Reputation: 1
After reading about constant expressions I wrote the following example that compiles with msvc but is rejected by both gcc and clang.
int *const ptr2 = nullptr;
static_assert(!ptr2); //msvc passes but both gcc and clang rejects/fails this
int main()
{
}
As we can see the gcc rejects the code saying:
<source>:2:15: error: non-constant condition for static assertion
2 | static_assert(!ptr2); //msvc passes but both gcc and clang rejects/fails this
| ^~~~~
<source>:2:15: error: the value of 'ptr2' is not usable in a constant expression
<source>:1:12: note: 'ptr2' was not declared 'constexpr'
On the other hand msvc accepts/compiles the program. I want to know which compiler is correct according to the C++ standard.
Note that I am aware that I can use constexpr
kewyord and the program will compiler with all compilers then. But my question is about the behavior of the current program as per the c++ standard. Also note that I am using C++20.
Upvotes: 2
Views: 133
Reputation: 76829
The operand of !
is contextually converted to bool
per [expr.unary.op]/9.
Applying [conv.general]/4 this means we obtain a bool
value as if by initializing a variable _
with
bool _(ptr2);
Per [dcl.init.general]/16.9 a standard conversion sequence is used to convert the initializer expression ptr2
to bool
.
In order to construct that sequence, an lvalue-to-rvalue conversion is needed, because the standard conversions to bool
all require prvalues (see [conv]), but ptr2
is a lvalue expression.
The lvalue-to-rvalue conversion is not permitted in constant expressions per [expr.const]/5.8, because the lifetime of ptr2
didn't start during the constant expression evaluation, nor is it usable in constant expressions, which is only possible for constexpr
variables and const
-qualified integral/enumeration type variables (see [expr.const]/4 together with [expr.const]/3)
So MSVC is incorrect and the other compilers are correct. The initialization of ptr2
doesn't matter.
However, if the type of the variable itself was std::nullptr_t
, then [dcl.init.general]/16.8) would preempt 16.7. and the value of the bool
would false
without any conversion being applied. In that case, it would be a constant expression.
Upvotes: 2