https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127235

            Bug ID: 127235
           Summary: C++20 rejects-valid with uninitialized member
           Product: gcc
           Version: 16.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakub at gcc dot gnu.org
  Target Milestone: ---

struct A { int a[2]; };
constexpr A fA () { A a; a.a[0] = 1; return a; }
constexpr A a = fA ();          // { dg-error "is not a constant expression" ""
{ xfail *-*-* } }
is incorrectly silently accepted for C++20 and later.
For C++17 we correctly reject it, but that is during the construction of the a
variable:
test.C: In function ‘constexpr A fA()’:
test.C:2:23: error: uninitialized variable ‘a’ in ‘constexpr’ function
    2 | constexpr A fA () { A a; a.a[0] = 1; return a; }
      |                       ^
test.C:1:8: note: ‘struct A’ has no user-provided default constructor
    1 | struct A { int a[2]; };
      |        ^
test.C:1:16: note: and the implicitly-defined constructor does not initialize
‘int A::a [2]’
    1 | struct A { int a[2]; };
      |                ^
test.C: At global scope:
test.C:3:20: error: ‘constexpr A fA()’ called in a constant expression
    3 | constexpr A a = fA ();          // { dg-error "is not a constant
expression" "" { xfail *-*-* } }
      |                 ~~~^~
For C++20, reduced_constant_expression_p correctly figures out it is not a
constant expression, but we only use it to make it non-cacheable:
          /* Only cache a permitted result of a constant expression.  */
          if (cacheable && !reduced_constant_expression_p (result))
            cacheable = false;
Later on, we trigger
  /* The result of a constexpr function must be completely initialized.

     However, in C++20, a constexpr constructor doesn't necessarily have
     to initialize all the fields, so we don't clear CONSTRUCTOR_NO_CLEARING
     in order to detect reading an uninitialized object in constexpr instead
     of value-initializing it.  (reduced_constant_expression_p is expected to
     take care of clearing the flag.)  */
  if (TREE_CODE (result) == CONSTRUCTOR
      && (cxx_dialect < cxx20
          || !DECL_CONSTRUCTOR_P (fun)))
    clear_no_implicit_zero (result);
fun here is fA, so not a constructor, so we silently clear the
CONSTRUCTOR_NO_CLEARING flag.

Reply via email to