2

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?

timrau
  • 22,578
  • 4
  • 51
  • 64
pmor
  • 5,392
  • 4
  • 17
  • 36
  • This code exhibits undefined behaviour and, for `constexpr` a diagnostic is required by the Standard. [This answer](https://stackoverflow.com/a/21319606/10871073) covers it well, so I *think* this question is a duplicate. – Adrian Mole May 21 '22 at 13:04
  • @AdrianMole _This code exhibits undefined behaviour and, for constexpr a diagnostic is required by the Standard_ No, for such code, the standard places no requirement. – Language Lawyer May 21 '22 at 13:09
  • @LanguageLawyer So what of the Standard citations given in the linked duplicates? Are they wrong? – Adrian Mole May 21 '22 at 13:12
  • @AdrianMole the citations are about constant expression **evaluation**. Do you see `f` being invoked? – Language Lawyer May 21 '22 at 13:15
  • @LanguageLawyer Irrelevant. The code for the `f` function is ill-formed. – Adrian Mole May 21 '22 at 13:19
  • @AdrianMole _Irrelevant_ Your dup targets? Absolutely. _The code for the `f` function is ill-formed_ With no diagnostic required, [which means there are no requirements](https://timsong-cpp.github.io/cppwp/n4861/intro.compliance#2.3). – Language Lawyer May 21 '22 at 13:21
  • @LanguageLawyer Just for information, g++ and clang have the same differences, even if the [function is invoked](https://godbolt.org/z/9hc1vv344). – Adrian Mole May 21 '22 at 13:28
  • @AdrianMole Those targets are not correct. While diagnosing UB during constant evaluation is required, there's no constant evaluation of `f` in the OP's program. In the demo you linked in your comment, the evaluation of `f` is at run-time, so there's no diagnostic required there either. I'm not able to find a duplicate target for this, so I'm voting to reopen. Please ping me if an appropriate target is found. – cigien May 21 '22 at 17:22

1 Answers1

2

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.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • _then it violates expr.const#5.10_ How is it possible to violate anything when https://timsong-cpp.github.io/cppwp/n4861/intro.compliance#2.3 – Language Lawyer Jul 18 '22 at 11:05