On Thu, Oct 08, 2026 at 06:50:03PM +0200, Jakub Jelinek wrote:
> On Thu, Oct 08, 2026 at 05:56:58PM +0200, Tomasz Kaminski wrote:
> > These error are produced from value initialization of aggregate member in
> > ctor initializer:
> >     constexpr
> >       __formatter_ptr() noexcept
> >       : _M_spec()
> >       {}
> > 
> > So these are bugs, there is no reads or lvalue-to-rvalue conversions.
> 
> Reduced:
> struct A { int a; int b = ' '; };
> struct B { constexpr B () noexcept : c () {} A c; };
> constexpr B a;
> This is similar to the problematic constexpr-dtor17.C testcase I've talked
> about.

Ok, here is an updated patch.
It has the incremental patch incorporated, plus for INIT_EXPR checks whether
the copy will be elided or not and if it will be, doesn't diagnose it.
This fixes both constexpr-dtor17.C and the remaining libstdc++-v3 FAILs,
so this version has no regressions.

2026-10-09  Jakub Jelinek  <[email protected]>

        PR c++/127235
        * cp-tree.h (INIT_EXPR_UNION_LIFETIME_START_P): Define.
        * constexpr.cc (any_scalar_subobject, find_uninit_subobject,
        check_uninit_subobjects): New functions.
        (cxx_bind_parameters_in_call): Use check_uninit_subobjects.
        (cxx_eval_call_expression): Mark INIT_EXPR with
        INIT_EXPR_UNION_LIFETIME_START_P flag.
        (cxx_eval_store_expression, cxx_eval_constant_expression): Use
        check_uninit_subobjects.

        * g++.dg/cpp0x/constexpr-92443.C: Expect diagnostics for C++20.
        * g++.dg/cpp26/trivial-union6.C: Remove xfailed dg-error, add
        dg-error with different diagnostics on a line before that.
        * g++.dg/cpp26/trivial-union7.C: New test.
        * g++.dg/cpp26/within-lifetime1.C (std::bit_cast): Remove.
        (foo): Remove tests with std::bit_cast.
        * g++.dg/cpp2a/constexpr-init24.C: New test.
        * g++.dg/cpp2a/bit-cast11.C: Expect different diagnostics for C++20.
        * g++.dg/cpp2a/bit-cast12.C: Likewise.
        * g++.dg/cpp2a/bit-cast14.C: Likewise.
        * g++.dg/reflect/bases_of5.C (_Vector_impl): Initialize _M_start
        to nullptr in the ctor.

--- a/gcc/cp/cp-tree.h  2026-10-09 10:03:50.499185090 +0200
+++ b/gcc/cp/cp-tree.h  2026-10-09 12:25:48.337582273 +0200
@@ -509,6 +509,7 @@ extern GTY(()) tree cp_global_trees[CPTI
       MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR)
       MULTIPLE_NAMES_PARM_P (in PARM_DECL)
       SPLICE_EXPR_ADDRESS_P (in SPLICE_EXPR)
+      INIT_EXPR_UNION_LIFETIME_START_P (in INIT_EXPR)
    3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
       ICS_BAD_FLAG (in _CONV)
       FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -4517,6 +4518,12 @@ struct GTY(()) lang_decl {
 #define INIT_EXPR_NRV_P(NODE) \
   TREE_LANG_FLAG_0 (INIT_EXPR_CHECK (NODE))
 
+/* True iff this represents starting of lifetime of a union member.
+   In such case we shouldn't check for indeterminate subobjects on the
+   rhs.  */
+#define INIT_EXPR_UNION_LIFETIME_START_P(NODE) \
+  TREE_LANG_FLAG_2 (INIT_EXPR_CHECK (NODE))
+
 #define CALL_OR_AGGR_INIT_CHECK(NODE) \
   TREE_CHECK2 ((NODE), CALL_EXPR, AGGR_INIT_EXPR)
 
--- a/gcc/cp/constexpr.cc       2026-10-09 10:03:42.070300255 +0200
+++ b/gcc/cp/constexpr.cc       2026-10-09 12:43:37.686135716 +0200
@@ -3291,6 +3291,188 @@ addr_of_non_const_var (tree *tp, int *wa
   return NULL_TREE;
 }
 
+/* Helper function of find_uninit_subobject.  Return true if TYPE contains
+   any scalar subobject except for subobjects of unions.  This is called on
+   types of subobjects of CONSTRUCTOR_NO_PADDING elements which are missing
+   in the CONSTRUCTOR.  For union it means no union member is considered
+   active.  */
+static bool
+any_scalar_subobject (tree type)
+{
+  type = strip_array_types (type);
+  if (type == error_mark_node || TREE_CODE (type) == UNION_TYPE)
+    return false;
+  if (TREE_CODE (type) == RECORD_TYPE)
+    {
+      for (tree field = next_subobject_field (TYPE_FIELDS (type));
+          field; field = next_subobject_field (DECL_CHAIN (field)))
+       if (any_scalar_subobject (TREE_TYPE (field)))
+         return true;
+      return false;
+    }
+  return true;
+}
+
+/* Return true if T contains an uninitialized member and leave in
+   COMPONENTS a vector of the indices.
+   If called recursively on a FIELD_DECL's CONSTRUCTOR, SZ
+   is DECL_SIZE of the FIELD_DECL, otherwise NULL.  */
+
+static bool
+find_uninit_subobject (tree t, tree sz, vec<tree> *components)
+{
+  if (t == void_node)
+    return true;
+  if (TREE_CODE (t) != CONSTRUCTOR)
+    return false;
+  if (!AGGREGATE_TYPE_P (TREE_TYPE (t)))
+    return true;
+  if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+    {
+      tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+      tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+      tree cursor = CONSTRUCTOR_NO_CLEARING (t) ? min : NULL_TREE;
+      int any_scalar_subobject_p = -1;
+      for (auto &e: CONSTRUCTOR_ELTS (t))
+       {
+         if (cursor && array_index_cmp (cursor, e.index))
+           {
+             if (any_scalar_subobject_p == -1)
+               any_scalar_subobject_p
+                 = any_scalar_subobject (TREE_TYPE (TREE_TYPE (t)));
+             if (any_scalar_subobject_p)
+               {
+                 components->safe_push (cursor);
+                 return true;
+               }
+             else
+               cursor = e.index;
+           }
+         components->safe_push (e.index);
+         if (find_uninit_subobject (e.value, NULL_TREE, components))
+           return true;
+         components->pop ();
+         if (!cursor)
+           continue;
+         if (TREE_CODE (e.index) == RANGE_EXPR)
+           cursor = TREE_OPERAND (e.index, 1);
+         if (TREE_CODE (e.value) == RAW_DATA_CST)
+           cursor
+             = int_const_binop (PLUS_EXPR, cursor,
+                                size_int (RAW_DATA_LENGTH (e.value)));
+         else
+           cursor = int_const_binop (PLUS_EXPR, cursor,
+                                     size_one_node);
+       }
+      if (cursor)
+       {
+         max = int_const_binop (PLUS_EXPR, max, size_one_node);
+         if (array_index_cmp (cursor, max))
+           {
+             if (any_scalar_subobject_p == -1)
+               any_scalar_subobject_p
+                 = any_scalar_subobject (TREE_TYPE (TREE_TYPE (t)));
+             if (any_scalar_subobject_p)
+               {
+                 components->safe_push (cursor);
+                 return true;
+               }
+           }
+       }
+      return false;
+    }
+  if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+    /* Union copying is done by copying object representation.  */
+    return false;
+  tree field = NULL_TREE;
+  if (CONSTRUCTOR_NO_CLEARING (t))
+    field = next_subobject_field (TYPE_FIELDS (TREE_TYPE (t)));
+  for (auto &e: CONSTRUCTOR_ELTS (t))
+    {
+      for (; field && e.index != field;
+          field = next_subobject_field (DECL_CHAIN (field)))
+       if (any_scalar_subobject (TREE_TYPE (field)))
+         {
+           components->safe_push (field);
+           return true;
+         }
+      components->safe_push (e.index);
+      if (find_uninit_subobject (e.value, DECL_SIZE (e.index),
+                                components))
+       return true;
+      components->pop ();
+      if (field)
+       field = next_subobject_field (DECL_CHAIN (field));
+    }
+  for (; field; field = next_subobject_field (DECL_CHAIN (field)))
+    if (any_scalar_subobject (TREE_TYPE (field)))
+      {
+       /* Ignore FIELD_DECLs with bit positions beyond DECL_SIZE of
+          the parent FIELD_DECL (if any) for classes with virtual bases.  */
+       if (cxx_dialect >= cxx26
+           && sz
+           && tree_int_cst_le (sz, bit_position (field)))
+         break;
+       components->safe_push (field);
+       return true;
+      }
+  return false;
+}
+
+/* Return true if INIT contains any uninitialized subobjects and
+   if !CTX->quiet, diagnose it as well.  */
+
+static bool
+check_uninit_subobjects (const constexpr_ctx *ctx,
+                        location_t init_loc, tree init)
+{
+  auto_vec <tree, 8> components;
+  if (!find_uninit_subobject (init, NULL_TREE, &components))
+    return false;
+  if (!ctx->quiet)
+    {
+      if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
+       {
+         pretty_printer pp;
+         pretty_printer *refpp = global_dc->get_reference_printer ();
+         pp_format_decoder (&pp) = pp_format_decoder (refpp);
+         pp.set_format_postprocessor
+           (pp_format_postprocessor (refpp)->clone ());
+#if __GNUC__ >= 10
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+         unsigned int i;
+         tree c;
+         FOR_EACH_VEC_ELT (components, i, c)
+           {
+             if (TREE_CODE (c) == INTEGER_CST)
+               {
+                 pp_character (&pp, '[');
+                 pp_printf (&pp, "%E", c);
+                 pp_character (&pp, ']');
+               }
+             else
+               {
+                 if (i)
+                   pp_character (&pp, '.');
+                 pp_printf (&pp, "%D", c);
+               }
+           }
+#if __GNUC__ >= 10
+#pragma GCC diagnostic pop
+#endif
+         error_at (init_loc, "accessing uninitialized subobject %qs",
+                   pp_formatted_text (&pp));
+       }
+      else
+       error_at (init_loc, "reading indeterminate value of type %qT",
+                 TREE_TYPE (init));
+    }
+  return true;
+}
+
 /* Subroutine of cxx_eval_call_expression.
    We are processing a call expression (either CALL_EXPR or
    AGGR_INIT_EXPR) in the context of CTX.  Evaluate
@@ -3406,6 +3588,16 @@ cxx_bind_parameters_in_call (const const
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p && ctx->quiet)
        break;
+
+      if (cxx_dialect >= cxx20
+         && TREE_CODE (arg) == CONSTRUCTOR
+         && !*non_constant_p)
+       {
+         location_t arg_loc = cp_expr_loc_or_input_loc (x);
+         if (check_uninit_subobjects (ctx, arg_loc, arg))
+           *non_constant_p = true;
+       }
+
       /* Just discard ellipsis args after checking their constantitude.  */
       if (!parms)
        continue;
@@ -5041,6 +5233,7 @@ cxx_eval_call_expression (const constexp
              CONSTRUCTOR_NO_CLEARING (ctor) = true;
              tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
                                      new_obj, ctor);
+             INIT_EXPR_UNION_LIFETIME_START_P (activate) = true;
              cxx_eval_constant_expression (ctx, activate,
                                            lval, non_constant_p, overflow_p,
                                            jump_target);
@@ -8985,6 +9178,43 @@ cxx_eval_store_expression (const constex
   if (*non_constant_p)
     return t;
 
+  /* For C++20 and above check if aggregate assignment or default construction
+     doesn't copy uninitialized subobjects, because that violates
+     [expr.const]/(2.12): an lvalue-to-rvalue conversion that is applied to
+     an object with an indeterminate value.  */
+  if (cxx_dialect >= cxx20
+      && TREE_CODE (init) == CONSTRUCTOR
+      && !TREE_CLOBBER_P (init)
+      && TREE_CODE (t) != MODOP_EXPR
+      && (TREE_CODE (t) != INIT_EXPR
+         || !INIT_EXPR_UNION_LIFETIME_START_P (t)))
+    {
+      location_t init_loc = cp_expr_loc_or_input_loc (TREE_OPERAND (t, 1));
+      bool check = true;
+      if (TREE_CODE (t) == INIT_EXPR)
+       {
+         /* For INIT_EXPR, don't diagnose copying of aggregates with
+            indeterminate subobjects if the copying will be elided
+            in cp_gimplify_init_expr.  */
+         tree from = TREE_OPERAND (t, 1);
+         if (TREE_CODE (from) == TARGET_EXPR
+             && TARGET_EXPR_INITIAL (from)
+             && (TARGET_EXPR_ELIDING_P (from)
+                 || !TREE_ADDRESSABLE (TREE_TYPE (from))))
+           from = TARGET_EXPR_INITIAL (from);
+         while (TREE_CODE (from) == COMPOUND_EXPR)
+           from = TREE_OPERAND (from, 1);
+         if (TREE_CODE (from) == AGGR_INIT_EXPR
+             || TREE_CODE (from) == VEC_INIT_EXPR)
+           check = false;
+       }
+      if (check && check_uninit_subobjects (ctx, init_loc, init))
+       {
+         *non_constant_p = true;
+         return t;
+       }
+    }
+
   /* Don't share a CONSTRUCTOR that might be changed later.  */
   init = unshare_constructor (init);
 
@@ -10084,6 +10314,15 @@ cxx_eval_constant_expression (const cons
                                                 jump_target);
            if (*jump_target)
              return NULL_TREE;
+           if (cxx_dialect >= cxx20
+               && TREE_CODE (init) == CONSTRUCTOR
+               && !*non_constant_p)
+             {
+               location_t init_loc
+                 = cp_expr_loc_or_input_loc (DECL_INITIAL (r));
+               if (check_uninit_subobjects (ctx, init_loc, init))
+                 *non_constant_p = true;
+             }
            /* Don't share a CONSTRUCTOR that might be changed.  */
            init = unshare_constructor (init);
            /* Remember that a constant object's constructor has already
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-92443.C      2026-10-09 
10:03:42.091299968 +0200
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-92443.C      2026-10-09 
12:25:48.340812101 +0200
@@ -9,4 +9,4 @@ struct a {
   long b;
 };
 using d = a;
-constexpr d e = 6, f = f | e;
+constexpr d e = 6, f = f | e;  // { dg-error "accessing uninitialized 
subobject 'a::b'" "" { target c++20 } }
--- a/gcc/testsuite/g++.dg/cpp26/trivial-union6.C       2026-10-09 
10:03:42.093299941 +0200
+++ b/gcc/testsuite/g++.dg/cpp26/trivial-union6.C       2026-10-09 
12:25:48.341005726 +0200
@@ -10,8 +10,8 @@ struct E { C a; };
 union F { int a; A b; };
 union G { int a; A b[2]; };
 
-constexpr A fA () { A a; a.a[0] = 1; return a; }
-constexpr A a = fA ();         // { dg-error "is not a constant expression" "" 
{ xfail *-*-* } }
+constexpr A fA () { A a; a.a[0] = 1; return a; }       // { dg-error 
"accessing uninitialized subobject 'A::a\\\[1\\\]'" }
+constexpr A a = fA ();
 constexpr B fB () { B a; a.b[0] = 1; return a; }
 constexpr B b = fB ();         // { dg-error "is not a constant expression" }
 constexpr C fC () { C a; a.b[0][0] = 1; a.b[1][0] = 2; a.b[1][1] = 3; return 
a; }
--- a/gcc/testsuite/g++.dg/cpp26/trivial-union7.C       2026-10-09 
12:25:48.341116719 +0200
+++ b/gcc/testsuite/g++.dg/cpp26/trivial-union7.C       2026-10-09 
12:25:48.341116719 +0200
@@ -0,0 +1,61 @@
+// P3074R7 - trivial unions (was std::uninitialized<T>)
+// P3726R2 - Adjustments to Union Lifetime Rules
+// { dg-do compile { target c++20 } }
+
+struct A { int a[2]; };
+union B { int a; int b[2]; };
+union C { int a; int b[2][2]; };
+struct D { B a; };
+struct E { C a; };
+union F { int a; A b; };
+union G { int a; A b[2]; };
+
+struct H { constexpr H () { a.a[0] = 1; } A a; };
+constexpr H h; // { dg-error "is not a constant expression" }
+struct I { constexpr I () { a.b[0] = 1; } B a; };
+constexpr I i; // { dg-error "is not a constant expression" }
+struct J { constexpr J () { a.b[0][0] = 1; a.b[1][0] = 2; a.b[1][1] = 3; } C 
a; };
+constexpr J j; // { dg-error "is not a constant expression" }
+struct K { constexpr K () { a.a.b[0] = 1; } D a; };
+constexpr K k; // { dg-error "is not a constant expression" }
+struct L { constexpr L () { a.a.b[0][0] = 1; a.a.b[1][0] = 2; a.a.b[1][1] = 3; 
} E a; };
+constexpr L l; // { dg-error "is not a constant expression" }
+struct M { constexpr M () { a.b.a[0] = 1; } F a; };
+constexpr M m; // { dg-error "is not a constant expression" }
+struct N { constexpr N () { a.b[0].a[0] = 1; } G a; };
+constexpr N n; // { dg-error "is not a constant expression" }
+struct O { constexpr O () { __builtin_start_lifetime (&a.b); a.b[0] = 1; } B 
a; };
+constexpr O o; // { dg-error "is not a constant expression" "" { target 
c++23_down } }
+struct P { constexpr P (bool x) {
+  __builtin_start_lifetime (&a.b);
+  __builtin_start_lifetime (&a.b[0]);
+  if (x)
+    __builtin_start_lifetime (&a.b[1]);
+  a.b[0][0] = 1;
+  a.b[1][0] = 2;
+  a.b[1][1] = 3;
+} C a; };
+constexpr P pf (false);        // { dg-error "is not a constant expression" "" 
{ target c++23_down } }
+constexpr P pt (true); // { dg-error "is not a constant expression" "" { 
target c++23_down } }
+struct Q { constexpr Q () { __builtin_start_lifetime (&a.a.b); a.a.b[0] = 1; } 
D a; };
+constexpr Q q; // { dg-error "is not a constant expression" "" { target 
c++23_down } }
+struct R { constexpr R (bool x) {
+  __builtin_start_lifetime (&a.a.b);
+  __builtin_start_lifetime (&a.a.b[0]);
+  if (x)
+    __builtin_start_lifetime (&a.a.b[1]);
+  a.a.b[0][0] = 1;
+  a.a.b[1][0] = 2;
+  a.a.b[1][1] = 3;
+} E a; };
+constexpr R rf (false);        // { dg-error "is not a constant expression" "" 
{ target c++23_down } }
+constexpr R rt (true); // { dg-error "is not a constant expression" "" { 
target c++23_down } }
+struct S { constexpr S (bool x) {
+  __builtin_start_lifetime (&a.a.b[0]);        // { dg-error 
"'__builtin_start_lifetime' with containing object not within lifetime" }
+  if (x)
+    __builtin_start_lifetime (&a.a.b[1]);
+  a.a.b[0][0] = 1;
+  a.a.b[1][1] = 3;
+} E a; };
+constexpr S sf (false);
+constexpr S st (true);
--- a/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C     2026-10-09 
10:03:42.093299941 +0200
+++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C     2026-10-09 
12:25:48.341250777 +0200
@@ -12,15 +12,6 @@ namespace std {
 }
 #endif
 
-namespace std {
-  template <typename T, typename F>
-  constexpr T
-  bit_cast (const F &f) noexcept
-  {
-    return __builtin_bit_cast (T, f);
-  }
-}
-
 constexpr char d = 0;
 struct E { char a; union F { int b; long c; short d; struct G { int e; } f[2]; 
} g; };
 constexpr E e = {};
@@ -149,15 +140,9 @@ foo ()
     return __LINE__;
   if (!std::is_within_lifetime (&k))
     return __LINE__;
-  unsigned char l = std::bit_cast <unsigned char> (k);
-  if (!std::is_within_lifetime (&l))
-    return __LINE__;
   struct {} m;
   if (!std::is_within_lifetime (&m))
     return __LINE__;
-  unsigned char n = std::bit_cast <unsigned char> (m);
-  if (!std::is_within_lifetime (&n))
-    return __LINE__;
   int o;
   if (!std::is_within_lifetime (static_cast <volatile int *> (&o)))
     return __LINE__;
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init24.C     2026-10-09 
12:25:48.341425730 +0200
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init24.C     2026-10-09 
13:03:28.935164460 +0200
@@ -0,0 +1,218 @@
+// PR c++/127235
+// { dg-do compile { target c++20 } }
+
+struct A { int a, b; };
+struct B { int c; A d; int e; };
+union C { int f; long g; A h; };
+struct D { A i[3]; C j; };
+
+template <typename T>
+constexpr bool
+baz (T x)
+{
+  return true;
+}
+
+constexpr bool
+qux (bool x, ...)
+{
+  return x;
+}
+
+constexpr bool
+foo (int x)
+{
+  B b, c;
+  b.c = 1;
+  b.d.a = 2;
+  b.e = 3;
+  D d, e;
+  d.i[0] = {};
+  d.i[1] = {};
+  d.i[2].b = 4;
+  if (x == 1)
+    c.d.b = b.d.b;             // { dg-error "accessing uninitialized member 
'A::b'" }
+  else if (x == 2)
+    c.d = b.d;                 // { dg-error "accessing uninitialized 
subobject 'A::b'" }
+  else if (x == 3)
+    c = b;                     // { dg-error "accessing uninitialized 
subobject 'B::d.A::b'" }
+  else if (x == 4)
+    e.i[2].a = d.i[2].a;       // { dg-error "accessing uninitialized member 
'A::a'" }
+  else if (x == 5)
+    e.i[2] = d.i[2];           // { dg-error "accessing uninitialized 
subobject 'A::a'" }
+  else if (x == 6)
+    e.i[1] = d.i[1];
+  else if (x == 7)
+    e = d;                     // { dg-error "accessing uninitialized 
subobject 'D::i\\\[2\\\].A::a'" }
+  d.i[2].a = 5;
+  if (x == 8)
+    e = d;
+  d.j.f = 6;
+  if (x == 9)
+    e = d;
+  d.j.g = 7;
+  if (x == 10)
+    e = d;
+  d.j.h.a = 8;
+  if (x == 11)
+    e = d;
+  d.j.h.b = 9;
+  if (x == 12)
+    e = d;
+  d = {};
+  if (x == 13)
+    e = d;
+  d.j.h.b = 10;
+  if (x == 14)
+    e = d;
+  C f, g;
+  f = {};
+  if (x == 15)
+    g = f;
+  f.h = {};
+  if (x == 16)
+    g = f;
+  f.g = {};
+  if (x == 17)
+    g = f;
+  f.h.a = {};
+  if (x == 18)
+    g = f;
+  if (x == 19)
+    C h = f;
+  else if (x == 20)
+    D i = d;
+  else if (x == 21)
+    B j = b;                   // { dg-error "accessing uninitialized 
subobject 'B::d.A::b'" }
+  else if (x == 22)
+    baz (f);
+  else if (x == 23)
+    baz (d);
+  else if (x == 24)
+    baz (b);                   // { dg-error "accessing uninitialized 
subobject 'B::d.A::b'" }
+  else if (x == 25)
+    baz <C &> (f);
+  else if (x == 26)
+    baz <D &> (d);
+  else if (x == 27)
+    baz <B &> (b);
+  else if (x == 28)
+    qux (true, f);
+  else if (x == 29)
+    qux (true, d);
+  else if (x == 30)
+    qux (true, b);             // { dg-error "accessing uninitialized 
subobject 'B::d.A::b'" }
+  return true;
+}
+
+constexpr A
+bar (int x)
+{
+  A a;
+  if (x == 1 || x == 3)
+    a.a = 1;
+  if (x == 2 || x == 3)
+    a.b = 2;
+  return a;                    // { dg-error "accessing uninitialized 
subobject 'A::a'" }
+}                              // { dg-error "accessing uninitialized 
subobject 'A::b'" "" { target *-*-* } .-1 }
+
+constexpr B
+fred (int x)
+{
+  if (x == 1)
+    {
+      B a;
+      a.c = 1;
+      a.d.a = 2;
+      a.e = 3;
+      return a;                        // { dg-error "accessing uninitialized 
subobject 'B::d.A::b'" }
+    }
+  else if (x == 2)
+    {
+      B b;
+      b.c = 4;
+      b.d.b = 5;
+      b.e = 6;
+      return b;                        // { dg-error "accessing uninitialized 
subobject 'B::d.A::a'" }
+    }
+  return {};
+}
+
+constexpr C
+corge (int x)
+{
+  if (x == 1)
+    {
+      C a;
+      return a;
+    }
+  else if (x == 2)
+    {
+      C b;
+      b.h.a = 1;
+      return b;
+    }
+  else if (x == 3)
+    {
+      C c;
+      c.g = 42;
+      return c;
+    }
+  C d;
+  if (x == 5)
+    d.f = 1;
+  else if (x == 6)
+    d.g = 2;
+  else if (x == 7)
+    d.h.b = 3;
+  else if (x == 8)
+    d.h.a = 4;
+  else if (x == 9)
+    d.h.a = d.h.b = 5;
+  return d;
+}
+
+constexpr bool a = foo (1);
+constexpr bool b = foo (2);
+constexpr bool c = foo (3);
+constexpr bool d = foo (4);
+constexpr bool e = foo (5);
+static_assert (foo (6));
+constexpr bool f = foo (7);
+static_assert (foo (8));
+static_assert (foo (9));
+static_assert (foo (10));
+static_assert (foo (11));
+static_assert (foo (12));
+static_assert (foo (13));
+static_assert (foo (14));
+static_assert (foo (15));
+static_assert (foo (16));
+static_assert (foo (17));
+static_assert (foo (18));
+static_assert (foo (19));
+static_assert (foo (20));
+constexpr bool l = foo (21);
+static_assert (foo (22));
+static_assert (foo (23));
+constexpr bool o = foo (24);
+static_assert (foo (25));
+static_assert (foo (26));
+static_assert (foo (27));
+static_assert (foo (28));
+static_assert (foo (29));
+constexpr bool r = foo (30);
+constexpr int s = bar (1).a;
+constexpr int t = bar (2).b;
+static_assert (bar (3).a == 1);
+constexpr int u = fred (1).d.a;
+constexpr int v = fred (2).d.b;
+static_assert ((corge (1), true));
+constexpr int w = corge (2).h.a;
+static_assert (corge (3).g == 42);
+static_assert ((corge (4), true));
+static_assert (corge (5).f == 1);
+static_assert (corge (6).g == 2);
+constexpr int x = corge (7).h.b;
+constexpr int y = corge (8).h.a;
+static_assert (corge (9).h.a == 5);
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   2026-10-09 10:03:42.093299941 
+0200
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   2026-10-09 12:25:48.341574360 
+0200
@@ -11,7 +11,7 @@ constexpr bool
 f1 ()
 {
   T t = { 1, 2 };
-  S s = __builtin_bit_cast (S, t);
+  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized 
subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
   return s.a[0] == 1;
 }
 
@@ -19,7 +19,7 @@ constexpr bool
 f2 ()
 {
   U u = { 0, 0 };
-  unsigned char a = __builtin_bit_cast (unsigned char, u);
+  unsigned char a = __builtin_bit_cast (unsigned char, u); // { dg-error 
"reading indeterminate value of type 'unsigned char'" "" { target c++20 } }
   return true;
 }
 
@@ -27,23 +27,23 @@ constexpr bool
 f3 ()
 {
   T t = { 1, 2 };
-  S s = __builtin_bit_cast (S, t);
-  return s.a[1] == 0;          // { dg-error "accessing uninitialized array 
element" }
+  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized 
subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.a[1] == 0;          // { dg-error "accessing uninitialized array 
element" "" { target c++17_down } }
 }
 
 constexpr bool
 f4 ()
 {
   U u = { 0, 0 };
-  unsigned char a = __builtin_bit_cast (unsigned char, u);
-  return a == 0;               // { dg-error "is not a constant expression" }
+  unsigned char a = __builtin_bit_cast (unsigned char, u); // { dg-error 
"reading indeterminate value of type 'unsigned char'" "" { target c++20 } }
+  return a == 0;               // { dg-error "is not a constant expression" "" 
{ target c++17_down } }
 }
 
 constexpr bool
 f5 ()
 {
   W t = { 1, 2 };
-  V s = __builtin_bit_cast (V, t);
+  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized 
subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
   return s.b.a[0] == 1;
 }
 
@@ -51,13 +51,13 @@ constexpr bool
 f6 ()
 {
   W t = { 1, 2 };
-  V s = __builtin_bit_cast (V, t);
-  return s.b.a[1] == 1;                // { dg-error "accessing uninitialized 
array element" }
+  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized 
subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.b.a[1] == 1;                // { dg-error "accessing uninitialized 
array element" "" { target c++17_down } }
 }
 
-constexpr bool a = f1 ();
-constexpr bool b = f2 ();
+constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
+constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
 constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion" }
 constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion" }
-constexpr bool e = f5 ();
+constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
 constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion" }
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   2026-10-09 10:03:42.093299941 
+0200
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   2026-10-09 12:25:48.341735065 
+0200
@@ -6,7 +6,7 @@ namespace std
   enum class byte : unsigned char {};
 }
 
-struct S { unsigned char a[2]; alignas(sizeof 0) int b; };
+struct S { std::byte a[2]; alignas(sizeof 0) int b; };
 struct T { char a; alignas(sizeof 0) int b; };
 struct U { char a : 1; char : 6; char b : 1; };
 struct V { int a; S b; };
@@ -16,15 +16,15 @@ constexpr bool
 f1 ()
 {
   T t = { 1, 2 };
-  S s = __builtin_bit_cast (S, t);
-  return s.a[0] == 1;
+  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized 
subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.a[0] == std::byte (1);
 }
 
 constexpr bool
 f2 ()
 {
   U u = { 0, 0 };
-  unsigned char a = __builtin_bit_cast (unsigned char, u);
+  std::byte a = __builtin_bit_cast (std::byte, u); // { dg-error "reading 
indeterminate value of type 'std::byte'" "" { target c++20 } }
   return true;
 }
 
@@ -32,37 +32,37 @@ constexpr bool
 f3 ()
 {
   T t = { 1, 2 };
-  S s = __builtin_bit_cast (S, t);
-  return s.a[1] == 0;          // { dg-error "accessing uninitialized array 
element" }
+  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized 
subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.a[1] == std::byte (0); // { dg-error "accessing uninitialized array 
element" "" { target c++17_down } }
 }
 
 constexpr bool
 f4 ()
 {
   U u = { 0, 0 };
-  unsigned char a = __builtin_bit_cast (unsigned char, u);
-  return a == 0;               // { dg-error "is not a constant expression" }
+  std::byte a = __builtin_bit_cast (std::byte, u); // { dg-error "reading 
indeterminate value of type 'std::byte'" "" { target c++20 } }
+  return a == std::byte (0);   // { dg-error "is not a constant expression" "" 
{ target c++17_down } }
 }
 
 constexpr bool
 f5 ()
 {
   W t = { 1, 2 };
-  V s = __builtin_bit_cast (V, t);
-  return s.b.a[0] == 1;
+  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized 
subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.b.a[0] == std::byte (1);
 }
 
 constexpr bool
 f6 ()
 {
   W t = { 1, 2 };
-  V s = __builtin_bit_cast (V, t);
-  return s.b.a[1] == 1;                // { dg-error "accessing uninitialized 
array element" }
+  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized 
subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
+  return s.b.a[1] == std::byte (1); // { dg-error "accessing uninitialized 
array element" "" { target c++17_down } }
 }
 
-constexpr bool a = f1 ();
-constexpr bool b = f2 ();
+constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
+constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
 constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion" }
 constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion" }
-constexpr bool e = f5 ();
+constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
 constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion" }
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   2026-10-09 10:03:42.094299927 
+0200
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   2026-10-09 12:25:48.341882020 
+0200
@@ -11,7 +11,7 @@ constexpr bool
 f1 ()
 {
   T1 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::a'" "" { target c++20 } }
   return true;
 }
 
@@ -19,7 +19,7 @@ constexpr bool
 f2 ()
 {
   T2 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::b'" "" { target c++20 } }
   return true;
 }
 
@@ -27,7 +27,7 @@ constexpr bool
 f3 ()
 {
   T3 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::c'" "" { target c++20 } }
   return true;
 }
 
@@ -43,8 +43,8 @@ constexpr bool
 f5 ()
 {
   T1 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
-  unsigned char a = s.a;               // { dg-error "accessing uninitialized 
member" }
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::a'" "" { target c++20 } }
+  unsigned char a = s.a;               // { dg-error "accessing uninitialized 
member" "" { target c++17_down } }
   return true;
 }
 
@@ -52,8 +52,8 @@ constexpr bool
 f6 ()
 {
   T2 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
-  unsigned char b = s.b;               // { dg-error "accessing uninitialized 
member" }
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::b'" "" { target c++20 } }
+  unsigned char b = s.b;               // { dg-error "accessing uninitialized 
member" "" { target c++17_down } }
   return true;
 }
 
@@ -61,14 +61,14 @@ constexpr bool
 f7 ()
 {
   T3 t = { 0, 0, 0, 0, 0, 0, 0 };
-  S s = __builtin_bit_cast (S, t);
-  unsigned char c = s.c;               // { dg-error "accessing uninitialized 
member" }
+  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing uninitialized 
subobject 'S::c'" "" { target c++20 } }
+  unsigned char c = s.c;               // { dg-error "accessing uninitialized 
member" "" { target c++17_down } }
   return true;
 }
 
-constexpr bool a = f1 ();
-constexpr bool b = f2 ();
-constexpr bool c = f3 ();
+constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
+constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
+constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion" "" { 
target c++20 } }
 constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion" }
 constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion" }
 constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion" }
--- a/gcc/testsuite/g++.dg/reflect/bases_of5.C  2026-10-09 10:03:42.096299900 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/bases_of5.C  2026-10-09 12:25:48.342054145 
+0200
@@ -69,7 +69,7 @@ template <typename _Tp, typename _Alloc>
   typedef __alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
   typedef __alloc_traits<_Tp_alloc_type>::pointer pointer;
   struct _Vector_impl : _Tp_alloc_type {
-    constexpr _Vector_impl(_Tp_alloc_type) {}
+    constexpr _Vector_impl(_Tp_alloc_type) : _M_start(nullptr) {}
     pointer _M_start;
   };
   constexpr ~_Vector_base() { _M_deallocate(_M_impl._M_start); }

        Jakub

Reply via email to