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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With