Reputation: 21317
In the following program, function foo
receives parameter v
of type std::integral_constant<bool, true>
, which is used for passing in template argument A<b>
:
template <bool>
struct A{};
constexpr bool foo(auto b) {
return requires { typename A<b>; };
}
static_assert( foo( std::true_type{} ) );
Both GCC and MSVC find it valid (foo
returns true
), but in Clang foo
returns false
. Online demo: https://gcc.godbolt.org/z/j6Mnqjvbz
Which compiler is correct here?
Upvotes: 11
Views: 203
Reputation: 39869
The code you have provided is correct. It fails because of a known LLVM bug 42406 / issue 41751.
You can call member functions on objects that don't exist in constant expressions, as long as the member functions don't access the object. Two classic examples:
std::array<int, 10> arr; // arr is not usable in a constant expression,
// but we can obtain its size()
static_assert(arr.size() == 10);
std::true_type t;
static_assert(t); // does not access t, but calls its operator bool()
Clang compiles both of the above. The same logic extends to function parameters, which are never usable in a constant expression:
// your code, except using std::true_type instead of auto
constexpr bool foo(std::true_type b) {
return requires { typename A<b>; };
}
The code above should work, but results in a compiler error for clang:
error: reference to local variable 'b' declared in enclosing function > 'foo' 7 | return requires { typename A<b>; }; | ^ note: 'b' declared here 6 | constexpr bool foo(std::true_type b) { |
Your static assertion fails for the same reason, though you can understand the issue better when avoiding templates. This error message is obviously nonsensical and a compiler bug because no reference is being declared.
Upvotes: 2