[PATCH] c++, libstdc++, v2: Implement C++26 P3074R7, P3726R0 and CWG3189 - trivial unions [PR119059]

Tomasz Kaminski tkaminsk@redhat.com
Thu May 21 07:00:42 GMT 2026


On Thu, May 21, 2026 at 8:37 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:

>
>
> On Wed, May 20, 2026 at 5:41 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
>> On Wed, May 20, 2026 at 02:00:27PM +0200, Tomasz Kaminski wrote:
>> > I would like to see test user-provided constructors for union-like
>> types,
>> > something like:
>> > union U  { U();  int x; X b;  }; // trivial for X = int, and deleted
>> for T
>> > = G (non-trivial destructor)
>> > struct UL { UL(); union { int x; X b; }  }; // same
>> >
>> > Also, for a non-default constructor and a union-like version of the
>> above
>> > union U { U(int);  int x; X b;  }; // All constructors matter, not only
>> the
>> > default one,
>> > union  U { U() = default; U(int);  int x; X b;  }; // all cosntructor
>> > matters, not only default,
>> > (above with union-like versions)
>>
>> I've added some tests.
>>
>> > This would be a follow-up regardless, but could you check if codegen for
>> > the below
>> > is now the same:
>> > FixedVector<char, 4> f() {
>> >   return {'a', 'b', 'c'};
>> > }
>> > FixedVector<char, 4> g() {
>> >   constexpr FixedVector<char, 4> result{'a', 'b', 'c'};
>> >   return result;
>> > }
>> >
>> > (Need a FixedVector from initializer_liust constructor )
>> >
>> > // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124121
>>
>> The FixedVector doesn't have ctor from initializer_list; when using
>> inplace_vector as is in the headers, f gets worse code generated,
>> e.g. because start_lifetime_as uses inline asm.
>>
>> > > +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" "" { target c++23_down } }
>> > > +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" "" { target c++23_down } }
>> > > +constexpr D fD () { D a; a.a.b[0] = 1; return a; }
>> > > +constexpr D d = fD ();         // { dg-error "is not a constant
>> > > expression" "" { target c++23_down } }
>> > > +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" "" { target c++23_down } }
>> > >
>> > I think it's already mentioned in the commit message, but all of the
>> above
>> > should also fails in C++26 mode.
>> > The assigments rules were not changed so a.b[0][0] = 1, starts the whole
>> > array with all the elements,
>> > and we have uninitialized elements inside, that are in-lifetime.
>> >
>> > To achieve the above, you should start_lifetime of the array first and
>> only
>> > then assign values to its elements,
>> > so https://eel.is/c++draft/class.union#general-5 does not create an
>> array
>> > with elements.
>>
>> Haven't touched this yet.
>> >
>> > +static_assert (!is_defaulted (Octor) && !is_deleted (Octor));
>> > > +static_assert (is_defaulted (Odtor) && is_deleted (Odtor));
>> > >
>> > I assume you are skipping questions about the constructor/destructor
>> > anonymous union inside
>> > union-like types on purpose?
>>
>> CWG3130 says they don't exist and I plan to work on resolving that soon,
>> so trying to test those is pointless.
>>
>> > > +#if __glibcxx_start_lifetime >= 202603L // C++ >= 26
>> > > +namespace std _GLIBCXX_VISIBILITY(default)
>> > > +{
>> > > +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>> > > +
>> > > +  template <class _Tp>
>> > > +    constexpr void
>> > > +    start_lifetime(_Tp& __r) noexcept
>> > >
>> > Could you move the declaration to
>> libstdc++-v3/include/bits/stl_construct.h,
>> > (we start_lifetime_as, cosntruct_as is). We do not not want  to include
>> > whole header.
>>
>> Moved.
>>
>> 2026-05-20  Jakub Jelinek  <jakub@redhat.com>
>>
>> gcc/c-family/
>>         * c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine
>>         __cpp_trivial_union to 202603L.
>> gcc/cp/
>>         * method.cc: Implement C++26 P3074R7 - trivial unions (was
>>         std::uninitialized<T>), P3726R2 - Adjustments to Union Lifetime
>> Rules
>>         and proposed resolution of CWG3189 - Implicitly deleted
>> destructors
>>         for union-like classes.
>>         (walk_field_subobs): Don't do default_init_uninitialized_part
>> checks
>>         for variant members.  Don't check subobject ctor/dtor for variant
>>         members for ctor/inheriting ctor or when subobject doesn't have
>> member
>>         initializer for dtor and it is either the dtor_from_ctor case or
>>         the current class doesn't have user provided ctors.
>>         * class.cc (check_field_decl): Don't or in
>>         TYPE_HAS_NONTRIVIAL_DESTRUCTOR or TYPE_HAS_DEFAULT_CONSTRUCTOR of
>>         variant subobjects for C++26.
>>         * cp-tree.h (enum cp_built_in_function): Add
>>         CP_BUILT_IN_START_LIFETIME.
>>         (check_builtin_start_lifetime): Declare.
>>         (reduced_constant_expression_p): Add a bool argument defaulted to
>>         false.
>>         * tree.cc (builtin_valid_in_constant_expr_p): Handle
>>         CP_BUILT_IN_START_LIFETIME.
>>         * decl.cc (cxx_init_decl_processing): Create
>> __builtin_start_lifetime
>>         decl.
>>         * cp-gimplify.cc (cp_gimplify_expr): Handle
>>         CP_BUILT_IN_START_LIFETIME.
>>         * semantics.cc (check_builtin_start_lifetime): New function.
>>         * constexpr.cc (cxx_eval_start_lifetime): New function.
>>         (cxx_eval_builtin_function_call): Handle
>> CP_BUILT_IN_START_LIFETIME.
>>         (reduced_constant_expression_p): Add union_elemental_subobject
>>         argument and propagate it to recursive calls.  If set, ignore
>> holes
>>         in array initializers.
>>         (cxx_eval_store_expression): Add start_lifetime argument.  Don't
>>         preevaluate init in tha tcase, return early if !seen_union after
>>         loop around the possibly nested ARRAY_REFs/COMPONENT_REFs etc.
>>         or when all union members are already active.
>> gcc/testsuite/
>>         * g++.dg/DRs/dr2581-1.C: Expect warning for __cpp_trivial_union.
>>         * g++.dg/DRs/dr2581-2.C: Expect error for __cpp_trivial_union.
>>         * g++.dg/cpp26/feat-cxx26.C: Add __cpp_trivial_union checking.
>>         * g++.dg/cpp26/trivial-union1.C: New test.
>>         * g++.dg/cpp26/trivial-union2.C: New test.
>>         * g++.dg/cpp26/trivial-union3.C: New test.
>>         * g++.dg/cpp26/trivial-union4.C: New test.
>>         * g++.dg/cpp26/trivial-union5.C: New test.
>>         * g++.dg/cpp26/trivial-union6.C: New test.
>>         * g++.dg/reflect/trivial-union1.C: New test.
>>         * g++.dg/reflect/type_trait6.C: Adjust expected result of
>>         one is_destructible_type and two is_nothrow_destructible_type
>> calls.
>>         * g++.dg/reflect/is_constructible_type1.C: Adjust expected result
>>         of one is_constructible_type call.
>>         * g++.dg/init/pr43719.C: Don't expect one error.
>>         * g++.dg/init/pr25811.C: Don't expect 3 diagnostic messages,
>>         instead expect a different one for C++98 only.
>>         * g++.dg/other/anon-union2.C: Only expect one diagnostic for
>>         C++23 and older.
>>         * g++.dg/cpp0x/union1.C: Only expect 6 diagnostic messages for
>>         C++23 and older.
>>         * g++.dg/cpp0x/union4.C: Only expect 3 diagnostic messages for
>>         C++23 and older.
>>         * g++.dg/cpp0x/defaulted2.C: Only expect 2 diagnostic messages for
>>         C++23 and older.
>> libstdc++-v3/
>>         * include/bits/version.def (start_lifetime): New.
>>         * include/bits/version.h: Regenerate.
>>         * include/bits/stl_construct.h (std::start_lifetime): New function
>>         template.
>>         * include/std/memory: Define __glibcxx_want_start_lifetime before
>>         including bits/version.h.
>>         * src/c++23/std.cc.in: Add export std::start_lifetime.
>>
>> --- gcc/c-family/c-cppbuiltin.cc.jj     2026-05-20 08:43:02.545478650
>> +0200
>> +++ gcc/c-family/c-cppbuiltin.cc        2026-05-20 14:26:01.233439033
>> +0200
>> @@ -1122,6 +1122,7 @@ c_cpp_builtins (cpp_reader *pfile)
>>             cpp_define (pfile, "__cpp_impl_reflection=202603L");
>>           else
>>             cpp_warn (pfile, "__cpp_impl_reflection");
>> +         cpp_define (pfile, "__cpp_trivial_union=202603L");
>>         }
>>        if (flag_concepts && cxx_dialect > cxx14)
>>         cpp_define (pfile, "__cpp_concepts=202002L");
>> --- gcc/cp/method.cc.jj 2026-05-20 08:43:02.566478296 +0200
>> +++ gcc/cp/method.cc    2026-05-20 14:26:01.234439016 +0200
>> @@ -2692,6 +2692,7 @@ walk_field_subobs (tree fields, special_
>>    enum { unknown, no, yes }
>>    only_dmi_mem = (sfk == sfk_constructor && TREE_CODE (ctx) == UNION_TYPE
>>                   ? unknown : no);
>> +  int has_user_provided_ctor = -1;
>>
>>   again:
>>    for (tree field = fields; field; field = DECL_CHAIN (field))
>> @@ -2771,6 +2772,7 @@ walk_field_subobs (tree fields, special_
>>
>>           bad = false;
>>           if (CP_TYPE_CONST_P (mem_type)
>> +             && TREE_CODE (ctx) != UNION_TYPE
>>               && default_init_uninitialized_part (mem_type))
>>             {
>>               if (diag)
>> @@ -2847,6 +2849,22 @@ walk_field_subobs (tree fields, special_
>>        else
>>         argtype = NULL_TREE;
>>
>> +      if (cxx_dialect >= cxx26 && TREE_CODE (ctx) == UNION_TYPE)
>> +       {
>> +         if (sfk == sfk_constructor || sfk == sfk_inheriting_constructor)
>> +           continue;
>> +
>> +         if (sfk == sfk_destructor)
>> +           {
>> +             if (!dtor_from_ctor && has_user_provided_ctor == -1)
>> +               has_user_provided_ctor
>> +                 = type_has_user_provided_constructor
>> (current_class_type);
>> +             if (DECL_INITIAL (field) == NULL_TREE
>> +                 && (dtor_from_ctor || !has_user_provided_ctor))
>> +               continue;
>> +           }
>> +       }
>> +
>>        rval = locate_fn_flags (mem_type, fnname, argtype, flags,
>> complain);
>>
>>        process_subob_fn (rval, sfk, spec_p, trivial_p, deleted_p,
>> --- gcc/cp/class.cc.jj  2026-05-20 08:43:02.551478549 +0200
>> +++ gcc/cp/class.cc     2026-05-20 14:26:01.235439000 +0200
>> @@ -3903,17 +3903,25 @@ check_field_decl (tree field,
>>        else
>>         {
>>           TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
>> -         TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
>> -           |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
>>           TYPE_HAS_COMPLEX_COPY_ASSIGN (t)
>>             |= (TYPE_HAS_COMPLEX_COPY_ASSIGN (type)
>>                 || !TYPE_HAS_COPY_ASSIGN (type));
>>           TYPE_HAS_COMPLEX_COPY_CTOR (t) |= (TYPE_HAS_COMPLEX_COPY_CTOR
>> (type)
>>                                              || !TYPE_HAS_COPY_CTOR
>> (type));
>> -         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |=
>> TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);
>> +         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)
>> +           |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);
>>           TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR
>> (type);
>> -         TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR
>> (type)
>> -                                       || TYPE_HAS_COMPLEX_DFLT (type));
>> +         /* In C++26, triviality of default ctor or dtor of a variant
>> member
>> +            doesn't matter for triviality of the t's default ctor or
>> dtor.  */
>> +         if (cxx_dialect < cxx26
>> +             || TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)
>> +           {
>> +             TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
>> +               |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
>> +             TYPE_HAS_COMPLEX_DFLT (t)
>> +               |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
>> +                   || TYPE_HAS_COMPLEX_DFLT (type));
>> +           }
>>         }
>>
>>        if (TYPE_HAS_COPY_CTOR (type)
>> --- gcc/cp/cp-tree.h.jj 2026-05-20 08:43:07.245399375 +0200
>> +++ gcc/cp/cp-tree.h    2026-05-20 14:26:01.237438967 +0200
>> @@ -7245,6 +7245,7 @@ enum cp_built_in_function {
>>    CP_BUILT_IN_CONSTEXPR_DIAG,
>>    CP_BUILT_IN_CURRENT_EXCEPTION,
>>    CP_BUILT_IN_UNCAUGHT_EXCEPTIONS,
>> +  CP_BUILT_IN_START_LIFETIME,
>>    CP_BUILT_IN_LAST
>>  };
>>
>> @@ -8666,6 +8667,7 @@ extern tree fold_builtin_is_correspondin
>>  extern bool pointer_interconvertible_base_of_p (tree, tree, bool =
>> false);
>>  extern tree fold_builtin_is_pointer_inverconvertible_with_class
>> (location_t, int, tree *);
>>  extern tree fold_builtin_is_string_literal     (location_t, int, tree *);
>> +extern bool check_builtin_start_lifetime       (location_t, int, tree *,
>> tsubst_flags_t);
>>  extern tree finish_structured_binding_size     (location_t, tree,
>> tsubst_flags_t);
>>  extern tree finish_trait_expr                  (location_t, enum
>> cp_trait_kind, tree, tree);
>>  extern tree finish_trait_type                  (enum cp_trait_kind,
>> tree, tree, tsubst_flags_t);
>> @@ -9435,7 +9437,7 @@ extern tree fold_non_dependent_init
>>  (tr
>>                                                  bool = false, tree =
>> NULL_TREE);
>>  extern tree fold_simple                                (tree);
>>  extern tree fold_to_constant                   (tree);
>> -extern bool reduced_constant_expression_p       (tree, tree = NULL_TREE);
>> +extern bool reduced_constant_expression_p       (tree, tree = NULL_TREE,
>> bool = false);
>>  extern bool is_instantiation_of_constexpr       (tree);
>>  extern bool var_in_constexpr_fn                 (tree);
>>  extern bool var_in_maybe_constexpr_fn           (tree);
>> --- gcc/cp/tree.cc.jj   2026-05-20 08:43:02.572478195 +0200
>> +++ gcc/cp/tree.cc      2026-05-20 14:26:01.238177470 +0200
>> @@ -574,6 +574,7 @@ builtin_valid_in_constant_expr_p (const_
>>           case CP_BUILT_IN_CONSTEXPR_DIAG:
>>           case CP_BUILT_IN_CURRENT_EXCEPTION:
>>           case CP_BUILT_IN_UNCAUGHT_EXCEPTIONS:
>> +         case CP_BUILT_IN_START_LIFETIME:
>>             return true;
>>           default:
>>             break;
>> --- gcc/cp/decl.cc.jj   2026-05-20 08:43:02.564478330 +0200
>> +++ gcc/cp/decl.cc      2026-05-20 14:26:01.240438917 +0200
>> @@ -5663,6 +5663,13 @@ cxx_init_decl_processing (void)
>>                                BUILT_IN_FRONTEND, NULL, NULL_TREE);
>>    set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
>>
>> +  tree void_vaftype = build_varargs_function_type_list
>> (boolean_type_node,
>> +                                                       NULL_TREE);
>> +  decl = add_builtin_function ("__builtin_start_lifetime",
>> +                              void_vaftype, CP_BUILT_IN_START_LIFETIME,
>> +                              BUILT_IN_FRONTEND, NULL, NULL_TREE);
>> +  set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
>> +
>>    integer_two_node = build_int_cst (NULL_TREE, 2);
>>
>>    /* Guess at the initial static decls size.  */
>> --- gcc/cp/cp-gimplify.cc.jj    2026-05-20 08:43:02.554478498 +0200
>> +++ gcc/cp/cp-gimplify.cc       2026-05-20 14:26:01.241438900 +0200
>> @@ -1015,6 +1015,14 @@ cp_gimplify_expr (tree *expr_p, gimple_s
>>               case CP_BUILT_IN_CONSTEXPR_DIAG:
>>                 *expr_p = void_node;
>>                 break;
>> +             case CP_BUILT_IN_START_LIFETIME:
>> +               check_builtin_start_lifetime (EXPR_LOCATION (*expr_p),
>> +                                             call_expr_nargs (*expr_p),
>> +                                             call_expr_nargs (*expr_p)
>> +                                             ? &CALL_EXPR_ARG (*expr_p,
>> 0)
>> +                                             : NULL,
>> +                                             tf_warning_or_error);
>> +               *expr_p = void_node;
>>               default:
>>                 break;
>>               }
>> --- gcc/cp/semantics.cc.jj      2026-05-20 08:43:07.247399342 +0200
>> +++ gcc/cp/semantics.cc 2026-05-20 14:26:01.242438884 +0200
>> @@ -13989,6 +13989,53 @@ fold_builtin_is_string_literal (location
>>    return boolean_true_node;
>>  }
>>
>> +/* Perform __builtin_start_lifetime call checking, return false
>> +   when errors are reported.  */
>> +
>> +bool
>> +check_builtin_start_lifetime (location_t loc, int nargs, tree *args,
>> +                             tsubst_flags_t complain)
>> +{
>> +  /* Unless users call the builtin directly, the following 2 checks
>> should be
>> +     ensured from std::start_lifetime template.  */
>> +  if (nargs != 1)
>> +    {
>> +      if (complain & tf_error)
>> +       error_at (loc, "%<__builtin_start_lifetime%> needs a single "
>> +                 "argument");
>> +      return false;
>> +    }
>> +  tree arg = args[0];
>> +  if (error_operand_p (arg))
>> +    return false;
>> +  tree ptype = TREE_TYPE (arg);
>> +  if (!POINTER_TYPE_P (ptype))
>> +    {
>> +      if (complain & tf_error)
>> +       error_at (loc, "%<__builtin_start_lifetime%> argument type %qT "
>> +                 "is not pointer type", ptype);
>> +      return false;
>> +    }
>> +  tree type = TREE_TYPE (ptype);
>> +  if (!complete_type_or_else (type, NULL_TREE))
>> +    return false;
>> +  if (!CP_AGGREGATE_TYPE_P (type))
>> +    {
>> +      if (complain & tf_error)
>> +       error_at (loc, "%<__builtin_start_lifetime%> argument type %qT "
>> +                 "is not a pointer to aggregate type", ptype);
>> +      return false;
>> +    }
>> +  if (!implicit_lifetime_type_p (type))
>> +    {
>> +      if (complain & tf_error)
>> +       error_at (loc, "%<__builtin_start_lifetime%> argument type %qT "
>> +                 "is not a pointer to implicit-lifetime type", ptype);
>> +      return false;
>> +    }
>> +  return true;
>> +}
>> +
>>  /* [basic.types] 8.  True iff TYPE is an object type.  */
>>
>>  static bool
>> --- gcc/cp/constexpr.cc.jj      2026-05-20 08:43:07.244399392 +0200
>> +++ gcc/cp/constexpr.cc 2026-05-20 14:26:01.243438867 +0200
>> @@ -2456,6 +2456,49 @@ cxx_eval_constexpr_diag (const constexpr
>>    return void_node;
>>  }
>>
>> +static tree cxx_eval_store_expression (const constexpr_ctx *, tree,
>> +                                      value_cat, bool *, bool *,
>> +                                      tree *, bool = false);
>> +
>> +/* Attempt to evaluate T which represents a call to
>> +   __builtin_start_lifetime.  */
>> +
>> +static tree
>> +cxx_eval_start_lifetime (const constexpr_ctx *ctx, tree t, bool
>> *non_constant_p,
>> +                        bool *overflow_p, tree *jump_target)
>> +{
>> +  location_t loc = EXPR_LOCATION (t);
>> +  if (!check_builtin_start_lifetime (loc, call_expr_nargs (t),
>> +                                    call_expr_nargs (t)
>> +                                    ? &CALL_EXPR_ARG (t, 0) : NULL,
>> +                                    ctx->quiet ? tf_none
>> +                                    : tf_warning_or_error))
>> +    {
>> +      *non_constant_p = true;
>> +      return t;
>> +    }
>> +  tree arg = CALL_EXPR_ARG (t, 0);
>> +  arg = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (arg)), arg);
>> +  arg = cxx_eval_constant_expression (ctx, arg, vc_glvalue,
>> +                                     non_constant_p, overflow_p,
>> +                                     jump_target);
>> +  if (*jump_target)
>> +    return NULL_TREE;
>> +  if (*non_constant_p)
>> +    return t;
>> +  tree ctor = build_constructor (TREE_TYPE (arg), NULL);
>> +  CONSTRUCTOR_NO_CLEARING (ctor) = 1;
>> +  tree modexpr = build2 (MODIFY_EXPR, TREE_TYPE (arg), arg, ctor);
>> +  arg = cxx_eval_store_expression (ctx, modexpr, vc_discard,
>> non_constant_p,
>> +                                  overflow_p, jump_target, true);
>> +  ggc_free (modexpr);
>> +  if (*jump_target)
>> +    return NULL_TREE;
>> +  if (*non_constant_p)
>> +    return t;
>> +  return void_node;
>> +}
>> +
>>  /* Attempt to evaluate T which represents a call to a builtin function.
>>     We assume here that all builtin functions evaluate to scalar types
>>     represented by _CST nodes.  */
>> @@ -2529,6 +2572,10 @@ cxx_eval_builtin_function_call (const co
>>         return cxx_eval_constexpr_diag (ctx, t, non_constant_p,
>> overflow_p,
>>                                         jump_target);
>>
>> +      case CP_BUILT_IN_START_LIFETIME:
>> +        return cxx_eval_start_lifetime (ctx, t, non_constant_p,
>> overflow_p,
>> +                                       jump_target);
>> +
>>        default:
>>         break;
>>        }
>> @@ -4708,7 +4755,8 @@ cxx_eval_call_expression (const constexp
>>     FIXME speed this up, it's taking 16% of compile time on sieve
>> testcase.  */
>>
>>  bool
>> -reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */)
>> +reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */,
>> +                              bool union_elemental_subobject /* = false
>> */)
>>  {
>>    if (t == NULL_TREE)
>>      return false;
>> @@ -4732,7 +4780,10 @@ reduced_constant_expression_p (tree t, t
>>         return false;
>>        if (CONSTRUCTOR_NO_CLEARING (t))
>>         {
>> -         if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
>> +         if (union_elemental_subobject
>> +             && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
>> +           field = NULL_TREE;
>> +         else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
>>             {
>>               /* There must be a valid constant initializer at every array
>>                  index.  */
>> @@ -4766,12 +4817,25 @@ reduced_constant_expression_p (tree t, t
>>                  active member has no constituent values, so all
>> constituent
>>                  values are constant.  */
>>               field = NULL_TREE;
>> +             union_elemental_subobject = cxx_dialect >= cxx26;
>>             }
>>           else
>> -           field = next_subobject_field (TYPE_FIELDS (TREE_TYPE (t)));
>> +           {
>> +             field = next_subobject_field (TYPE_FIELDS (TREE_TYPE (t)));
>> +             union_elemental_subobject = false;
>> +           }
>>         }
>>        else
>> -       field = NULL_TREE;
>> +       {
>> +         field = NULL_TREE;
>> +         if (cxx_dialect >= cxx26)
>> +           {
>> +             if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
>> +               union_elemental_subobject = true;
>> +             else if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE)
>> +               union_elemental_subobject = false;
>> +           }
>> +       }
>>        for (auto &e: CONSTRUCTOR_ELTS (t))
>>         {
>>           /* If VAL is null, we're in the middle of initializing this
>> @@ -4781,7 +4845,8 @@ reduced_constant_expression_p (tree t, t
>>                                                && (TREE_CODE (e.index)
>>                                                    == FIELD_DECL))
>>                                               ? DECL_SIZE (e.index)
>> -                                             : NULL_TREE))
>> +                                             : NULL_TREE,
>> +                                             union_elemental_subobject))
>>             return false;
>>           /* We want to remove initializers for empty fields in a struct
>> to
>>              avoid confusing output_constructor.  */
>> @@ -7817,7 +7882,7 @@ static tree
>>  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>>                            value_cat lval,
>>                            bool *non_constant_p, bool *overflow_p,
>> -                          tree *jump_target)
>> +                          tree *jump_target, bool
>> start_lifetime/*=false*/)
>>  {
>>    constexpr_ctx new_ctx = *ctx;
>>
>> @@ -7830,7 +7895,7 @@ cxx_eval_store_expression (const constex
>>
>>    tree type = TREE_TYPE (target);
>>    bool preeval = SCALAR_TYPE_P (type) || TREE_CODE (t) == MODIFY_EXPR;
>> -  if (preeval && !TREE_CLOBBER_P (init))
>> +  if (preeval && !TREE_CLOBBER_P (init) && !start_lifetime)
>>      {
>>        /* Ignore var = .DEFERRED_INIT (); for now, until PR121965 is
>> fixed.  */
>>        if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
>> @@ -8037,6 +8102,11 @@ cxx_eval_store_expression (const constex
>>        const_object_being_modified = NULL_TREE;
>>      }
>>
>> +  /* For __builtin_start_lifetime, if no union is involved, no need to
>> +     change anything.  */
>> +  if (start_lifetime && !seen_union)
>> +    return void_node;
>> +
>>    type = TREE_TYPE (object);
>>    bool no_zero_init = true;
>>    bool zero_padding_bits = false;
>> @@ -8170,12 +8240,13 @@ cxx_eval_store_expression (const constex
>>                           index);
>>               *non_constant_p = true;
>>             }
>> -         else if (!is_access_expr
>> -                  || (TREE_CLOBBER_P (init)
>> -                      && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END)
>> -                  || (TREE_CODE (t) == MODIFY_EXPR
>> -                      && CLASS_TYPE_P (inner)
>> -                      && !type_has_non_deleted_trivial_default_ctor
>> (inner)))
>> +         else if ((!is_access_expr
>> +                   || (TREE_CLOBBER_P (init)
>> +                       && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END)
>> +                   || (TREE_CODE (t) == MODIFY_EXPR
>> +                       && CLASS_TYPE_P (inner)
>> +                       && !type_has_non_deleted_trivial_default_ctor
>> (inner)))
>> +                  && !start_lifetime)
>>             {
>>               /* Diagnose changing active union member after
>> initialization
>>                  without a valid member access expression, as described in
>> @@ -8221,6 +8292,10 @@ cxx_eval_store_expression (const constex
>>             }
>>           no_zero_init = true;
>>         }
>> +      /* If this is the innermost union and we aren't changing active
>> member
>> +        of it during start_lifetime, we don't need to change anything.
>> */
>> +      else if (code == UNION_TYPE && start_lifetime && seen_union == 1)
>> +       return void_node;
>>
>>        /* Ending the lifetime of the active union member means the union
>> no
>>          longer has an active member.  */
>> --- gcc/testsuite/g++.dg/DRs/dr2581-1.C.jj      2026-05-20
>> 08:43:02.577478111 +0200
>> +++ gcc/testsuite/g++.dg/DRs/dr2581-1.C 2026-05-20 14:26:01.244438851
>> +0200
>> @@ -94,7 +94,7 @@
>>  #undef __cpp_template_parameters
>>  #undef __cpp_template_template_args    // { dg-warning "undefining
>> '__cpp_template_template_args'" "" { target c++20 } }
>>  #undef __cpp_threadsafe_static_init    // { dg-warning "undefining
>> '__cpp_threadsafe_static_init'" "" { target c++20 } }
>> -#undef __cpp_trivial_union
>> +#undef __cpp_trivial_union             // { dg-warning "undefining
>> '__cpp_trivial_union'" "" { target c++26 } }
>>  #undef __cpp_unicode_characters                // { dg-warning
>> "undefining '__cpp_unicode_characters'" "" { target c++20 } }
>>  #undef __cpp_unicode_literals          // { dg-warning "undefining
>> '__cpp_unicode_literals'" "" { target c++20 } }
>>  #undef __cpp_user_defined_literals     // { dg-warning "undefining
>> '__cpp_user_defined_literals'" "" { target c++20 } }
>> --- gcc/testsuite/g++.dg/DRs/dr2581-2.C.jj      2026-05-20
>> 08:43:02.577478111 +0200
>> +++ gcc/testsuite/g++.dg/DRs/dr2581-2.C 2026-05-20 14:26:01.244751680
>> +0200
>> @@ -95,7 +95,7 @@
>>  #define __cpp_template_parameters 202502L
>>  #define __cpp_template_template_args 201611L   // { dg-error
>> "'__cpp_template_template_args' redefined" "" { target c++20 } }
>>  #define __cpp_threadsafe_static_init 200806L   // { dg-error
>> "'__cpp_threadsafe_static_init' redefined" "" { target c++20 } }
>> -#define __cpp_trivial_union 202502L
>> +#define __cpp_trivial_union 202603L            // { dg-error
>> "'__cpp_trivial_union' redefined" "" { target c++26 } }
>>  #define __cpp_unicode_characters 200704L       // { dg-error
>> "'__cpp_unicode_characters' redefined" "" { target c++17 } }
>>  #define __cpp_unicode_literals 200710L         // { dg-error
>> "'__cpp_unicode_literals' redefined" "" { target c++20 } }
>>  #define __cpp_user_defined_literals 200809L    // { dg-error
>> "'__cpp_user_defined_literals' redefined" "" { target c++20 } }
>> --- gcc/testsuite/g++.dg/cpp0x/union1.C.jj      2026-03-27
>> 10:17:15.542307763 +0100
>> +++ gcc/testsuite/g++.dg/cpp0x/union1.C 2026-05-20 14:26:01.248075538
>> +0200
>> @@ -14,7 +14,7 @@ union B
>>    A a;                         // { dg-error "union member" }
>>  };
>>
>> -B b;                           // { dg-error "B::B\\(\\)" "B::B" }
>> +B b;                           // { dg-error "B::B\\(\\)" "B::B" {
>> target c++23_down } }
>>  B b2(b);                       // { dg-error "B::B\\(const B&\\)" "B::B"
>> }
>>
>>  struct C
>> @@ -25,10 +25,10 @@ struct C
>>    };
>>  };
>>
>> -C c;                           // { dg-error "C::C\\(\\)" "C::C" }
>> +C c;                           // { dg-error "C::C\\(\\)" "C::C" {
>> target c++23_down } }
>>  C c2(c);                       // { dg-error "C::C\\(const C&\\)" "C::C"
>> }
>>
>> -// { dg-error "B::~B" "B::~B" { target *-*-* } 17 }
>> -// { dg-error "B::~B" "B::~B" { target *-*-* } 18 }
>> -// { dg-error "C::~C" "C::~C" { target *-*-* } 28 }
>> -// { dg-error "C::~C" "C::~C" { target *-*-* } 29 }
>> +// { dg-error "B::~B" "B::~B" { target c++23_down } 17 }
>> +// { dg-error "B::~B" "B::~B" { target c++23_down } 18 }
>> +// { dg-error "C::~C" "C::~C" { target c++23_down } 28 }
>> +// { dg-error "C::~C" "C::~C" { target c++23_down } 29 }
>> --- gcc/testsuite/g++.dg/cpp0x/union4.C.jj      2026-03-27
>> 10:17:15.542307763 +0100
>> +++ gcc/testsuite/g++.dg/cpp0x/union4.C 2026-05-20 14:26:01.248438784
>> +0200
>> @@ -3,15 +3,15 @@
>>
>>  struct SFoo
>>  {
>> -  SFoo() =delete;              // { dg-message "declared" }
>> +  SFoo() =delete;              // { dg-message "declared" "" { target
>> c++23_down } }
>>  };
>>
>> -union UFoo                     // { dg-error "deleted" }
>> +union UFoo                     // { dg-error "deleted" "" { target
>> c++23_down } }
>>  {
>>    SFoo foo;
>>  };
>>
>>  int main()
>>  {
>> -  UFoo();                      // { dg-error "deleted" }
>> +  UFoo();                      // { dg-error "deleted" "" { target
>> c++23_down } }
>>  }
>> --- gcc/testsuite/g++.dg/cpp0x/defaulted2.C.jj  2026-03-27
>> 10:17:15.446309330 +0100
>> +++ gcc/testsuite/g++.dg/cpp0x/defaulted2.C     2026-05-20
>> 14:26:01.248646182 +0200
>> @@ -55,7 +55,7 @@ G::G() = default;
>>
>>  union U
>>  {
>> -  G g;                         // { dg-error "union member.*non-trivial"
>> }
>> +  G g;                         // { dg-error "union member.*non-trivial"
>> "" { target c++23_down } }
>>  };
>>
>>  int main()
>> @@ -63,7 +63,7 @@ int main()
>>    F f;
>>    F f2(f);                     // { dg-error "use" }
>>    const B* b = new const B;            // { dg-error "uninitialized
>> const" }
>> -  U u;                         // { dg-error "deleted" }
>> +  U u;                         // { dg-error "deleted" "" { target
>> c++23_down } }
>>  }
>>
>>  // { dg-prune-output "implicitly deleted because" }
>> --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj  2026-05-20
>> 08:43:02.579478077 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C     2026-05-20
>> 14:26:01.245053195 +0200
>> @@ -652,3 +652,9 @@
>>  #elif __cpp_expansion_statements != 202506
>>  #  error "__cpp_expansion_statements != 202506"
>>  #endif
>> +
>> +#ifndef __cpp_trivial_union
>> +#  error "__cpp_trivial_union"
>> +#elif __cpp_trivial_union != 202603
>> +#  error "__cpp_trivial_union != 202603"
>> +#endif
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union1.C.jj      2026-05-20
>> 14:26:01.245197174 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union1.C 2026-05-20
>> 17:26:39.297942500 +0200
>> @@ -0,0 +1,93 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++11 } }
>> +
>> +#include <type_traits>
>> +
>> +// These two were incorrectly deleted.
>> +union A { int a; const int b; };
>> +static_assert (std::is_default_constructible <A>::value, "");
>> +static_assert (std::is_trivially_default_constructible <A>::value, "");
>> +static_assert (std::is_destructible <A>::value, "");
>> +static_assert (std::is_trivially_destructible <A>::value, "");
>> +struct B { int a; union { int b; const int c; }; };
>> +static_assert (std::is_default_constructible <B>::value, "");
>> +static_assert (std::is_trivially_default_constructible <B>::value, "");
>> +static_assert (std::is_destructible <B>::value, "");
>> +static_assert (std::is_trivially_destructible <B>::value, "");
>> +// C::C() is incorrectly not deleted in C++11 to 23, but in C++26 it
>> should
>> +// not be deleted.
>> +union C { const int a = 42; const long b; ~C (); };
>> +#if __cpp_trivial_union >= 202502L
>> +static_assert (std::is_default_constructible <C>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <C>::value, "");
>> +static_assert (std::is_destructible <C>::value, "");
>> +static_assert (!std::is_trivially_destructible <C>::value, "");
>> +#endif
>> +struct D { D () = delete; D (int); ~D () = default; };
>> +union E { D a = 42; D b; ~E (); };
>> +static_assert (std::is_default_constructible <E>::value, "");
>> +static_assert (std::is_destructible <E>::value, "");
>> +struct F { int a; union { D b = 42; D c; }; };
>> +static_assert (std::is_default_constructible <F>::value, "");
>> +static_assert (std::is_destructible <F>::value, "");
>> +struct G { G (); ~G (); };
>> +union I { int a; const int b; ~I (); };
>> +static_assert (std::is_default_constructible <I>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <I>::value, "");
>> +static_assert (std::is_destructible <I>::value, "");
>> +static_assert (!std::is_trivially_destructible <I>::value, "");
>> +union J { D a; int b; };
>> +#if __cpp_trivial_union >= 202502L
>> +static_assert (std::is_default_constructible <J>::value, "");
>> +static_assert (std::is_trivially_default_constructible <J>::value, "");
>> +#else
>> +static_assert (!std::is_default_constructible <J>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <J>::value, "");
>> +#endif
>> +static_assert (std::is_destructible <J>::value, "");
>> +static_assert (std::is_trivially_destructible <J>::value, "");
>> +union K { G a; int b; };
>> +#if __cpp_trivial_union >= 202502L
>> +static_assert (std::is_default_constructible <K>::value, "");
>> +static_assert (std::is_trivially_default_constructible <K>::value, "");
>> +static_assert (std::is_destructible <K>::value, "");
>> +static_assert (std::is_trivially_destructible <K>::value, "");
>> +#else
>> +static_assert (!std::is_default_constructible <K>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <K>::value, "");
>> +static_assert (!std::is_destructible <K>::value, "");
>> +static_assert (!std::is_trivially_destructible <K>::value, "");
>> +#endif
>> +struct L { int a; union { G b; int c; }; };
>> +#if __cpp_trivial_union >= 202502L
>> +static_assert (std::is_default_constructible <L>::value, "");
>> +static_assert (std::is_trivially_default_constructible <L>::value, "");
>> +static_assert (std::is_destructible <L>::value, "");
>> +static_assert (std::is_trivially_destructible <L>::value, "");
>> +#else
>> +static_assert (!std::is_default_constructible <L>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <L>::value, "");
>> +static_assert (!std::is_destructible <L>::value, "");
>> +static_assert (!std::is_trivially_destructible <L>::value, "");
>> +#endif
>> +union M { M (); int a; int b; };
>> +static_assert (std::is_default_constructible <M>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <M>::value, "");
>> +static_assert (std::is_destructible <M>::value, "");
>> +static_assert (std::is_trivially_destructible <M>::value, "");
>> +union N { N (); int a; G b; };
>> +static_assert (!std::is_default_constructible <N>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <N>::value, "");
>> +static_assert (!std::is_destructible <N>::value, "");
>> +static_assert (!std::is_trivially_destructible <N>::value, "");
>> +struct O { O (); union { int a; int b; }; };
>> +static_assert (std::is_default_constructible <O>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <O>::value, "");
>> +static_assert (std::is_destructible <O>::value, "");
>> +static_assert (std::is_trivially_destructible <O>::value, "");
>> +struct P { P (); union { int a; G b; }; };
>> +static_assert (!std::is_default_constructible <P>::value, "");
>> +static_assert (!std::is_trivially_default_constructible <P>::value, "");
>> +static_assert (!std::is_destructible <P>::value, "");
>> +static_assert (!std::is_trivially_destructible <P>::value, "");
>>
> I would still like to see cases where the default constructor is not the
> one creating the union.
> Destructor deleted.
> struct R { R () = default; R(int); union { int a; G b; }; };
> static_assert (std::is_default_constructible <R>::value, "");
> static_assert (std::is_trivially_default_constructible <R>::value, "");
> static_assert (!std::is_destructible <R>::value, "");
> static_assert (!std::is_trivially_destructible <R>::value, "");
>
> struct Q { Q(int); union { int a; G b; }; };
> static_assert (!std::is_default_constructible <Q>::value, "");
> static_assert (!std::is_trivially_default_constructible <Q>::value, "");
> static_assert (!std::is_destructible <Q>::value, "");
> static_assert (!std::is_trivially_destructible <Q>::value, "");
>
> Have you considered using templates for this tests, to have something like
> this?
> I will find that easier to follow, but it does not seem to be used in the
> core tests,
> so feel free to ignore that suggestions. (Unions could also be tested this
> way).
>
> template<bool XTrivial, typename X>
> void test_union_like() {
>    struct A { union { int a; X b; }; };
>    static_assert (std::is_default_constructible <A>::value, "");
>    static_assert (std::is_trivially_default_constructible <A>::value, "");
>    static_assert (std::is_destructible <A>::value, "");
>    static_assert (std::is_trivially_destructible <A>::value, "");
>
>    struct B { union { int a; X b = 10; }; };
>    static_assert (std::is_default_constructible <B>::value, "");
>    static_assert (!std::is_trivially_default_constructible <B>::value, "");
>    static_assert (std::is_destructible <B>::value == XTrivial, "");
>    static_assert (std::is_trivially_destructible <B>::value == XTrivial,
> "");
>
> We could also have:
   struct F { union { int a = 10; X b; }; };
   static_assert (std::is_default_constructible <F>::value, "");
   static_assert (!std::is_trivially_default_constructible <F>::value, "");
   static_assert (std::is_destructible <F>::value, "");
   static_assert (std::is_trivially_destructible <F>::value, "");

Assignments to b were copy-pasted below; I removed them.

>    struct C { C(); union { int a; X b; }; };
>    static_assert (std::is_default_constructible <C>::value, "");
>    static_assert (!std::is_trivially_default_constructible <C>::value, "");
>    static_assert (std::is_destructible <C>::value == XTrivial, "");
>    static_assert (std::is_trivially_destructible <C>::value == XTrivial,
> "");
>
>    struct D { D() = default; D(int); union { int a; X b; }; };
>    static_assert (std::is_default_constructible <D>::value, "");
>    static_assert (std::is_trivially_default_constructible <D>::value, "");
>    static_assert (std::is_destructible <D>::value == XTrivial, "");
>    static_assert (std::is_trivially_destructible <D>::value == XTrivial,
> "");
>
>    // Defaullt constructor not present
>    struct E { E(int); union { int a; X b; }; };
>    static_assert (!std::is_default_constructible <E>::value, "");
>    static_assert (!std::is_trivially_default_constructible <E>::value, "");
>    static_assert (std::is_destructible <E>::value == XTrivial, "");
>    static_assert (std::is_trivially_destructible <E>::value == XTrivial,
> "");
> }
>
> struct NT { NT(int); ~NT(); };
>
> int main() {
>    test_union_like<true, int>;
>    test_union_like<true, NT>;
>
The second line should be: test_union_like<false, NT>

> }
>
>
>
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union2.C.jj      2026-05-20
>> 14:26:01.245359408 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union2.C 2026-05-20
>> 14:26:01.245359408 +0200
>> @@ -0,0 +1,8 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++20 } }
>> +
>> +union U { int a, b; };
>> +template<U u> class X {};
>> +constexpr U make() { U u; return u; }
>> +void f(X<make()>) {}
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union3.C.jj      2026-05-20
>> 14:26:01.245486713 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union3.C 2026-05-20
>> 14:26:01.245486713 +0200
>> @@ -0,0 +1,28 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++26 } }
>> +
>> +#include <memory>
>> +#include <string>
>> +
>> +template <typename T, size_t N>
>> +struct FixedVector {
>> +  union { T storage[N]; };
>> +  size_t size = 0;
>> +
>> +  constexpr FixedVector () { std::start_lifetime (storage); }
>> +
>> +  constexpr ~FixedVector() { std::destroy(storage, storage + size); }
>> +
>> +  constexpr void push_back(T const& v) { ::new (storage + size) T(v);
>> ++size; }
>> +};
>> +
>> +constexpr size_t
>> +silly_test ()
>> +{
>> +  FixedVector <std::string, 3> v;
>> +  v.push_back ("some sufficiently longer string");
>> +  return v.size;
>> +}
>> +
>> +static_assert (silly_test () == 1);
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union4.C.jj      2026-05-20
>> 14:26:01.245562152 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union4.C 2026-05-20
>> 14:26:01.245562152 +0200
>> @@ -0,0 +1,63 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++26 } }
>> +
>> +namespace std {
>> +  template <class T>
>> +  constexpr void
>> +  start_lifetime (T &r) noexcept
>> +  {
>> +    __builtin_start_lifetime (__builtin_addressof (r));
>> +  }
>> +}
>> +
>> +struct S { int a; };
>> +union U { int a; S b[3]; };
>> +union V { int a; U b[2]; };
>> +
>> +consteval
>> +{
>> +  S s;
>> +  s.a = 42;
>> +  std::start_lifetime (s);
>> +  if (s.a != 42)
>> +    throw 1;
>> +  U u;
>> +  u.b[0].a = 42;
>> +  std::start_lifetime (u.b);
>> +  std::start_lifetime (u.b[0]);
>> +  std::start_lifetime (u.b[2]);
>> +  u.a = 42;
>> +  std::start_lifetime (u.b);
>> +  std::start_lifetime (u.b[0]);
>> +  std::start_lifetime (u.b[1]);
>> +  V v;
>> +  v.a = 42;
>> +  std::start_lifetime (v.b);
>> +  std::start_lifetime (v.b[1]);
>> +  v.b[1].a = 42;
>> +  std::start_lifetime (v.b[1].b);
>> +  std::start_lifetime (v.b[1].b[1]);
>> +  v.b[1].b[1].a = 43;
>> +  std::start_lifetime (v.b);
>> +  std::start_lifetime (v.b[1].b[1]);
>> +  if (v.b[1].b[1].a != 43)
>> +    throw 2;
>> +  const S cs = { 42 };
>> +  std::start_lifetime (cs);
>> +  if (cs.a != 42)
>> +    throw 3;
>> +  const U cu = { .b = { { 41 }, { 42 }, { 43 } } };
>> +  std::start_lifetime (cu.b);
>> +  std::start_lifetime (cu.b[0]);
>> +  std::start_lifetime (cu.b[2]);
>> +  if (cu.b[2].a != 43)
>> +    throw 4;
>> +  const V cv = { .b = { { .b = { { 44 } } } } };
>> +  std::start_lifetime (cv.b);
>> +  std::start_lifetime (cv.b[0]);
>> +  std::start_lifetime (cv.b[0].b);
>> +  std::start_lifetime (cv.b[0].b[0]);
>> +  if (cv.b[0].b[0].a != 44)
>> +    throw 5;
>> +}
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union5.C.jj      2026-05-20
>> 14:26:01.245655416 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union5.C 2026-05-20
>> 14:26:01.245655416 +0200
>> @@ -0,0 +1,37 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++26 } }
>> +
>> +struct S { int a; };
>> +S a = { 5 };
>> +struct T { constexpr T () : a (42) {} int a; };
>> +struct R { int a; constexpr ~R () {} };
>> +union U { int a; S b[2]; };
>> +
>> +consteval { int a = 5; __builtin_start_lifetime (&a); }
>> // { dg-error "'__builtin_start_lifetime' argument type 'int\\\*' is not a
>> pointer to aggregate type" }
>> +consteval { __builtin_start_lifetime (&a); };                  // {
>> dg-error "modification of 'a' from outside current evaluation is not a
>> constant expression" }
>> +consteval { __builtin_start_lifetime (); };                    // {
>> dg-error "'__builtin_start_lifetime' needs a single argument" }
>> +consteval { S a = { 6 }; __builtin_start_lifetime (&a, &a); }; // {
>> dg-error "'__builtin_start_lifetime' needs a single argument" }
>> +consteval { __builtin_start_lifetime (42); };                  // {
>> dg-error "'__builtin_start_lifetime' argument type 'int' is not pointer
>> type" }
>> +consteval { T t; __builtin_start_lifetime (&t); }              // {
>> dg-error "'__builtin_start_lifetime' argument type 'T\\\*' is not a pointer
>> to aggregate type" }
>> +consteval { R r; __builtin_start_lifetime (&r); }              // {
>> dg-error "'__builtin_start_lifetime' argument type 'R\\\*' is not a pointer
>> to implicit-lifetime type" }
>> +consteval { const U u = { .a = 42 }; __builtin_start_lifetime (&u.a); }
>>       // { dg-error "'__builtin_start_lifetime' argument type 'const
>> int\\\*' is not a pointer to aggregate type" }
>> +consteval { const U u = { .a = 42 }; __builtin_start_lifetime (&u.b); }
>>       // { dg-error "modifying a const object 'u.U::b' is not allowed in a
>> constant expression" }
>> +
>> +void
>> +foo ()
>> +{
>> +  S s;
>> +  __builtin_start_lifetime (&s);
>> +  int a = 5;
>> +  __builtin_start_lifetime (&a);               // { dg-error
>> "'__builtin_start_lifetime' argument type 'int\\\*' is not a pointer to
>> aggregate type" }
>> +  __builtin_start_lifetime (&::a);
>> +  __builtin_start_lifetime ();                 // { dg-error
>> "'__builtin_start_lifetime' needs a single argument" }
>> +  S b = { 6 };
>> +  __builtin_start_lifetime (&b, &b);           // { dg-error
>> "'__builtin_start_lifetime' needs a single argument" }
>> +  __builtin_start_lifetime (42);               // { dg-error
>> "'__builtin_start_lifetime' argument type 'int' is not pointer type" }
>> +  T t;
>> +  __builtin_start_lifetime (&t);               // { dg-error
>> "'__builtin_start_lifetime' argument type 'T\\\*' is not a pointer to
>> aggregate type" }
>> +  R r;
>> +  __builtin_start_lifetime (&r);               // { dg-error
>> "'__builtin_start_lifetime' argument type 'R\\\*' is not a pointer to
>> implicit-lifetime type" }
>> +}
>> --- gcc/testsuite/g++.dg/cpp26/trivial-union6.C.jj      2026-05-20
>> 14:26:01.245756124 +0200
>> +++ gcc/testsuite/g++.dg/cpp26/trivial-union6.C 2026-05-20
>> 14:26:01.245756124 +0200
>> @@ -0,0 +1,26 @@
>> +// 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]; };
>> +
>> +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" "" { target c++23_down } }
>> +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" "" { target c++23_down } }
>> +constexpr D fD () { D a; a.a.b[0] = 1; return a; }
>> +constexpr D d = fD ();         // { dg-error "is not a constant
>> expression" "" { target c++23_down } }
>> +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" "" { target c++23_down } }
>> +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" }
>> --- gcc/testsuite/g++.dg/init/pr43719.C.jj      2026-04-29
>> 07:45:23.186351218 +0200
>> +++ gcc/testsuite/g++.dg/init/pr43719.C 2026-05-20 14:26:01.247279549
>> +0200
>> @@ -109,7 +109,7 @@ struct Z            // { dg-error "deleted" "" { t
>>    Z5 z5;
>>  };
>>
>> -union U // { dg-error "uninitialized" "" { target c++11 } }
>> +union U
>>  {
>>    int const i; // { dg-message "should be initialized" }
>>  };
>> --- gcc/testsuite/g++.dg/init/pr25811.C.jj      2026-04-29
>> 07:45:23.183351272 +0200
>> +++ gcc/testsuite/g++.dg/init/pr25811.C 2026-05-20 14:26:01.247438801
>> +0200
>> @@ -124,10 +124,9 @@ struct Z // { dg-error "deleted" "" { ta
>>    Z5 z5;
>>  };
>>
>> -union U // { dg-message "implicitly deleted" "" { target c++11 } }
>> -       // { dg-error "uninitialized" "" { target c++11 } .-1 }
>> +union U
>>  {
>> -  int const i; // { dg-message "should be initialized" }
>> +  int const i;
>>  };
>>
>>  void f1 ()
>> @@ -207,5 +206,5 @@ void f15 ()
>>
>>  void f16 ()
>>  {
>> -  new U; // { dg-error "deleted|uninitialized const member" }
>> +  new U; // { dg-error "uninitialized const member in 'union U' using
>> 'new' without new-initializer" "" { target c++98_only } }
>>  }
>> --- gcc/testsuite/g++.dg/other/anon-union2.C.jj 2026-03-27
>> 10:17:16.040299637 +0100
>> +++ gcc/testsuite/g++.dg/other/anon-union2.C    2026-05-20
>> 14:26:01.247698101 +0200
>> @@ -6,5 +6,5 @@ struct S {
>>  };
>>
>>  void f() {
>> -  union { S a; };              // { dg-error "constructor|no match" }
>> +  union { S a; };              // { dg-error "constructor|no match" "" {
>> target c++23_down } }
>>  }
>> --- gcc/testsuite/g++.dg/reflect/trivial-union1.C.jj    2026-05-20
>> 14:26:01.245919804 +0200
>> +++ gcc/testsuite/g++.dg/reflect/trivial-union1.C       2026-05-20
>> 14:26:01.245919804 +0200
>> @@ -0,0 +1,108 @@
>> +// P3074R7 - trivial unions (was std::uninitialized<T>)
>> +// P3726R2 - Adjustments to Union Lifetime Rules
>> +// { dg-do compile { target c++26 } }
>> +// { dg-additional-options "-freflection" }
>> +
>> +#include <meta>
>> +#include <ranges>
>> +
>> +using namespace std::meta;
>> +constexpr auto ctx = std::meta::access_context::unchecked ();
>> +union A { int a; const int b; };
>> +static_assert (is_default_constructible_type (^^A));
>> +static_assert (is_trivially_default_constructible_type (^^A));
>> +static_assert (is_destructible_type (^^A));
>> +static_assert (is_trivially_destructible_type (^^A));
>> +constexpr auto Actor = (members_of (^^A, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Adtor = (members_of (^^A, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Actor) && !is_deleted (Actor));
>> +static_assert (is_defaulted (Adtor) && !is_deleted (Adtor));
>> +struct B { int a; union { int b; const int c; }; };
>> +static_assert (is_default_constructible_type (^^B));
>> +static_assert (is_trivially_default_constructible_type (^^B));
>> +static_assert (is_destructible_type (^^B));
>> +static_assert (is_trivially_destructible_type (^^B));
>> +constexpr auto Bctor = (members_of (^^B, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Bdtor = (members_of (^^B, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Bctor) && !is_deleted (Bctor));
>> +static_assert (is_defaulted (Bdtor) && !is_deleted (Bdtor));
>> +union C { const int a = 42; const long b; ~C (); };
>> +static_assert (is_default_constructible_type (^^C));
>> +static_assert (!is_trivially_default_constructible_type (^^C));
>> +static_assert (is_destructible_type (^^C));
>> +static_assert (!is_trivially_destructible_type (^^C));
>> +constexpr auto Cctor = (members_of (^^C, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Cdtor = (members_of (^^C, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Cctor) && !is_deleted (Cctor));
>> +static_assert (!is_defaulted (Cdtor) && !is_deleted (Cdtor));
>> +struct D { D () = delete; D (int); ~D () = default; };
>> +union E { D a = 42; D b; ~E (); };
>> +static_assert (is_default_constructible_type (^^E));
>> +static_assert (is_destructible_type (^^E));
>> +constexpr auto Ector = (members_of (^^E, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Edtor = (members_of (^^E, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Ector) && !is_deleted (Ector));
>> +static_assert (!is_defaulted (Edtor) && !is_deleted (Edtor));
>> +struct F { int a; union { D b = 42; D c; }; };
>> +static_assert (is_default_constructible_type (^^F));
>> +static_assert (is_destructible_type (^^F));
>> +constexpr auto Fctor = (members_of (^^F, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Fdtor = (members_of (^^F, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Fctor) && !is_deleted (Fctor));
>> +static_assert (is_defaulted (Fdtor) && !is_deleted (Fdtor));
>> +struct G { G (); ~G (); };
>> +union I { int a; const int b; ~I (); };
>> +static_assert (is_default_constructible_type (^^I));
>> +static_assert (!is_trivially_default_constructible_type (^^I));
>> +static_assert (is_destructible_type (^^I));
>> +static_assert (!is_trivially_destructible_type (^^I));
>> +constexpr auto Ictor = (members_of (^^I, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Idtor = (members_of (^^I, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Ictor) && !is_deleted (Ictor));
>> +static_assert (!is_defaulted (Idtor) && !is_deleted (Idtor));
>> +union J { D a; int b; };
>> +static_assert (is_default_constructible_type (^^J));
>> +static_assert (is_trivially_default_constructible_type (^^J));
>> +static_assert (is_destructible_type (^^J));
>> +static_assert (is_trivially_destructible_type (^^J));
>> +constexpr auto Jctor = (members_of (^^J, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Jdtor = (members_of (^^J, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Jctor) && !is_deleted (Jctor));
>> +static_assert (is_defaulted (Jdtor) && !is_deleted (Jdtor));
>> +union K { G a; int b; };
>> +static_assert (is_default_constructible_type (^^K));
>> +static_assert (is_trivially_default_constructible_type (^^K));
>> +static_assert (is_destructible_type (^^K));
>> +static_assert (is_trivially_destructible_type (^^K));
>> +constexpr auto Kctor = (members_of (^^K, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Kdtor = (members_of (^^K, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Kctor) && !is_deleted (Kctor));
>> +static_assert (is_defaulted (Kdtor) && !is_deleted (Kdtor));
>> +struct L { int a; union { G b; int c; }; };
>> +static_assert (is_default_constructible_type (^^L));
>> +static_assert (is_trivially_default_constructible_type (^^L));
>> +static_assert (is_destructible_type (^^L));
>> +static_assert (is_trivially_destructible_type (^^L));
>> +constexpr auto Lctor = (members_of (^^L, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Ldtor = (members_of (^^L, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (is_defaulted (Lctor) && !is_deleted (Lctor));
>> +static_assert (is_defaulted (Ldtor) && !is_deleted (Ldtor));
>> +union M { M (); int a; long b; };
>> +static_assert (is_default_constructible_type (^^M));
>> +static_assert (!is_trivially_default_constructible_type (^^M));
>> +static_assert (is_destructible_type (^^M));
>> +static_assert (is_trivially_destructible_type (^^M));
>> +constexpr auto Mctor = (members_of (^^M, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Mdtor = (members_of (^^M, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (!is_defaulted (Mctor) && !is_deleted (Mctor));
>> +static_assert (is_defaulted (Mdtor) && !is_deleted (Mdtor));
>> +struct N { N () = default; N (const N &) = default; int a; ~N (); };
>> +union O { O (); int a; N b; };
>> +static_assert (!is_default_constructible_type (^^O));
>> +static_assert (!is_trivially_default_constructible_type (^^O));
>> +static_assert (!is_destructible_type (^^O));
>> +static_assert (!is_trivially_destructible_type (^^O));
>> +constexpr auto Octor = (members_of (^^O, ctx) | std::views::filter
>> (is_default_constructor) | std::ranges::to <std::vector> ())[0];
>> +constexpr auto Odtor = (members_of (^^O, ctx) | std::views::filter
>> (is_destructor) | std::ranges::to <std::vector> ())[0];
>> +static_assert (!is_defaulted (Octor) && !is_deleted (Octor));
>> +static_assert (is_defaulted (Odtor) && is_deleted (Odtor));
>> --- gcc/testsuite/g++.dg/reflect/type_trait6.C.jj       2026-05-20
>> 08:43:02.581478043 +0200
>> +++ gcc/testsuite/g++.dg/reflect/type_trait6.C  2026-05-20
>> 14:26:01.246323664 +0200
>> @@ -985,7 +985,7 @@ static_assert (!is_destructible_type (^^
>>  static_assert (!is_destructible_type (^^const N2::Del [1]));
>>  static_assert (!is_destructible_type (^^N2::Del []));
>>  static_assert (!is_destructible_type (^^const N2::Del []));
>> -static_assert (!is_destructible_type (^^N2::NontrivialUnion));
>> +static_assert (is_destructible_type (^^N2::NontrivialUnion));
>>  static_assert (is_destructible_type (^^N2::UnusualCopy));
>>
>>  static_assert (is_trivially_default_constructible_type (^^int));
>> @@ -1367,8 +1367,8 @@ static_assert (!is_nothrow_destructible_
>>  static_assert (!is_nothrow_destructible_type (^^N2::Aggr2));
>>  static_assert (!is_nothrow_destructible_type (^^N2::Aggr2 [1]));
>>  static_assert (!is_nothrow_destructible_type (^^N2::TD1 [1][2]));
>> -static_assert (!is_nothrow_destructible_type (^^N2::Ut));
>> -static_assert (!is_nothrow_destructible_type (^^N2::Ut [3]));
>> +static_assert (is_nothrow_destructible_type (^^N2::Ut));
>> +static_assert (is_nothrow_destructible_type (^^N2::Ut [3]));
>>  static_assert (!is_nothrow_destructible_type (^^N2::AbstractDelDtor));
>>  static_assert (!is_nothrow_destructible_type (^^N2::Abstract2));
>>  static_assert (!is_nothrow_destructible_type (^^N2::Abstract3));
>> --- gcc/testsuite/g++.dg/reflect/is_constructible_type1.C.jj
>> 2026-05-20 08:43:02.580478060 +0200
>> +++ gcc/testsuite/g++.dg/reflect/is_constructible_type1.C
>>  2026-05-20 14:26:01.246691288 +0200
>> @@ -603,7 +603,7 @@ static_assert (!is_constructible_type (^
>>  static_assert (!is_constructible_type (^^const DelnAny, { ^^int, ^^void
>> * }));
>>  static_assert (!is_constructible_type (^^DelnAny, { ^^Empty, ^^B, ^^D
>> }));
>>  static_assert (!is_constructible_type (^^const DelnAny, { ^^Empty, ^^B,
>> ^^D }));
>> -static_assert (!is_constructible_type (^^NontrivialUnion, {}));
>> +static_assert (is_constructible_type (^^NontrivialUnion, {}));
>>  static_assert (!is_constructible_type (^^NontrivialUnion, { ^^const
>> NontrivialUnion & }));
>>  static_assert (!is_constructible_type (^^UnusualCopy, {}));
>>  static_assert (!is_constructible_type (^^UnusualCopy, { ^^UnusualCopy
>> }));
>> --- libstdc++-v3/include/bits/version.def.jj    2026-05-20
>> 08:43:02.584477993 +0200
>> +++ libstdc++-v3/include/bits/version.def       2026-05-20
>> 14:26:01.249947842 +0200
>> @@ -2410,6 +2410,15 @@ ftms = {
>>    };
>>  };
>>
>> +ftms = {
>> +  name = start_lifetime;
>> +  values = {
>> +    v = 202603;
>> +    cxxmin = 26;
>> +    extra_cond = "__has_builtin(__builtin_start_lifetime)";
>> +  };
>> +};
>> +
>>  // Standard test specifications.
>>  stds[97] = ">= 199711L";
>>  stds[03] = ">= 199711L";
>> --- libstdc++-v3/include/bits/version.h.jj      2026-05-20
>> 08:43:02.584477993 +0200
>> +++ libstdc++-v3/include/bits/version.h 2026-05-20 14:26:01.250438751
>> +0200
>> @@ -2675,4 +2675,14 @@
>>  #endif /* !defined(__cpp_lib_is_structural) */
>>  #undef __glibcxx_want_is_structural
>>
>> +#if !defined(__cpp_lib_start_lifetime)
>> +# if (__cplusplus >  202302L) &&
>> (__has_builtin(__builtin_start_lifetime))
>> +#  define __glibcxx_start_lifetime 202603L
>> +#  if defined(__glibcxx_want_all) ||
>> defined(__glibcxx_want_start_lifetime)
>> +#   define __cpp_lib_start_lifetime 202603L
>> +#  endif
>> +# endif
>> +#endif /* !defined(__cpp_lib_start_lifetime) */
>> +#undef __glibcxx_want_start_lifetime
>> +
>>  #undef __glibcxx_want_all
>> --- libstdc++-v3/include/bits/stl_construct.h.jj        2026-03-27
>> 10:17:22.883187971 +0100
>> +++ libstdc++-v3/include/bits/stl_construct.h   2026-05-20
>> 14:30:52.025619611 +0200
>> @@ -404,6 +404,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>      }
>>  #endif // C++23
>>
>> +#if __glibcxx_start_lifetime >= 202603L // C++ >= 26
>> +  template <typename _Tp>
>> +    constexpr void
>> +    start_lifetime(_Tp& __r) noexcept
>> +    {
>> +#ifdef __cpp_lib_is_implicit_lifetime
>> +      static_assert(std::is_implicit_lifetime_v<_Tp>);
>> +#endif
>> +#ifdef __cpp_lib_is_aggregate
>> +      static_assert(std::is_aggregate_v<_Tp>);
>> +#endif
>> +      __builtin_start_lifetime(__builtin_addressof(__r));
>> +    }
>> +#endif // C++26
>> +
>>  _GLIBCXX_END_NAMESPACE_VERSION
>>  } // namespace std
>>
>> --- libstdc++-v3/include/std/memory.jj  2026-05-20 08:43:02.586477959
>> +0200
>> +++ libstdc++-v3/include/std/memory     2026-05-20 14:28:05.835373954
>> +0200
>> @@ -126,6 +126,7 @@
>>  #define __glibcxx_want_transparent_operators
>>  #define __glibcxx_want_smart_ptr_owner_equality
>>  #define __glibcxx_want_allocate_at_least
>> +#define __glibcxx_want_start_lifetime
>>  #include <bits/version.h>
>>
>>  #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
>> --- libstdc++-v3/src/c++23/std.cc.in.jj 2026-05-20 08:43:02.591477875
>> +0200
>> +++ libstdc++-v3/src/c++23/std.cc.in    2026-05-20 14:26:01.251438735
>> +0200
>> @@ -2062,6 +2062,9 @@ export namespace std
>>  #ifdef __glibcxx_allocate_at_least
>>    using std::allocation_result;
>>  #endif
>> +#if __cpp_lib_start_lifetime
>> +  using std::start_lifetime;
>> +#endif
>>  }
>>
>>  // 20.4 <memory_resource>
>>
>>
>>         Jakub
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260521/9fe829b3/attachment-0001.htm>


More information about the Libstdc++ mailing list