On Fri, Oct 9, 2026 at 3:37 PM Jakub Jelinek <[email protected]> wrote:
> 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; };
>
Could you add some guaranteed copy elision cases. To be able to crete
uninitialized prvalue we need some cosntructor doing so
struct X { constexpr X(int p) : x(p) {}; int x; int y };
X create() { return X(10); }
void pass(X);
void test() {
X x = X(10); // OK, no copy
pass(X(10)); // OK, no copy
X x2 = create(); // OK, no copy
pass(create()); // OK, no copy
X x3 = x; // FAIL, copy
pass(x); // FAIL, copy
}
constexpr X gx = create(); // FAILs,
// due constexpr variable with uninitialized consitiutent value,
// but initialization should be OK
> +
> +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
>
>