On Thu, Oct 8, 2026 at 4:32 PM Tomasz Kaminski <[email protected]> wrote:
> > > On Thu, Oct 8, 2026 at 1:16 PM Jakub Jelinek <[email protected]> wrote: > >> Hi! >> >> C++20 P1331R2 has added http://eel.is/c++draft/expr.const#core-2.12 >> - an lvalue-to-rvalue conversion that is applied to an object with an >> indeterminate value; >> as one of the cases which result in an expression not being core constant >> expression. >> Now, if we are reading a scalar with indeterminate value, we already >> usually diagnose it, but when copying an aggregate with uninitialized >> subobjects, we can accept it even when it should be rejected, whether >> the copying is done because of trivial copy/move construction or trivial >> copy/move assignment. >> >> The following patch attempts to diagnose it / make evaluation >> *non_constant_p in such cases, in 3 places (cxx_eval_store_expression >> for copying of the aggregates including returning them by value, >> cxx_bind_parameters_in_call for passing aggregates by value and >> cxx_eval_constant_expression DECL_EXPR handling for constructing >> objects by copying aggregate). >> There are some problems I've run into: >> 1) the current behavior in the patch on constexpr-init24.C differs >> in some spots from how clang++ behaves. >> Small testcase: >> struct S { int a, b; }; >> union U { int c; S d; }; >> constexpr U foo () { U u; u.d.a = 42; return u; } >> static_assert (foo ().d.a == 42); >> Now, Tomasz pointed out that >> https://eel.is/c++draft/class.copy.ctor#16 >> and https://eel.is/c++draft/class.copy.assign#13 define copying/moving >> of unions by copy of object representation, so maybe in the current >> standard wording the above is valid. I think copying of object >> representation is the only reasonable thing for runtime (together with >> saying that it starts lifetime of the subobjects that were within >> lifetime on the other side), but I believe it is a wrong thing to do >> for constant evaluation. The object representation and lifetime >> is not the only thing we care about during constant evaluation, an >> important case is e.g. for pointers the knowledge whether they point >> to the start of a complete object or past the end of a different >> complete object which happens to have the same object representation, >> or e.g. whether the value is indeterminate or not. >> Shall I keep it as is in the patch and discuss on CWG reflector, >> or shall I change the patch to basically ignore anything inside of >> unions for this? >> 2) when trying to implement the bit_cast related part of P1272R4, I've >> assumed that the changes mentioned in that paper are meant for >> constant evaluation as well; but if returning or otherwise copying >> a struct with indeterminate subobjects is not valid constant >> expression, >> a lot of what those testcases test is now just invalid >> 3) in an earlier version of the patch, I had basically all of reflection >> tests FAIL, because cxx_eval_call_expression uses >> /* If this is a constructor, we are beginning the lifetime of the >> object we are initializing. */ >> hunk to activate a union member and implements that with an >> cxx_eval_constant_expression on a made up INIT_EXPR with >> CONSTRUCTOR_NO_CLEARING empty ctor on the rhs; that triggered >> the new diagnostics/*non_constant_p. I've added a flag on INIT_EXPR >> with an ugly name to work around this >> 4) on trivial-union6.C testcase, many spots now result in different >> diagnostics because we diagnose returning structures with indeterminate >> subobjects; in order to partly preserve what the test was doing, I've >> added trivial-union7.C test which instead of returning those has those >> in default constructor and so no copying is involved >> 5) there is one unresolved FAIL in g++.dg - >> g++.dg/cpp2a/constexpr-dtor17.C >> for C++20 and above; the errors are >> cpp2a/constexpr-dtor17.C:38:17: error: non-constant condition for >> static assertion >> cpp2a/constexpr-dtor17.C:17:40: error: accessing uninitialized >> subobject 'basic_string::_M_local_buf' >> cpp2a/constexpr-dtor17.C:39:17: error: non-constant condition for >> static assertion >> cpp2a/constexpr-dtor17.C:17:40: error: accessing uninitialized >> subobject 'basic_string::_M_local_buf' >> Now the test is maybe reduced too much, but even adding constexpr user >> defined copy ctor and copy assignment op doesn't help. >> The get() method uses INIT_EXPR from a TARGET_EXPR for the return, >> in check_return_expr >> /* Actually copy the value returned into the appropriate location. */ >> if (retval && retval != result) >> retval = cp_build_init_expr (result, retval); >> >> if (current_function_return_value == bare_retval) >> INIT_EXPR_NRV_P (retval) = true; >> where INIT_EXPR_NRV_P isn't set in this case. If we shouldn't >> diagnose it in this case, how to differentiate that from the >> case where one simply returns an aggregate by value? >> 6) there are some libstdc++ FAILs caused by this patch: >> FAIL: 23_containers/inplace_vector/move.cc -std=gnu++26 (test for >> excess errors) >> FAIL: 23_containers/inplace_vector/move.cc -std=gnu++29 (test for >> excess errors) >> FAIL: 23_containers/inplace_vector/copy.cc -std=gnu++26 (test for >> excess errors) >> FAIL: 23_containers/inplace_vector/copy.cc -std=gnu++29 (test for >> excess errors) >> FAIL: 23_containers/inplace_vector/modifiers/multi_insert.cc >> -std=gnu++26 (test for excess errors) >> FAIL: 23_containers/inplace_vector/modifiers/multi_insert.cc >> -std=gnu++29 (test for excess errors) >> FAIL: std/format/constexpr.cc -std=gnu++26 (test for excess errors) >> FAIL: std/format/constexpr.cc -std=gnu++29 (test for excess errors) >> FAIL: std/format/functions/format.cc -std=gnu++20 (test for excess >> errors) >> e.g. >> error: accessing uninitialized subobject 'std::inplace_vector<int, >> 5>::<anonymous>.std::inplace_vector<int, 5>::<unnamed union>::_M_elems[0]' >> Now, I admit it isn't clear if P3726R2 is somehow supposed to interact >> with this, maybe if 1) is changed to ignore unions then at least >> the inplace_vector ones would go away. Or if we change what the >> trivial copying of unions does during constant evaluation, whether >> the lvalue-to-rvalue conversion doesn't happen for inactive union >> elemental subobjects. >> > An object must be within its lifetime to have a value, so it cannot be > indeterminate or uninitialized. > I have allowed such out-of lifetime members only in unions because the > standard never copies union > elements (the bit about copying object representation). > If we want to change to a constexpr path, to copy active union elements, > we do lvalue-to-rvalue conversion > only of active union member objects. > > >> The format errors are like: >> format:2552: error: accessing uninitialized subobject >> 'std::__format::_Spec<char>::_M_width' >> > I will try to take a look on this one, if they are no gone with next > patch. > These error are produced from value initialization of aggregate member in ctor initializer: constexpr __formatter_ptr() noexcept : _M_spec() {} The struct looks like this: // Used to make _Spec a non-C++98 POD, so the tail-padding is used. // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod struct _SpecBase { }; template<typename _CharT> struct _Spec : _SpecBase { unsigned short _M_width; unsigned short _M_prec; char32_t _M_fill = ' '; _Align _M_align : 2; _Sign _M_sign : 2; unsigned _M_alt : 1; unsigned _M_localized : 1; unsigned _M_zero_fill : 1; _WidthPrec _M_width_kind : 2; _WidthPrec _M_prec_kind : 2; unsigned _M_debug : 1; _Pres_type _M_type : 4; unsigned _M_reserved : 8; So these are bugs, there is no reads or lvalue-to-rvalue conversions. > >> 2026-10-08 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: Expect different diagnostics. >> * 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-09-25 17:52:15.181532762 +0200 >> +++ b/gcc/cp/cp-tree.h 2026-10-07 15:47:31.888619582 +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-07 10:13:02.740411711 +0200 >> +++ b/gcc/cp/constexpr.cc 2026-10-07 17:58:04.370425876 +0200 >> @@ -3291,6 +3291,196 @@ 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) >> + { >> + if (CONSTRUCTOR_NELTS (t) == 0) >> + return false; >> + components->safe_push (CONSTRUCTOR_ELT (t, 0)->index); >> + if (find_uninit_subobject (CONSTRUCTOR_ELT (t, 0)->value, >> + NULL_TREE, components)) >> + return true; >> + components->pop (); >> + 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 +3596,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 +5241,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 +9186,25 @@ 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)); >> + if (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 +10304,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-03-27 >> 10:17:15.418309787 +0100 >> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-92443.C 2026-10-07 >> 17:24:54.562533390 +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-09-10 >> 16:56:41.692638816 +0200 >> +++ b/gcc/testsuite/g++.dg/cpp26/trivial-union6.C 2026-10-07 >> 17:49:38.504057082 +0200 >> @@ -10,29 +10,29 @@ 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 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; } >> -constexpr C c = fC (); // { dg-error "is not a constant >> expression" } >> -constexpr D fD () { D a; a.a.b[0] = 1; return a; } >> -constexpr D d = fD (); // { dg-error "is not a constant >> expression" } >> -constexpr E fE () { E a; a.a.b[0][0] = 1; a.a.b[1][0] = 2; a.a.b[1][1] = >> 3; return a; } >> -constexpr E e = fE (); // { dg-error "is not a constant >> expression" } >> -constexpr F fF () { F a; a.b.a[0] = 1; return a; } >> -constexpr F f = fF (); // { dg-error "is not a constant >> expression" } >> -constexpr G fG () { G a; a.b[0].a[0] = 1; return a; } >> -constexpr G g = fG (); // { dg-error "is not a constant >> expression" } >> +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; } // { dg-error >> "accessing uninitialized subobject 'B::b\\\[1\\\]'" } >> +constexpr B b = fB (); >> +constexpr C fC () { C a; a.b[0][0] = 1; a.b[1][0] = 2; a.b[1][1] = 3; >> return a; } // { dg-error "accessing uninitialized subobject >> 'C::b\\\[0\\\]\\\[1\\\]'" } >> +constexpr C c = fC (); >> +constexpr D fD () { D a; a.a.b[0] = 1; return a; } // { dg-error >> "accessing uninitialized subobject 'D::a.B::b\\\[1\\\]'" } >> +constexpr D d = fD (); >> +constexpr E fE () { E a; a.a.b[0][0] = 1; a.a.b[1][0] = 2; a.a.b[1][1] = >> 3; return a; } // { dg-error "accessing uninitialized subobject >> 'E::a.C::b\\\[0\\\]\\\[1\\\]'" } >> +constexpr E e = fE (); >> +constexpr F fF () { F a; a.b.a[0] = 1; return a; } // { dg-error >> "accessing uninitialized subobject 'F::b.A::a\\\[1\\\]'" } >> +constexpr F f = fF (); >> +constexpr G fG () { G a; a.b[0].a[0] = 1; return a; } // { dg-error >> "accessing uninitialized subobject 'G::b\\\[0\\\].A::a\\\[1\\\]'" } >> +constexpr G g = fG (); >> constexpr B >> fB2 () >> { >> B a; >> __builtin_start_lifetime (&a.b); >> a.b[0] = 1; >> - return a; >> + return a; // { dg-error "accessing uninitialized >> subobject 'B::b\\\[1\\\]'" } >> } >> -constexpr B b2 = fB2 (); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> +constexpr B b2 = fB2 (); >> constexpr C >> fC2 (bool x) >> { >> @@ -44,19 +44,19 @@ fC2 (bool x) >> a.b[0][0] = 1; >> a.b[1][0] = 2; >> a.b[1][1] = 3; >> - return a; >> + return a; // { dg-error "accessing uninitialized >> subobject 'C::b\\\[0\\\]\\\[1\\\]'" } >> } >> -constexpr C c2 = fC2 (false); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> -constexpr C c3 = fC2 (true); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> +constexpr C c2 = fC2 (false); >> +constexpr C c3 = fC2 (true); >> constexpr D >> fD2 () >> { >> D a; >> __builtin_start_lifetime (&a.a.b); >> a.a.b[0] = 1; >> - return a; >> + return a; // { dg-error "accessing uninitialized >> subobject 'D::a.B::b\\\[1\\\]'" } >> } >> -constexpr D d2 = fD2 (); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> +constexpr D d2 = fD2 (); >> constexpr E >> fE2 (bool x) >> { >> @@ -68,10 +68,10 @@ fE2 (bool x) >> a.a.b[0][0] = 1; >> a.a.b[1][0] = 2; >> a.a.b[1][1] = 3; >> - return a; >> + return a; // { dg-error "accessing uninitialized >> subobject 'E::a.C::b\\\[0\\\]\\\[1\\\]'" } >> } >> -constexpr E e2 = fE2 (false); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> -constexpr E e3 = fE2 (true); // { dg-error "is not a constant >> expression" "" { target c++23_down } } >> +constexpr E e2 = fE2 (false); >> +constexpr E e3 = fE2 (true); >> constexpr E >> fE3 (bool x) >> { >> --- a/gcc/testsuite/g++.dg/cpp26/trivial-union7.C 2026-10-07 >> 19:10:03.791539734 +0200 >> +++ b/gcc/testsuite/g++.dg/cpp26/trivial-union7.C 2026-10-07 >> 19:35:19.844409324 +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-09-14 >> 18:13:08.000000000 +0200 >> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C 2026-10-07 >> 17:52:42.254648368 +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-07 >> 10:40:43.626150885 +0200 >> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init24.C 2026-10-07 >> 13:31:38.442354373 +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; // { dg-error "accessing uninitialized >> subobject 'D::j.C::h.A::b'" } >> + 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; // { dg-error "accessing uninitialized >> subobject 'D::j.C::h.A::a'" } >> + 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; // { dg-error "accessing uninitialized >> subobject 'C::h.A::b'" } >> + if (x == 19) >> + C h = f; // { dg-error "accessing uninitialized >> subobject 'C::h.A::b'" } >> + else if (x == 20) >> + D i = d; // { dg-error "accessing uninitialized >> subobject 'D::j.C::h.A::a'" } >> + else if (x == 21) >> + B j = b; // { dg-error "accessing uninitialized >> subobject 'B::d.A::b'" } >> + else if (x == 22) >> + baz (f); // { dg-error "accessing uninitialized >> subobject 'C::h.A::b'" } >> + else if (x == 23) >> + baz (d); // { dg-error "accessing uninitialized >> subobject 'D::j.C::h.A::a'" } >> + 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); // { dg-error "accessing uninitialized >> subobject 'C::h.A::b'" } >> + else if (x == 29) >> + qux (true, d); // { dg-error "accessing uninitialized >> subobject 'D::j.C::h.A::a'" } >> + 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; // { dg-error "accessing >> uninitialized subobject 'C::h.A::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; // { dg-error "accessing uninitialized >> subobject 'C::h.A::a'" } >> +} // { dg-error "accessing uninitialized >> subobject 'C::h.A::b'" "" { target *-*-* } .-1 } >> + >> +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)); >> +constexpr bool g = foo (11); >> +static_assert (foo (12)); >> +static_assert (foo (13)); >> +constexpr bool h = foo (14); >> +static_assert (foo (15)); >> +static_assert (foo (16)); >> +static_assert (foo (17)); >> +constexpr bool i = foo (18); >> +constexpr bool j = foo (19); >> +constexpr bool k = foo (20); >> +constexpr bool l = foo (21); >> +constexpr bool m = foo (22); >> +constexpr bool n = foo (23); >> +constexpr bool o = foo (24); >> +static_assert (foo (25)); >> +static_assert (foo (26)); >> +static_assert (foo (27)); >> +constexpr bool p = foo (28); >> +constexpr bool q = 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-03-27 >> 10:17:15.660305838 +0100 >> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C 2026-10-08 >> 10:26:30.691073100 +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-03-27 >> 10:17:15.660305838 +0100 >> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C 2026-10-08 >> 10:36:25.502885551 +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-03-27 >> 10:17:15.660305838 +0100 >> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C 2026-10-08 >> 10:48:52.696607070 +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-05-14 >> 09:51:59.000000000 +0200 >> +++ b/gcc/testsuite/g++.dg/reflect/bases_of5.C 2026-10-08 >> 11:18:57.465809669 +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 >> >>
