Consider this code:
typedef union { float v; unsigned u; } T;
constexpr T x = { .u = 0 };
constexpr float f(void)
{
return x.v;
}
Is this code valid?
Invocations:
$ g++ t506a.cpp -c -std=c++20 -pedantic -Wall -Wextra
<nothing>
$ clang++ t506a.cpp -c -std=c++20 -pedantic -Wall -Wextra
t506a.cpp:3:17: error: constexpr function never produces a constant expression
[-Winvalid-constexpr]
constexpr float f(void)
^
t506a.cpp:5:9: note: read of member 'v' of union with active member 'u' is not allowed in a
constant expression
return x.v;
^
1 error generated.
Which compiler is correct?
Both compilers are correct, even though the code is ill-formed, because no diagnostic is required in the program you've shown. It's true that f
can never be evaluated as a core constant expression, but in that case dcl.constexpr#6 applies:
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object ([basic.start.static]), the program is ill-formed, no diagnostic required.
(emphasis mine)
Since no diagnostic is required, GCC is allowed to not diagnose this.
On the other hand, if you do attempt to evaluate f
as a constant, e.g.
constexpr float a = f();
then it violates expr.const#5.10:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
- an lvalue-to-rvalue conversion that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;
and indeed, both GCC and Clang diagnose this error, as required during constant evaluation.