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
>>
>>

Reply via email to