<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, May 21, 2026 at 9:50 AM Jakub Jelinek <<a href="mailto:jakub@redhat.com">jakub@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi!<br>
<br>
Given the ongoing discussions in core on the start_lifetime/union elemental<br>
subobject discussions, the following patch extracts just the P3074R7<br>
minus the sentence removed again in P3726R2 and CWG3189 part of the patch,<br>
leaving P3726R2 plus possible CWG and/or LWG issues related to it for<br>
an incremental patch.<br>
I've extended the testsuite coverage as well (both trivial-union1.C tests).<br></blockquote><div>The test coverage looks good to me now. Using reflection to site-step the</div><div>the fact that it's trivially constructible and you can look at the destructor <br>is a really nice idea, that I haven't thought of before. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?<br>
<br>
2026-05-21  Jakub Jelinek  <<a href="mailto:jakub@redhat.com" target="_blank">jakub@redhat.com</a>><br>
<br>
gcc/c-family/<br>
        * c-cppbuiltin.cc (c_cpp_builtins): For C++26 predefine<br>
        __cpp_trivial_union to 202502L.<br>
gcc/cp/<br>
        * method.cc: Implement C++26 P3074R7 - trivial unions (was<br>
        std::uninitialized<T>) (except the sentence removed again in P3726R2)<br>
        and proposed resolution of CWG3189 - Implicitly deleted destructors<br>
        for union-like classes.<br>
        (walk_field_subobs): Don't do default_init_uninitialized_part checks<br>
        for variant members.  Don't check subobject ctor/dtor for variant<br>
        members for ctor/inheriting ctor or when subobject doesn't have member<br>
        initializer for dtor and it is either the dtor_from_ctor case or<br>
        the current class doesn't have user provided ctors.<br>
        * class.cc (check_field_decl): Don't or in<br>
        TYPE_HAS_NONTRIVIAL_DESTRUCTOR or TYPE_HAS_DEFAULT_CONSTRUCTOR of<br>
        variant subobjects for C++26.<br>
gcc/testsuite/<br>
        * g++.dg/DRs/dr2581-1.C: Expect warning for __cpp_trivial_union.<br>
        * g++.dg/DRs/dr2581-2.C: Expect error for __cpp_trivial_union.<br>
        * g++.dg/cpp26/feat-cxx26.C: Add __cpp_trivial_union checking.<br>
        * g++.dg/cpp26/trivial-union1.C: New test.<br>
        * g++.dg/cpp26/trivial-union2.C: New test.<br>
        * g++.dg/reflect/trivial-union1.C: New test.<br>
        * g++.dg/reflect/type_trait6.C: Adjust expected result of<br>
        one is_destructible_type and two is_nothrow_destructible_type calls.<br>
        * g++.dg/reflect/is_constructible_type1.C: Adjust expected result<br>
        of one is_constructible_type call.<br>
        * g++.dg/init/pr43719.C: Don't expect one error.<br>
        * g++.dg/init/pr25811.C: Don't expect 3 diagnostic messages,<br>
        instead expect a different one for C++98 only.<br>
        * g++.dg/other/anon-union2.C: Only expect one diagnostic for<br>
        C++23 and older.<br>
        * g++.dg/cpp0x/union1.C: Only expect 6 diagnostic messages for<br>
        C++23 and older.<br>
        * g++.dg/cpp0x/union4.C: Only expect 3 diagnostic messages for<br>
        C++23 and older.<br>
        * g++.dg/cpp0x/defaulted2.C: Only expect 2 diagnostic messages for<br>
        C++23 and older.<br>
<br>
--- gcc/c-family/c-cppbuiltin.cc.jj     2026-05-20 08:43:02.545478650 +0200<br>
+++ gcc/c-family/c-cppbuiltin.cc        2026-05-20 14:26:01.233439033 +0200<br>
@@ -1122,6 +1122,7 @@ c_cpp_builtins (cpp_reader *pfile)<br>
            cpp_define (pfile, "__cpp_impl_reflection=202603L");<br>
          else<br>
            cpp_warn (pfile, "__cpp_impl_reflection");<br>
+         cpp_define (pfile, "__cpp_trivial_union=202502L");<br>
        }<br>
       if (flag_concepts && cxx_dialect > cxx14)<br>
        cpp_define (pfile, "__cpp_concepts=202002L");<br>
--- gcc/cp/method.cc.jj 2026-05-20 08:43:02.566478296 +0200<br>
+++ gcc/cp/method.cc    2026-05-20 14:26:01.234439016 +0200<br>
@@ -2692,6 +2692,7 @@ walk_field_subobs (tree fields, special_<br>
   enum { unknown, no, yes }<br>
   only_dmi_mem = (sfk == sfk_constructor && TREE_CODE (ctx) == UNION_TYPE<br>
                  ? unknown : no);<br>
+  int has_user_provided_ctor = -1;<br>
<br>
  again:<br>
   for (tree field = fields; field; field = DECL_CHAIN (field))<br>
@@ -2771,6 +2772,7 @@ walk_field_subobs (tree fields, special_<br>
<br>
          bad = false;<br>
          if (CP_TYPE_CONST_P (mem_type)<br>
+             && TREE_CODE (ctx) != UNION_TYPE<br>
              && default_init_uninitialized_part (mem_type))<br>
            {<br>
              if (diag)<br>
@@ -2847,6 +2849,22 @@ walk_field_subobs (tree fields, special_<br>
       else<br>
        argtype = NULL_TREE;<br>
<br>
+      if (cxx_dialect >= cxx26 && TREE_CODE (ctx) == UNION_TYPE)<br>
+       {<br>
+         if (sfk == sfk_constructor || sfk == sfk_inheriting_constructor)<br>
+           continue;<br>
+<br>
+         if (sfk == sfk_destructor)<br>
+           {<br>
+             if (!dtor_from_ctor && has_user_provided_ctor == -1)<br>
+               has_user_provided_ctor<br>
+                 = type_has_user_provided_constructor (current_class_type);<br>
+             if (DECL_INITIAL (field) == NULL_TREE<br>
+                 && (dtor_from_ctor || !has_user_provided_ctor))<br>
+               continue;<br>
+           }<br>
+       }<br>
+<br>
       rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);<br>
<br>
       process_subob_fn (rval, sfk, spec_p, trivial_p, deleted_p,<br>
--- gcc/cp/class.cc.jj  2026-05-20 08:43:02.551478549 +0200<br>
+++ gcc/cp/class.cc     2026-05-20 14:26:01.235439000 +0200<br>
@@ -3903,17 +3903,25 @@ check_field_decl (tree field,<br>
       else<br>
        {<br>
          TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);<br>
-         TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)<br>
-           |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);<br>
          TYPE_HAS_COMPLEX_COPY_ASSIGN (t)<br>
            |= (TYPE_HAS_COMPLEX_COPY_ASSIGN (type)<br>
                || !TYPE_HAS_COPY_ASSIGN (type));<br>
          TYPE_HAS_COMPLEX_COPY_CTOR (t) |= (TYPE_HAS_COMPLEX_COPY_CTOR (type)<br>
                                             || !TYPE_HAS_COPY_CTOR (type));<br>
-         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);<br>
+         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)<br>
+           |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);<br>
          TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (type);<br>
-         TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)<br>
-                                       || TYPE_HAS_COMPLEX_DFLT (type));<br>
+         /* In C++26, triviality of default ctor or dtor of a variant member<br>
+            doesn't matter for triviality of the t's default ctor or dtor.  */<br>
+         if (cxx_dialect < cxx26<br>
+             || TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)<br>
+           {<br>
+             TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)<br>
+               |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);<br>
+             TYPE_HAS_COMPLEX_DFLT (t)<br>
+               |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)<br>
+                   || TYPE_HAS_COMPLEX_DFLT (type));<br>
+           }<br>
        }<br>
<br>
       if (TYPE_HAS_COPY_CTOR (type)<br>
--- gcc/testsuite/g++.dg/DRs/dr2581-1.C.jj      2026-05-20 08:43:02.577478111 +0200<br>
+++ gcc/testsuite/g++.dg/DRs/dr2581-1.C 2026-05-20 14:26:01.244438851 +0200<br>
@@ -94,7 +94,7 @@<br>
 #undef __cpp_template_parameters<br>
 #undef __cpp_template_template_args    // { dg-warning "undefining '__cpp_template_template_args'" "" { target c++20 } }<br>
 #undef __cpp_threadsafe_static_init    // { dg-warning "undefining '__cpp_threadsafe_static_init'" "" { target c++20 } }<br>
-#undef __cpp_trivial_union<br>
+#undef __cpp_trivial_union             // { dg-warning "undefining '__cpp_trivial_union'" "" { target c++26 } }<br>
 #undef __cpp_unicode_characters                // { dg-warning "undefining '__cpp_unicode_characters'" "" { target c++20 } }<br>
 #undef __cpp_unicode_literals          // { dg-warning "undefining '__cpp_unicode_literals'" "" { target c++20 } }<br>
 #undef __cpp_user_defined_literals     // { dg-warning "undefining '__cpp_user_defined_literals'" "" { target c++20 } }<br>
--- gcc/testsuite/g++.dg/DRs/dr2581-2.C.jj      2026-05-20 08:43:02.577478111 +0200<br>
+++ gcc/testsuite/g++.dg/DRs/dr2581-2.C 2026-05-20 14:26:01.244751680 +0200<br>
@@ -95,7 +95,7 @@<br>
 #define __cpp_template_parameters 202502L<br>
 #define __cpp_template_template_args 201611L   // { dg-error "'__cpp_template_template_args' redefined" "" { target c++20 } }<br>
 #define __cpp_threadsafe_static_init 200806L   // { dg-error "'__cpp_threadsafe_static_init' redefined" "" { target c++20 } }<br>
-#define __cpp_trivial_union 202502L<br>
+#define __cpp_trivial_union 202502L            // { dg-error "'__cpp_trivial_union' redefined" "" { target c++26 } }<br>
 #define __cpp_unicode_characters 200704L       // { dg-error "'__cpp_unicode_characters' redefined" "" { target c++17 } }<br>
 #define __cpp_unicode_literals 200710L         // { dg-error "'__cpp_unicode_literals' redefined" "" { target c++20 } }<br>
 #define __cpp_user_defined_literals 200809L    // { dg-error "'__cpp_user_defined_literals' redefined" "" { target c++20 } }<br>
--- gcc/testsuite/g++.dg/cpp0x/union1.C.jj      2026-03-27 10:17:15.542307763 +0100<br>
+++ gcc/testsuite/g++.dg/cpp0x/union1.C 2026-05-20 14:26:01.248075538 +0200<br>
@@ -14,7 +14,7 @@ union B<br>
   A a;                         // { dg-error "union member" }<br>
 };<br>
<br>
-B b;                           // { dg-error "B::B\\(\\)" "B::B" }<br>
+B b;                           // { dg-error "B::B\\(\\)" "B::B" { target c++23_down } }<br>
 B b2(b);                       // { dg-error "B::B\\(const B&\\)" "B::B" }<br>
<br>
 struct C<br>
@@ -25,10 +25,10 @@ struct C<br>
   };<br>
 };<br>
<br>
-C c;                           // { dg-error "C::C\\(\\)" "C::C" }<br>
+C c;                           // { dg-error "C::C\\(\\)" "C::C" { target c++23_down } }<br>
 C c2(c);                       // { dg-error "C::C\\(const C&\\)" "C::C" }<br>
<br>
-// { dg-error "B::~B" "B::~B" { target *-*-* } 17 }<br>
-// { dg-error "B::~B" "B::~B" { target *-*-* } 18 }<br>
-// { dg-error "C::~C" "C::~C" { target *-*-* } 28 }<br>
-// { dg-error "C::~C" "C::~C" { target *-*-* } 29 }<br>
+// { dg-error "B::~B" "B::~B" { target c++23_down } 17 }<br>
+// { dg-error "B::~B" "B::~B" { target c++23_down } 18 }<br>
+// { dg-error "C::~C" "C::~C" { target c++23_down } 28 }<br>
+// { dg-error "C::~C" "C::~C" { target c++23_down } 29 }<br>
--- gcc/testsuite/g++.dg/cpp0x/union4.C.jj      2026-03-27 10:17:15.542307763 +0100<br>
+++ gcc/testsuite/g++.dg/cpp0x/union4.C 2026-05-20 14:26:01.248438784 +0200<br>
@@ -3,15 +3,15 @@<br>
<br>
 struct SFoo<br>
 {<br>
-  SFoo() =delete;              // { dg-message "declared" }<br>
+  SFoo() =delete;              // { dg-message "declared" "" { target c++23_down } }<br>
 };<br>
<br>
-union UFoo                     // { dg-error "deleted" }<br>
+union UFoo                     // { dg-error "deleted" "" { target c++23_down } }<br>
 {<br>
   SFoo foo;<br>
 };<br>
<br>
 int main()<br>
 {<br>
-  UFoo();                      // { dg-error "deleted" }<br>
+  UFoo();                      // { dg-error "deleted" "" { target c++23_down } }<br>
 }<br>
--- gcc/testsuite/g++.dg/cpp0x/defaulted2.C.jj  2026-03-27 10:17:15.446309330 +0100<br>
+++ gcc/testsuite/g++.dg/cpp0x/defaulted2.C     2026-05-20 14:26:01.248646182 +0200<br>
@@ -55,7 +55,7 @@ G::G() = default;<br>
<br>
 union U<br>
 {<br>
-  G g;                         // { dg-error "union member.*non-trivial" }<br>
+  G g;                         // { dg-error "union member.*non-trivial" "" { target c++23_down } }<br>
 };<br>
<br>
 int main()<br>
@@ -63,7 +63,7 @@ int main()<br>
   F f;<br>
   F f2(f);                     // { dg-error "use" }<br>
   const B* b = new const B;            // { dg-error "uninitialized const" }<br>
-  U u;                         // { dg-error "deleted" }<br>
+  U u;                         // { dg-error "deleted" "" { target c++23_down } }<br>
 }<br>
<br>
 // { dg-prune-output "implicitly deleted because" }<br>
--- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj  2026-05-20 08:43:02.579478077 +0200<br>
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C     2026-05-20 14:26:01.245053195 +0200<br>
@@ -652,3 +652,9 @@<br>
 #elif __cpp_expansion_statements != 202506<br>
 #  error "__cpp_expansion_statements != 202506"<br>
 #endif<br>
+<br>
+#ifndef __cpp_trivial_union<br>
+#  error "__cpp_trivial_union"<br>
+#elif __cpp_trivial_union != 202502<br>
+#  error "__cpp_trivial_union != 202502"<br>
+#endif<br>
--- gcc/testsuite/g++.dg/cpp26/trivial-union1.C.jj      2026-05-20 22:41:11.373261717 +0200<br>
+++ gcc/testsuite/g++.dg/cpp26/trivial-union1.C 2026-05-21 09:07:54.724321137 +0200<br>
@@ -0,0 +1,133 @@<br>
+// P3074R7 - trivial unions (was std::uninitialized<T>)<br>
+// { dg-do compile { target c++11 } }<br>
+<br>
+#include <type_traits><br>
+<br>
+// These two were incorrectly deleted.<br>
+union A { int a; const int b; };<br>
+static_assert (std::is_default_constructible <A>::value, "");<br>
+static_assert (std::is_trivially_default_constructible <A>::value, "");<br>
+static_assert (std::is_destructible <A>::value, "");<br>
+static_assert (std::is_trivially_destructible <A>::value, "");<br>
+struct B { int a; union { int b; const int c; }; };<br>
+static_assert (std::is_default_constructible <B>::value, "");<br>
+static_assert (std::is_trivially_default_constructible <B>::value, "");<br>
+static_assert (std::is_destructible <B>::value, "");<br>
+static_assert (std::is_trivially_destructible <B>::value, "");<br>
+// C::C() is incorrectly not deleted in C++11 to 23, but in C++26 it should<br>
+// not be deleted.<br>
+union C { const int a = 42; const long b; ~C (); };<br>
+#if __cpp_trivial_union >= 202502L<br>
+static_assert (std::is_default_constructible <C>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <C>::value, "");<br>
+static_assert (std::is_destructible <C>::value, "");<br>
+static_assert (!std::is_trivially_destructible <C>::value, "");<br>
+#endif<br>
+struct D { D () = delete; D (int); ~D () = default; };<br>
+union E { D a = 42; D b; ~E (); };<br>
+static_assert (std::is_default_constructible <E>::value, "");<br>
+static_assert (std::is_destructible <E>::value, "");<br>
+struct F { int a; union { D b = 42; D c; }; };<br>
+static_assert (std::is_default_constructible <F>::value, "");<br>
+static_assert (std::is_destructible <F>::value, "");<br>
+struct G { G (); ~G (); };<br>
+union I { int a; const int b; ~I (); };<br>
+static_assert (std::is_default_constructible <I>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <I>::value, "");<br>
+static_assert (std::is_destructible <I>::value, "");<br>
+static_assert (!std::is_trivially_destructible <I>::value, "");<br>
+union J { D a; int b; };<br>
+#if __cpp_trivial_union >= 202502L<br>
+static_assert (std::is_default_constructible <J>::value, "");<br>
+static_assert (std::is_trivially_default_constructible <J>::value, "");<br>
+#else<br>
+static_assert (!std::is_default_constructible <J>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <J>::value, "");<br>
+#endif<br>
+static_assert (std::is_destructible <J>::value, "");<br>
+static_assert (std::is_trivially_destructible <J>::value, "");<br>
+union K { G a; int b; };<br>
+#if __cpp_trivial_union >= 202502L<br>
+static_assert (std::is_default_constructible <K>::value, "");<br>
+static_assert (std::is_trivially_default_constructible <K>::value, "");<br>
+static_assert (std::is_destructible <K>::value, "");<br>
+static_assert (std::is_trivially_destructible <K>::value, "");<br>
+#else<br>
+static_assert (!std::is_default_constructible <K>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <K>::value, "");<br>
+static_assert (!std::is_destructible <K>::value, "");<br>
+static_assert (!std::is_trivially_destructible <K>::value, "");<br>
+#endif<br>
+struct L { int a; union { G b; int c; }; };<br>
+#if __cpp_trivial_union >= 202502L<br>
+static_assert (std::is_default_constructible <L>::value, "");<br>
+static_assert (std::is_trivially_default_constructible <L>::value, "");<br>
+static_assert (std::is_destructible <L>::value, "");<br>
+static_assert (std::is_trivially_destructible <L>::value, "");<br>
+#else<br>
+static_assert (!std::is_default_constructible <L>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <L>::value, "");<br>
+static_assert (!std::is_destructible <L>::value, "");<br>
+static_assert (!std::is_trivially_destructible <L>::value, "");<br>
+#endif<br>
+union M { M (); int a; int b; };<br>
+static_assert (std::is_default_constructible <M>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <M>::value, "");<br>
+static_assert (std::is_destructible <M>::value, "");<br>
+static_assert (std::is_trivially_destructible <M>::value, "");<br>
+union N { N (); int a; G b; };<br>
+static_assert (!std::is_default_constructible <N>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <N>::value, "");<br>
+static_assert (!std::is_destructible <N>::value, "");<br>
+static_assert (!std::is_trivially_destructible <N>::value, "");<br>
+struct O { O (); union { int a; int b; }; };<br>
+static_assert (std::is_default_constructible <O>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <O>::value, "");<br>
+static_assert (std::is_destructible <O>::value, "");<br>
+static_assert (std::is_trivially_destructible <O>::value, "");<br>
+struct P { P (); union { int a; G b; }; };<br>
+static_assert (!std::is_default_constructible <P>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <P>::value, "");<br>
+static_assert (!std::is_destructible <P>::value, "");<br>
+static_assert (!std::is_trivially_destructible <P>::value, "");<br>
+struct Q { Q (int); union { int a; G b; }; };<br>
+static_assert (!std::is_default_constructible <Q>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <Q>::value, "");<br>
+static_assert (!std::is_destructible <Q>::value, "");<br>
+static_assert (!std::is_trivially_destructible <Q>::value, "");<br>
+struct R { R () = default; R (int); union { int a; G b; }; };<br>
+static_assert (!std::is_default_constructible <R>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <R>::value, "");<br>
+static_assert (!std::is_destructible <R>::value, "");<br>
+static_assert (!std::is_trivially_destructible <R>::value, "");<br>
+struct S { S (int); ~S (); };<br>
+union T { T (); int a; int b = 42; };<br>
+static_assert (std::is_default_constructible <T>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <T>::value, "");<br>
+static_assert (std::is_destructible <T>::value, "");<br>
+static_assert (std::is_trivially_destructible <T>::value, "");<br>
+union U { U (); int a; S b = 42; };<br>
+static_assert (!std::is_default_constructible <U>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <U>::value, "");<br>
+static_assert (!std::is_destructible <U>::value, "");<br>
+static_assert (!std::is_trivially_destructible <U>::value, "");<br>
+struct V { V (); union { int a; int b = 42; }; };<br>
+static_assert (std::is_default_constructible <V>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <V>::value, "");<br>
+static_assert (std::is_destructible <V>::value, "");<br>
+static_assert (std::is_trivially_destructible <V>::value, "");<br>
+struct W { W (); union { int a; S b = 42; }; };<br>
+static_assert (!std::is_default_constructible <W>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <W>::value, "");<br>
+static_assert (!std::is_destructible <W>::value, "");<br>
+static_assert (!std::is_trivially_destructible <W>::value, "");<br>
+struct X { X (int); union { int a; S b = 42; }; };<br>
+static_assert (!std::is_default_constructible <X>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <X>::value, "");<br>
+static_assert (!std::is_destructible <X>::value, "");<br>
+static_assert (!std::is_trivially_destructible <X>::value, "");<br>
+struct Y { Y () = default; Y (int); union { int a; S b = 42; }; };<br>
+static_assert (!std::is_default_constructible <Y>::value, "");<br>
+static_assert (!std::is_trivially_default_constructible <Y>::value, "");<br>
+static_assert (!std::is_destructible <Y>::value, "");<br>
+static_assert (!std::is_trivially_destructible <Y>::value, "");<br>
--- gcc/testsuite/g++.dg/cpp26/trivial-union2.C.jj      2026-05-20 14:26:01.245359408 +0200<br>
+++ gcc/testsuite/g++.dg/cpp26/trivial-union2.C 2026-05-20 14:26:01.245359408 +0200<br>
@@ -0,0 +1,7 @@<br>
+// P3074R7 - trivial unions (was std::uninitialized<T>)<br>
+// { dg-do compile { target c++20 } }<br>
+<br>
+union U { int a, b; };<br>
+template<U u> class X {};<br>
+constexpr U make() { U u; return u; }<br>
+void f(X<make()>) {}<br>
--- gcc/testsuite/g++.dg/init/pr43719.C.jj      2026-04-29 07:45:23.186351218 +0200<br>
+++ gcc/testsuite/g++.dg/init/pr43719.C 2026-05-20 14:26:01.247279549 +0200<br>
@@ -109,7 +109,7 @@ struct Z            // { dg-error "deleted" "" { t<br>
   Z5 z5;<br>
 };<br>
<br>
-union U // { dg-error "uninitialized" "" { target c++11 } }<br>
+union U<br>
 {<br>
   int const i; // { dg-message "should be initialized" }<br>
 };<br>
--- gcc/testsuite/g++.dg/init/pr25811.C.jj      2026-04-29 07:45:23.183351272 +0200<br>
+++ gcc/testsuite/g++.dg/init/pr25811.C 2026-05-20 14:26:01.247438801 +0200<br>
@@ -124,10 +124,9 @@ struct Z // { dg-error "deleted" "" { ta<br>
   Z5 z5;<br>
 };<br>
<br>
-union U // { dg-message "implicitly deleted" "" { target c++11 } }<br>
-       // { dg-error "uninitialized" "" { target c++11 } .-1 }<br>
+union U<br>
 {<br>
-  int const i; // { dg-message "should be initialized" }<br>
+  int const i;<br>
 };<br>
<br>
 void f1 ()<br>
@@ -207,5 +206,5 @@ void f15 ()<br>
<br>
 void f16 ()<br>
 {<br>
-  new U; // { dg-error "deleted|uninitialized const member" }<br>
+  new U; // { dg-error "uninitialized const member in 'union U' using 'new' without new-initializer" "" { target c++98_only } }<br>
 }<br>
--- gcc/testsuite/g++.dg/other/anon-union2.C.jj 2026-03-27 10:17:16.040299637 +0100<br>
+++ gcc/testsuite/g++.dg/other/anon-union2.C    2026-05-20 14:26:01.247698101 +0200<br>
@@ -6,5 +6,5 @@ struct S {<br>
 };<br>
<br>
 void f() {<br>
-  union { S a; };              // { dg-error "constructor|no match" }<br>
+  union { S a; };              // { dg-error "constructor|no match" "" { target c++23_down } }<br>
 }<br>
--- gcc/testsuite/g++.dg/reflect/trivial-union1.C.jj    2026-05-20 22:41:11.373882191 +0200<br>
+++ gcc/testsuite/g++.dg/reflect/trivial-union1.C       2026-05-21 09:36:03.469955381 +0200<br>
@@ -0,0 +1,214 @@<br>
+// P3074R7 - trivial unions (was std::uninitialized<T>)<br>
+// { dg-do compile { target c++26 } }<br>
+// { dg-additional-options "-freflection" }<br>
+<br>
+#include <meta><br>
+#include <ranges><br>
+<br>
+using namespace std::meta;<br>
+constexpr auto ctx = std::meta::access_context::unchecked ();<br>
+union A { int a; const int b; };<br>
+static_assert (is_default_constructible_type (^^A));<br>
+static_assert (is_trivially_default_constructible_type (^^A));<br>
+static_assert (is_destructible_type (^^A));<br>
+static_assert (is_trivially_destructible_type (^^A));<br>
+constexpr auto Actor = (members_of (^^A, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Adtor = (members_of (^^A, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Actor) && !is_deleted (Actor));<br>
+static_assert (is_defaulted (Adtor) && !is_deleted (Adtor));<br>
+struct B { int a; union { int b; const int c; }; };<br>
+static_assert (is_default_constructible_type (^^B));<br>
+static_assert (is_trivially_default_constructible_type (^^B));<br>
+static_assert (is_destructible_type (^^B));<br>
+static_assert (is_trivially_destructible_type (^^B));<br>
+constexpr auto Bctor = (members_of (^^B, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Bdtor = (members_of (^^B, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Bctor) && !is_deleted (Bctor));<br>
+static_assert (is_defaulted (Bdtor) && !is_deleted (Bdtor));<br>
+union C { const int a = 42; const long b; ~C (); };<br>
+static_assert (is_default_constructible_type (^^C));<br>
+static_assert (!is_trivially_default_constructible_type (^^C));<br>
+static_assert (is_destructible_type (^^C));<br>
+static_assert (!is_trivially_destructible_type (^^C));<br>
+constexpr auto Cctor = (members_of (^^C, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Cdtor = (members_of (^^C, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Cctor) && !is_deleted (Cctor));<br>
+static_assert (!is_defaulted (Cdtor) && !is_deleted (Cdtor));<br>
+struct D { D () = delete; D (int); ~D () = default; };<br>
+union E { D a = 42; D b; ~E (); };<br>
+static_assert (is_default_constructible_type (^^E));<br>
+static_assert (is_destructible_type (^^E));<br>
+constexpr auto Ector = (members_of (^^E, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Edtor = (members_of (^^E, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Ector) && !is_deleted (Ector));<br>
+static_assert (!is_defaulted (Edtor) && !is_deleted (Edtor));<br>
+struct F { int a; union { D b = 42; D c; }; };<br>
+static_assert (is_default_constructible_type (^^F));<br>
+static_assert (is_destructible_type (^^F));<br>
+constexpr auto Fctor = (members_of (^^F, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Fdtor = (members_of (^^F, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Fctor) && !is_deleted (Fctor));<br>
+static_assert (is_defaulted (Fdtor) && !is_deleted (Fdtor));<br>
+struct G { G (); ~G (); };<br>
+union I { int a; const int b; ~I (); };<br>
+static_assert (is_default_constructible_type (^^I));<br>
+static_assert (!is_trivially_default_constructible_type (^^I));<br>
+static_assert (is_destructible_type (^^I));<br>
+static_assert (!is_trivially_destructible_type (^^I));<br>
+constexpr auto Ictor = (members_of (^^I, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Idtor = (members_of (^^I, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Ictor) && !is_deleted (Ictor));<br>
+static_assert (!is_defaulted (Idtor) && !is_deleted (Idtor));<br>
+union J { D a; int b; };<br>
+static_assert (is_default_constructible_type (^^J));<br>
+static_assert (is_trivially_default_constructible_type (^^J));<br>
+static_assert (is_destructible_type (^^J));<br>
+static_assert (is_trivially_destructible_type (^^J));<br>
+constexpr auto Jctor = (members_of (^^J, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Jdtor = (members_of (^^J, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Jctor) && !is_deleted (Jctor));<br>
+static_assert (is_defaulted (Jdtor) && !is_deleted (Jdtor));<br>
+union K { G a; int b; };<br>
+static_assert (is_default_constructible_type (^^K));<br>
+static_assert (is_trivially_default_constructible_type (^^K));<br>
+static_assert (is_destructible_type (^^K));<br>
+static_assert (is_trivially_destructible_type (^^K));<br>
+constexpr auto Kctor = (members_of (^^K, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Kdtor = (members_of (^^K, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Kctor) && !is_deleted (Kctor));<br>
+static_assert (is_defaulted (Kdtor) && !is_deleted (Kdtor));<br>
+struct L { int a; union { G b; int c; }; };<br>
+static_assert (is_default_constructible_type (^^L));<br>
+static_assert (is_trivially_default_constructible_type (^^L));<br>
+static_assert (is_destructible_type (^^L));<br>
+static_assert (is_trivially_destructible_type (^^L));<br>
+constexpr auto Lctor = (members_of (^^L, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Ldtor = (members_of (^^L, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Lctor) && !is_deleted (Lctor));<br>
+static_assert (is_defaulted (Ldtor) && !is_deleted (Ldtor));<br>
+union M { M (); int a; int b; };<br>
+static_assert (is_default_constructible_type (^^M));<br>
+static_assert (!is_trivially_default_constructible_type (^^M));<br>
+static_assert (is_destructible_type (^^M));<br>
+static_assert (is_trivially_destructible_type (^^M));<br>
+constexpr auto Mctor = (members_of (^^M, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Mdtor = (members_of (^^M, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Mctor) && !is_deleted (Mctor));<br>
+static_assert (is_defaulted (Mdtor) && !is_deleted (Mdtor));<br>
+union N { N (); int a; G b; };<br>
+static_assert (!is_default_constructible_type (^^N));<br>
+static_assert (!is_trivially_default_constructible_type (^^N));<br>
+static_assert (!is_destructible_type (^^N));<br>
+static_assert (!is_trivially_destructible_type (^^N));<br>
+constexpr auto Nctor = (members_of (^^N, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Ndtor = (members_of (^^N, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Nctor) && !is_deleted (Nctor));<br>
+static_assert (is_defaulted (Ndtor) && is_deleted (Ndtor));<br>
+struct O { O (); union { int a; int b; }; };<br>
+static_assert (is_default_constructible_type (^^O));<br>
+static_assert (!is_trivially_default_constructible_type (^^O));<br>
+static_assert (is_destructible_type (^^O));<br>
+static_assert (is_trivially_destructible_type (^^O));<br>
+constexpr auto Octor = (members_of (^^O, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Odtor = (members_of (^^O, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Octor) && !is_deleted (Octor));<br>
+static_assert (is_defaulted (Odtor) && !is_deleted (Odtor));<br>
+struct P { P (); union { int a; G b; }; };<br>
+static_assert (!is_default_constructible_type (^^P));<br>
+static_assert (!is_trivially_default_constructible_type (^^P));<br>
+static_assert (!is_destructible_type (^^P));<br>
+static_assert (!is_trivially_destructible_type (^^P));<br>
+constexpr auto Pctor = (members_of (^^P, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Pdtor = (members_of (^^P, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Pctor) && !is_deleted (Pctor));<br>
+static_assert (is_defaulted (Pdtor) && is_deleted (Pdtor));<br>
+struct Q { Q (int); union { int a; G b; }; };<br>
+static_assert (!is_default_constructible_type (^^Q));<br>
+static_assert (!is_trivially_default_constructible_type (^^Q));<br>
+static_assert (!is_destructible_type (^^Q));<br>
+static_assert (!is_trivially_destructible_type (^^Q));<br>
+static_assert ((members_of (^^Q, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ()).size () == 0);<br>
+constexpr auto Qdtor = (members_of (^^Q, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Qdtor) && is_deleted (Qdtor));<br>
+struct R { R () = default; R (int); union { int a; G b; }; };<br>
+static_assert (!is_default_constructible_type (^^R));<br>
+static_assert (!is_trivially_default_constructible_type (^^R));<br>
+static_assert (!is_destructible_type (^^R));<br>
+static_assert (!is_trivially_destructible_type (^^R));<br>
+constexpr auto Rctor = (members_of (^^R, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Rdtor = (members_of (^^R, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Rctor) && !is_deleted (Rctor));<br>
+static_assert (is_defaulted (Rdtor) && is_deleted (Rdtor));<br>
+struct S { S (int); ~S (); };<br>
+union T { T (); int a; int b = 42; };<br>
+static_assert (is_default_constructible_type (^^T));<br>
+static_assert (!is_trivially_default_constructible_type (^^T));<br>
+static_assert (is_destructible_type (^^T));<br>
+static_assert (is_trivially_destructible_type (^^T));<br>
+constexpr auto Tctor = (members_of (^^T, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Tdtor = (members_of (^^T, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Tctor) && !is_deleted (Tctor));<br>
+static_assert (is_defaulted (Tdtor) && !is_deleted (Tdtor));<br>
+union U { U (); int a; S b = 42; };<br>
+static_assert (!is_default_constructible_type (^^U));<br>
+static_assert (!is_trivially_default_constructible_type (^^U));<br>
+static_assert (!is_destructible_type (^^U));<br>
+static_assert (!is_trivially_destructible_type (^^U));<br>
+constexpr auto Uctor = (members_of (^^U, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Udtor = (members_of (^^U, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Uctor) && !is_deleted (Uctor));<br>
+static_assert (is_defaulted (Udtor) && is_deleted (Udtor));<br>
+struct V { V (); union { int a; int b = 42; }; };<br>
+static_assert (is_default_constructible_type (^^V));<br>
+static_assert (!is_trivially_default_constructible_type (^^V));<br>
+static_assert (is_destructible_type (^^V));<br>
+static_assert (is_trivially_destructible_type (^^V));<br>
+constexpr auto Vctor = (members_of (^^V, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Vdtor = (members_of (^^V, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Vctor) && !is_deleted (Vctor));<br>
+static_assert (is_defaulted (Vdtor) && !is_deleted (Vdtor));<br>
+struct W { W (); union { int a; S b = 42; }; };<br>
+static_assert (!is_default_constructible_type (^^W));<br>
+static_assert (!is_trivially_default_constructible_type (^^W));<br>
+static_assert (!is_destructible_type (^^W));<br>
+static_assert (!is_trivially_destructible_type (^^W));<br>
+constexpr auto Wctor = (members_of (^^W, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Wdtor = (members_of (^^W, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (Wctor) && !is_deleted (Wctor));<br>
+static_assert (is_defaulted (Wdtor) && is_deleted (Wdtor));<br>
+struct X { X (int); union { int a; S b = 42; }; };<br>
+static_assert (!is_default_constructible_type (^^X));<br>
+static_assert (!is_trivially_default_constructible_type (^^X));<br>
+static_assert (!is_destructible_type (^^X));<br>
+static_assert (!is_trivially_destructible_type (^^X));<br>
+static_assert ((members_of (^^X, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ()).size () == 0);<br>
+constexpr auto Xdtor = (members_of (^^X, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Xdtor) && is_deleted (Xdtor));<br>
+struct Y { Y () = default; Y (int); union { int a; S b = 42; }; };<br>
+static_assert (!is_default_constructible_type (^^Y));<br>
+static_assert (!is_trivially_default_constructible_type (^^Y));<br>
+static_assert (!is_destructible_type (^^Y));<br>
+static_assert (!is_trivially_destructible_type (^^Y));<br>
+constexpr auto Yctor = (members_of (^^Y, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto Ydtor = (members_of (^^Y, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (is_defaulted (Yctor) && !is_deleted (Yctor));<br>
+static_assert (is_defaulted (Ydtor) && is_deleted (Ydtor));<br>
+union AA { AA (); int a; long b; };<br>
+static_assert (is_default_constructible_type (^^AA));<br>
+static_assert (!is_trivially_default_constructible_type (^^AA));<br>
+static_assert (is_destructible_type (^^AA));<br>
+static_assert (is_trivially_destructible_type (^^AA));<br>
+constexpr auto AActor = (members_of (^^AA, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto AAdtor = (members_of (^^AA, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (AActor) && !is_deleted (AActor));<br>
+static_assert (is_defaulted (AAdtor) && !is_deleted (AAdtor));<br>
+struct AB { AB () = default; AB (const AB &) = default; int a; ~AB (); };<br>
+union AC { AC (); int a; AB b; };<br>
+static_assert (!is_default_constructible_type (^^AC));<br>
+static_assert (!is_trivially_default_constructible_type (^^AC));<br>
+static_assert (!is_destructible_type (^^AC));<br>
+static_assert (!is_trivially_destructible_type (^^AC));<br>
+constexpr auto ACctor = (members_of (^^AC, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0];<br>
+constexpr auto ACdtor = (members_of (^^AC, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0];<br>
+static_assert (!is_defaulted (ACctor) && !is_deleted (ACctor));<br>
+static_assert (is_defaulted (ACdtor) && is_deleted (ACdtor));<br>
--- gcc/testsuite/g++.dg/reflect/type_trait6.C.jj       2026-05-20 08:43:02.581478043 +0200<br>
+++ gcc/testsuite/g++.dg/reflect/type_trait6.C  2026-05-20 14:26:01.246323664 +0200<br>
@@ -985,7 +985,7 @@ static_assert (!is_destructible_type (^^<br>
 static_assert (!is_destructible_type (^^const N2::Del [1]));<br>
 static_assert (!is_destructible_type (^^N2::Del []));<br>
 static_assert (!is_destructible_type (^^const N2::Del []));<br>
-static_assert (!is_destructible_type (^^N2::NontrivialUnion));<br>
+static_assert (is_destructible_type (^^N2::NontrivialUnion));<br>
 static_assert (is_destructible_type (^^N2::UnusualCopy));<br>
<br>
 static_assert (is_trivially_default_constructible_type (^^int));<br>
@@ -1367,8 +1367,8 @@ static_assert (!is_nothrow_destructible_<br>
 static_assert (!is_nothrow_destructible_type (^^N2::Aggr2));<br>
 static_assert (!is_nothrow_destructible_type (^^N2::Aggr2 [1]));<br>
 static_assert (!is_nothrow_destructible_type (^^N2::TD1 [1][2]));<br>
-static_assert (!is_nothrow_destructible_type (^^N2::Ut));<br>
-static_assert (!is_nothrow_destructible_type (^^N2::Ut [3]));<br>
+static_assert (is_nothrow_destructible_type (^^N2::Ut));<br>
+static_assert (is_nothrow_destructible_type (^^N2::Ut [3]));<br>
 static_assert (!is_nothrow_destructible_type (^^N2::AbstractDelDtor));<br>
 static_assert (!is_nothrow_destructible_type (^^N2::Abstract2));<br>
 static_assert (!is_nothrow_destructible_type (^^N2::Abstract3));<br>
--- gcc/testsuite/g++.dg/reflect/is_constructible_type1.C.jj    2026-05-20 08:43:02.580478060 +0200<br>
+++ gcc/testsuite/g++.dg/reflect/is_constructible_type1.C       2026-05-20 14:26:01.246691288 +0200<br>
@@ -603,7 +603,7 @@ static_assert (!is_constructible_type (^<br>
 static_assert (!is_constructible_type (^^const DelnAny, { ^^int, ^^void * }));<br>
 static_assert (!is_constructible_type (^^DelnAny, { ^^Empty, ^^B, ^^D }));<br>
 static_assert (!is_constructible_type (^^const DelnAny, { ^^Empty, ^^B, ^^D }));<br>
-static_assert (!is_constructible_type (^^NontrivialUnion, {}));<br>
+static_assert (is_constructible_type (^^NontrivialUnion, {}));<br>
 static_assert (!is_constructible_type (^^NontrivialUnion, { ^^const NontrivialUnion & }));<br>
 static_assert (!is_constructible_type (^^UnusualCopy, {}));<br>
 static_assert (!is_constructible_type (^^UnusualCopy, { ^^UnusualCopy }));<br>
<br>
<br>
        Jakub<br>
<br>
</blockquote></div></div>