Bug 109049 - std::declval gives wrong result for cv void
Summary: std::declval gives wrong result for cv void
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 12.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: wrong-code
Depends on:
Reported: 2023-03-07 06:18 UTC by fsb4000
Modified: 2023-03-07 17:24 UTC (History)
2 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description fsb4000 2023-03-07 06:18:11 UTC
A. Jiang <de34@live.cn> found that:


"The return type is... cursed for cv void.

It seems that decltype(std::declval<const void>) should be const void() (until C++17) / const void() noexcept (since C++17) (same for volatile void and const volatile void), but the cv-qualifiers are dropped"

Code example:

#include <utility>
#include <type_traits>

int main() {
    static_assert(std::is_same_v<decltype(std::declval<const void>), const void () noexcept>);
    static_assert(std::is_same_v<decltype(std::declval<volatile void>), volatile void () noexcept>);


I've created the same issue for libc++: https://github.com/llvm/llvm-project/issues/61232
Comment 1 Jonathan Wakely 2023-03-07 12:23:54 UTC
Who cares? Taking the address of std::declval is forbidden, and you can't call that specialization anyway.
Comment 2 Jonathan Wakely 2023-03-07 12:32:24 UTC
The reason it behaves this way is that we define declval as:

  template<typename _Tp>
    auto declval() noexcept -> decltype(__declval<_Tp>(0));

and decltype(__declval<_Tp>(0)) drops the cv-qualifiers. This implementation is much faster to compile, and so we're not going to stop using it to "fix" the useless testcase in this bug. Nobody cares about decltype(std::declval<const void>) but they do care about compile times.
Comment 3 Jiang An 2023-03-07 15:07:47 UTC
I've mailed to LWG Chair to request legitimation of libc++ and libstdc++'s current strategy.
Comment 4 Jonathan Wakely 2023-03-07 15:43:16 UTC
I thought it was already allowed, because std::declval is not an addressable function ([namespace.std]) but that only covers forming pointers and references to functions. We should extend that to cover this case.