Hi!
Here is an updated patch. It implements the P3074R7 wording without the later
removed sentence in https://eel.is/c++draft/class.mem#class.default.ctor-4
and https://eel.is/c++draft/class.dtor#7.1
<del>X is a non-union class and </del>any <del>non-variant </del>
potentially constructed subobject <ins>S </ins>has class type M (or possibly
multidimensional array thereof) where M has a destructor that is
deleted or is inaccessible from the defaulted destructor,
<ins> and either S is non-variant or S has a default member initializer,</ins>
and
https://eel.is/c++draft/class.dtor#7.2.1
overload resolution to select a constructor to default-initialize an object
of type X either fails or selects a constructor that is either deleted or
<del>not trivial</del><ins>user-provided</ins>, or
To make this work, I had to work around it in <optional> header, where
we have user-provided union ctor and defaulted dtor.
If we change the standard further to make that valid (e.g. with the
discussed rule that if all variant subobjects have accessible destructor
which is trivial, then we don't delete the defaulted dtor just because
default ctor is user-provided, further changes will be needed.
Note, I had to do this deletion because of user-provided default ctor
in two places, because sometimes in synthesized_method_walk it is too early,
the ctors might not have been cloned at all (and looking up ctor_identifier
and trying to call it with a bool argument doesn't work).
This doesn't implement anything from P3726R2 yet (and only tested on the
changed tests and reflect/* so far).
2026-05-06 Jakub Jelinek <[email protected]>
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine __cpp_trivial_union
202603L for C++26.
gcc/cp/
* method.cc (walk_field_subobs): Don't check
default_init_uninitialized_part for variant members. Avoid
locate_fn_flags/process_subob_fn for variant members for default ctor
or, if without member initializer, for dtor too.
(synthesized_method_walk): Make dtor deleted for C++26 if a union
in a complete class doesn't have usable default ctor or has it
user-provided.
* class.cc (check_field_decl): Don't adjust
TYPE_HAS_NONTRIVIAL_DESTRUCTOR or TYPE_HAS_COMPLEX_DFLT for variant
members in C++26.
(clone_constructors_and_destructors): Make defaulted dtor deleted
for C++26 if a union doesn't have usable default ctor or has it
user-provided.
gcc/testsuite/
* g++.dg/DRs/dr2581-1.C (__cpp_trivial_union): Expect a warning.
* g++.dg/DRs/dr2581-2.C (__cpp_trivial_union): Likewise.
* g++.dg/cpp26/feat-cxx26.C (__cpp_trivial_union): New test.
* g++.dg/cpp26/trivial-union1.C: New test.
* g++.dg/reflect/trivial-union1.C: New test.
* g++.dg/reflect/type_trait6.C: Change 3 static_asserts.
* g++.dg/reflect/is_constructible_type1.C: Change 1 static_assert.
libstdc++-v3/
* include/std/optional
(std::_Optional_payload_base<_Tp, bool>::_Storage <_Up>): For C++26
make ctor defaulted instead of inline user provided and add member
initializer for _M_empty member in that case.
--- gcc/c-family/c-cppbuiltin.cc.jj 2026-05-06 10:38:27.594915980 +0200
+++ gcc/c-family/c-cppbuiltin.cc 2026-05-06 12:27:41.897327631 +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-06 10:38:27.603915832 +0200
+++ gcc/cp/method.cc 2026-05-06 15:52:25.085718750 +0200
@@ -2771,6 +2771,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 +2848,15 @@ 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 && DECL_INITIAL (field) == NULL_TREE)
+ continue;
+ }
+
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
process_subob_fn (rval, sfk, spec_p, trivial_p, deleted_p,
@@ -2985,6 +2995,38 @@ synthesized_method_walk (tree ctype, spe
/* The synthesized method will call base dtors, but check complete
here to avoid having to deal with VTT. */
fnname = complete_dtor_identifier;
+
+ if (TREE_CODE (ctype) == UNION_TYPE
+ && cxx_dialect >= cxx26
+ && deleted_p
+ /* For still incomplete types defer this until ctor cloning. */
+ && COMPLETE_TYPE_P (ctype))
+ {
+ /* [class.dtor]/(7.2.1):
+ A defaulted destructor for a class X is defined as deleted if X
+ is a union and
+ -- overload resolution to select a constructor to
+ default-initialize an object of type X either fails or selects
+ a constructor that is either deleted or user-provided. */
+ tree ctor = locate_ctor (ctype);
+ if (ctor == NULL_TREE)
+ {
+ *deleted_p = true;
+ if (diag)
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (ctype)),
+ "default constructor of %qT unusable", ctype);
+ return;
+ }
+ else if (user_provided_p (ctor))
+ {
+ *deleted_p = true;
+ if (diag)
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (ctype)),
+ "default constructor of %qT is user-provided",
+ ctype);
+ return;
+ }
+ }
}
else if (SFK_ASSIGN_P (sfk))
fnname = assign_op_identifier;
--- gcc/cp/class.cc.jj 2026-05-06 10:38:27.597915931 +0200
+++ gcc/cp/class.cc 2026-05-06 16:03:31.068876166 +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)
@@ -5528,7 +5536,26 @@ clone_constructors_and_destructors (tree
clone_cdtor (fn, /*update_methods=*/true);
if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
- clone_cdtor (dtor, /*update_methods=*/true);
+ {
+ if (cxx_dialect >= cxx26
+ && TREE_CODE (t) == UNION_TYPE
+ && DECL_DEFAULTED_IN_CLASS_P (dtor)
+ && !DECL_DELETED_FN (dtor))
+ {
+ /* [class.dtor]/(7.2.1):
+ A defaulted destructor for a class X is defined as deleted if X
+ is a union and
+ -- overload resolution to select a constructor to
+ default-initialize an object of type X either fails or selects
+ a constructor that is either deleted or user-provided.
+ This isn't done by synthesized_method_walk for incomplete types
+ because the default ctor is not yet cloned. */
+ tree ctor = locate_ctor (t);
+ if (ctor == NULL_TREE || user_provided_p (ctor))
+ DECL_DELETED_FN (dtor) = true;
+ }
+ clone_cdtor (dtor, /*update_methods=*/true);
+ }
}
/* Deduce noexcept for a destructor DTOR. */
--- gcc/testsuite/g++.dg/DRs/dr2581-1.C.jj 2026-05-06 10:38:27.614915651
+0200
+++ gcc/testsuite/g++.dg/DRs/dr2581-1.C 2026-05-06 12:27:41.930583042 +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-06 10:38:27.615915634
+0200
+++ gcc/testsuite/g++.dg/DRs/dr2581-2.C 2026-05-06 12:27:41.932288299 +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/cpp26/feat-cxx26.C.jj 2026-05-06 10:38:27.621915535
+0200
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2026-05-06 12:27:41.932699175
+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-06
12:27:41.932834170 +0200
+++ gcc/testsuite/g++.dg/cpp26/trivial-union1.C 2026-05-06 12:27:41.932834170
+0200
@@ -0,0 +1,73 @@
+// 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
--- gcc/testsuite/g++.dg/reflect/trivial-union1.C.jj 2026-05-06
12:27:41.933015207 +0200
+++ gcc/testsuite/g++.dg/reflect/trivial-union1.C 2026-05-06
16:12:08.912460173 +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-03-27
10:17:16.145297923 +0100
+++ gcc/testsuite/g++.dg/reflect/type_trait6.C 2026-05-06 16:15:31.957157388
+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-03-27
10:17:16.128298201 +0100
+++ gcc/testsuite/g++.dg/reflect/is_constructible_type1.C 2026-05-06
16:15:59.526708933 +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/std/optional.jj 2026-05-06 10:38:27.623915503
+0200
+++ libstdc++-v3/include/std/optional 2026-05-06 12:27:41.933204607 +0200
@@ -221,7 +221,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Up, bool = is_trivially_destructible_v<_Up>>
union _Storage
{
+#if __cpp_trivial_union >= 202502L
+ constexpr _Storage() noexcept = default;
+#else
constexpr _Storage() noexcept : _M_empty() { }
+#endif
template<typename... _Args>
constexpr
@@ -258,7 +262,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Storage& operator=(_Storage&&) = default;
#endif
+#if __cpp_trivial_union >= 202502L
+ _Empty_byte _M_empty = {};
+#else
_Empty_byte _M_empty;
+#endif
_Up _M_value;
};
Jakub