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