https://github.com/brevzin updated 
https://github.com/llvm/llvm-project/pull/146815

>From 40290a957b6f349a9b670193c8bc699d8eb7d373 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.rev...@gmail.com>
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/5] [P3074] Implementing part of trivial unions

---
 clang/lib/AST/DeclCXX.cpp                   |  9 ++++--
 clang/lib/Sema/SemaDeclCXX.cpp              | 16 +++++++++-
 clang/test/CXX/drs/cwg6xx.cpp               |  4 +--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 +++++-----
 clang/test/CXX/special/class.ctor/p6-0x.cpp | 28 +++++++++--------
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 33 +++++++++++----------
 6 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index ccb308e103253..49adbdf1c393d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
     // those because they are always unnamed.
     bool IsZeroSize = Field->isZeroSize(Context);
 
+    // P3074
+    const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
+
     if (const auto *RecordTy = T->getAs<RecordType>()) {
       auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
       if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
         //    -- for all the non-static data members of its class that are of
         //       class type (or array thereof), each such class has a trivial
         //       default constructor.
-        if (!FieldRec->hasTrivialDefaultConstructor())
+        if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
           data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
 
         // C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
         if (!FieldRec->hasTrivialMoveAssignment())
           data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
 
-        if (!FieldRec->hasTrivialDestructor())
+        if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
           data().HasTrivialSpecialMembers &= ~SMF_Destructor;
-        if (!FieldRec->hasTrivialDestructorForCall())
+        if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
           data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
         if (!FieldRec->hasIrrelevantDestructor())
           data().HasIrrelevantDestructor = false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e8c65025bfe6d..225409a69df53 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,6 +9511,15 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
 
+  // P3074: default ctor and dtor for unions are not deleted, regardless of
+  // whether the underlying fields have non-trivial or deleted versions of 
those
+  // members
+  if (S.Context.getLangOpts().CPlusPlus26)
+    if (Field && Field->getParent()->isUnion() &&
+        (CSM == CXXSpecialMemberKind::DefaultConstructor ||
+         CSM == CXXSpecialMemberKind::Destructor))
+      return false;
+
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,8 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
 
       // At least one member in each anonymous union must be non-const
       if (CSM == CXXSpecialMemberKind::DefaultConstructor &&
-          AllVariantFieldsAreConst && !FieldRecord->field_empty()) {
+          AllVariantFieldsAreConst && !FieldRecord->field_empty() &&
+          !S.Context.getLangOpts().CPlusPlus26) {
         if (Diagnose)
           S.Diag(FieldRecord->getLocation(),
                  diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
   // default constructor. Don't do that.
   if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
       AllFieldsAreConst) {
+
+    if (S.Context.getLangOpts().CPlusPlus26)
+      return false;
+
     bool AnyFields = false;
     for (auto *F : MD->getParent()->fields())
       if ((AnyFields = !F->isUnnamedBitField()))
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..dd54bb5295b56 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,cxx26 
-fexceptions -fcxx-exceptions -pedantic-errors
 
 #if __cplusplus == 199711L
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -922,7 +922,7 @@ namespace cwg667 { // cwg667: 8
 
   struct B { ~B() = delete; };
   union C { B b; };
-  static_assert(!__is_trivially_destructible(C), "");
+  static_assert(!__is_trivially_destructible(C), ""); // cxx26-error {{failed}}
 
   struct D { D(const D&) = delete; };
   struct E : D {};
diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp 
b/clang/test/CXX/special/class.ctor/p5-0x.cpp
index e0c53058f892b..97a8b035a0705 100644
--- a/clang/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -fsyntax-only -verify=expected %s -std=c++26 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
 
 struct DefaultedDefCtor1 {};
 struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
@@ -23,8 +24,8 @@ int n;
 
 // - X is a union-like class that has a variant member with a non-trivial
 // default constructor,
-union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
-Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}}
+union Deleted1a { UserProvidedDefCtor u; }; // until26-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
+Deleted1a d1a; // until26-error {{implicitly-deleted default constructor}}
 union NotDeleted1a { DefaultedDefCtor1 nu; };
 NotDeleted1a nd1a;
 union NotDeleted1b { DefaultedDefCtor2 nu; };
@@ -86,19 +87,19 @@ NotDeleted3i nd3i;
 union Deleted4a {
   const int a;
   const int b;
-  const UserProvidedDefCtor c; // expected-note {{because variant field 'c' 
has a non-trivial default constructor}}
+  const UserProvidedDefCtor c; // until26-note {{because variant field 'c' has 
a non-trivial default constructor}}
 };
-Deleted4a d4a; // expected-error {{implicitly-deleted default constructor}}
+Deleted4a d4a; // until26-error {{implicitly-deleted default constructor}}
 union NotDeleted4a { const int a; int b; };
 NotDeleted4a nd4a;
 
 // - X is a non-union class and all members of any anonymous union member are 
of
 // const-qualified type (or array thereof),
 struct Deleted5a {
-  union { const int a; }; // expected-note {{because all data members of an 
anonymous union member are const-qualified}}
+  union { const int a; }; // until26-note {{because all data members of an 
anonymous union member are const-qualified}}
   union { int b; };
 };
-Deleted5a d5a; // expected-error {{implicitly-deleted default constructor}}
+Deleted5a d5a; // until26-error {{implicitly-deleted default constructor}}
 struct NotDeleted5a { union { const int a; int b; }; union { const int c; int 
d; }; };
 NotDeleted5a nd5a;
 
diff --git a/clang/test/CXX/special/class.ctor/p6-0x.cpp 
b/clang/test/CXX/special/class.ctor/p6-0x.cpp
index 156a2b20c6b52..6ce1b06841ab4 100644
--- a/clang/test/CXX/special/class.ctor/p6-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p6-0x.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx26 %s -std=c++26
 
 // Implicitly-defined default constructors are constexpr if the implicit
 // definition would be.
@@ -15,8 +16,9 @@ constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does 
not call construct
 constexpr int nc2_a = NonConstexpr2().nl.a; // ok
 constexpr int nc2a_a = NonConstexpr2a().a; // ok
 struct Helper {
-  friend constexpr NonConstexpr1::NonConstexpr1(); // expected-error {{follows 
non-constexpr declaration}}
-  friend constexpr NonConstexpr2::NonConstexpr2(); // expected-error {{follows 
non-constexpr declaration}}
+  friend constexpr NonConstexpr1::NonConstexpr1(); // until26-error {{follows 
non-constexpr declaration}} cxx26-error {{missing exception specification}}
+  friend constexpr NonConstexpr2::NonConstexpr2(); // until26-error {{follows 
non-constexpr declaration}} cxx26-error {{missing exception specification}}
+
 };
 
 struct Constexpr1 {};
@@ -31,14 +33,14 @@ constexpr Constexpr2 c2 = Constexpr2(); // ok
 
 int n;
 struct Member {
-  Member() : a(n) {}
+  Member() : a(n) {} // cxx26-note {{here}}
   constexpr Member(int&a) : a(a) {}
   int &a;
 };
-struct NonConstexpr4 { // expected-note {{here}}
+struct NonConstexpr4 { // until26-note {{here}} cxx26-note {{non-constexpr 
constructor}}
   Member m;
 };
-constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant 
expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}}
+constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant 
expression}} until26-note {{non-constexpr constructor 'NonConstexpr4'}} 
cxx26-note {{in call to}}
 struct Constexpr3 {
   constexpr Constexpr3() : m(n) {}
   Member m;
@@ -53,11 +55,11 @@ constexpr Constexpr4 c4 = Constexpr4(); // ok
 // This rule breaks some legal C++98 programs!
 struct A {}; // expected-note {{here}}
 struct B {
-  friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows 
constexpr declaration}}
+  friend A::A(); // until26-error {{non-constexpr declaration of 'A' follows 
constexpr declaration}} cxx26-error {{missing exception specification}}
 };
 
 namespace UnionCtors {
-  union A { // expected-note {{here}}
+  union A { // until26-note {{here}}
     int a;
     int b;
   };
@@ -79,7 +81,7 @@ namespace UnionCtors {
       int d = 5;
     };
   };
-  struct E { // expected-note {{here}}
+  struct E { // until26-note {{here}}
     union {
       int a;
       int b;
@@ -87,11 +89,11 @@ namespace UnionCtors {
   };
 
   struct Test {
-    friend constexpr A::A() noexcept; // expected-error {{follows 
non-constexpr declaration}}
+    friend constexpr A::A() noexcept; // until26-error {{follows non-constexpr 
declaration}}
     friend constexpr B::B() noexcept;
     friend constexpr C::C() noexcept;
     friend constexpr D::D() noexcept;
-    friend constexpr E::E() noexcept; // expected-error {{follows 
non-constexpr declaration}}
+    friend constexpr E::E() noexcept; // until26-error {{follows non-constexpr 
declaration}}
   };
 }
 
@@ -122,6 +124,6 @@ namespace PR48763 {
 
   struct G { G(); };
   struct H : D { using D::D; H(int); G g; };
-  union V { H h; }; // expected-note {{field 'h' has a non-trivial default 
constructor}}
-  V v; // expected-error {{deleted}}
+  union V { H h; }; // until26-note {{field 'h' has a non-trivial default 
constructor}}
+  V v; // until26-error {{deleted}}
 }
diff --git a/clang/test/CXX/special/class.dtor/p5-0x.cpp 
b/clang/test/CXX/special/class.dtor/p5-0x.cpp
index ae14dcdaf102a..7616383515e0a 100644
--- a/clang/test/CXX/special/class.dtor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.dtor/p5-0x.cpp
@@ -1,10 +1,11 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s -Wno-defaulted-function-deleted 
-triple x86_64-linux-gnu
+// RUN: %clang_cc1 -verify=expected,until26 -std=c++11 %s 
-Wno-defaulted-function-deleted -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -verify=expected -std=c++26 %s 
-Wno-defaulted-function-deleted -triple x86_64-linux-gnu
 
 struct NonTrivDtor {
   ~NonTrivDtor();
 };
 struct DeletedDtor {
-  ~DeletedDtor() = delete; // expected-note 5 {{deleted here}}
+  ~DeletedDtor() = delete; // expected-note 4+ {{deleted here}}
 };
 class InaccessibleDtor {
   ~InaccessibleDtor() = default;
@@ -16,28 +17,28 @@ class InaccessibleDtor {
 // destructor.
 union A1 {
   A1();
-  NonTrivDtor n; // expected-note {{destructor of 'A1' is implicitly deleted 
because variant field 'n' has a non-trivial destructor}}
+  NonTrivDtor n; // until26-note {{destructor of 'A1' is implicitly deleted 
because variant field 'n' has a non-trivial destructor}}
 };
-A1 a1; // expected-error {{deleted function}}
+A1 a1; // until26-error {{deleted function}}
 struct A2 {
   A2();
   union {
-    NonTrivDtor n; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
+    NonTrivDtor n; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
   };
 };
-A2 a2; // expected-error {{deleted function}}
+A2 a2; // until26-error {{deleted function}}
 union A3 {
   A3();
-  NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
+  NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
 };
-A3 a3; // expected-error {{deleted function}}
+A3 a3; // until26-error {{deleted function}}
 struct A4 {
   A4();
   union {
-    NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
+    NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
   };
 };
-A4 a4; // expected-error {{deleted function}}
+A4 a4; // until26-error {{deleted function}}
 
 // -- any of the non-static data members has class type M (or array thereof) 
and
 // M has a deleted or inaccessible destructor.
@@ -63,18 +64,18 @@ struct B4 {
 B4 b4; // expected-error {{deleted function}}
 union B5 {
   B5();
-  union { // expected-note-re {{because field 'B5::(anonymous union at 
{{.+}})' has a deleted destructor}}
-    DeletedDtor a; // expected-note {{because field 'a' has a deleted 
destructor}}
+  union { // until26-note-re {{because field 'B5::(anonymous union at {{.+}})' 
has a deleted destructor}}
+    DeletedDtor a; // until26-note {{because field 'a' has a deleted 
destructor}}
   };
 };
-B5 b5; // expected-error {{deleted function}}
+B5 b5; // until26-error {{deleted function}}
 union B6 {
   B6();
-  union { // expected-note-re {{because field 'B6::(anonymous union at 
{{.+}})' has a deleted destructor}}
-    InaccessibleDtor a; // expected-note {{because field 'a' has an 
inaccessible destructor}}
+  union { // until26-note-re {{because field 'B6::(anonymous union at {{.+}})' 
has a deleted destructor}}
+    InaccessibleDtor a; // until26-note {{because field 'a' has an 
inaccessible destructor}}
   };
 };
-B6 b6; // expected-error {{deleted function}}
+B6 b6; // until26-error {{deleted function}}
 
 // -- any direct or virtual base class has a deleted or inaccessible 
destructor.
 struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} 
expected-note {{base class 'DeletedDtor' has a deleted destructor}}

>From 59b0649e184ab1ea73b3b239ae0240bb2dcd3ac4 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.rev...@gmail.com>
Date: Wed, 2 Jul 2025 23:04:59 -0500
Subject: [PATCH 2/5] Adding test case that I have to fix still

---
 clang/test/CXX/special/class.dtor/p7.cpp | 48 ++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 clang/test/CXX/special/class.dtor/p7.cpp

diff --git a/clang/test/CXX/special/class.dtor/p7.cpp 
b/clang/test/CXX/special/class.dtor/p7.cpp
new file mode 100644
index 0000000000000..b9b2e2bde5676
--- /dev/null
+++ b/clang/test/CXX/special/class.dtor/p7.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -verify -std=c++26 %s -Wno-defaulted-function-deleted 
-triple x86_64-linux-gnu
+
+struct NonTrivial {
+    NonTrivial(int) { }
+    ~NonTrivial() { }
+};
+
+union U0 {
+    NonTrivial nt;
+    int i;
+  };
+  U0 u0;
+
+// overload resolution to select a constructor to default-initialize an object 
of type X either fails
+union U1 {
+    U1(int);
+    NonTrivial nt;
+};
+U1 u1(1); // expected-error {{deleted destructor}}
+
+// or selects a constructor that is either deleted or not trivial, or
+union U2 {
+    U2() : nt(2) { }
+    NonTrivial nt;
+};
+U2 u2; // expected-error {{deleted destructor}}
+
+union U3 {
+    U3() = delete;
+    U3(int);
+    NonTrivial nt;
+};
+U3 u3(1); // expected-error {{deleted destructor}}
+
+// or X has a variant member V of class type M (or possibly multi-dimensional 
array thereof) where V has a default member initializer and M has a destructor 
that is non-trivial,
+union U4 {
+    NonTrivial nt = 1;
+};
+U4 u4; // expected-error {{deleted destructor}}
+
+union U5 {
+  NonTrivial nt;
+  U5* next = nullptr;
+};
+U5 u5;
+
+
+

>From e7cc4ec355367a06a85e154cc616a647616fe451 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.rev...@gmail.com>
Date: Wed, 2 Jul 2025 23:27:25 -0500
Subject: [PATCH 3/5] One down

---
 clang/lib/Sema/SemaDeclCXX.cpp           | 5 +++++
 clang/test/CXX/special/class.dtor/p7.cpp | 8 ++++----
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 225409a69df53..0a7e71cfcf0fe 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9705,6 +9705,11 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
   if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD))
     return true;
 
+  if (S.Context.getLangOpts().CPlusPlus26 && FD->hasInClassInitializer() &&
+      FieldRecord && !FieldRecord->hasTrivialDestructor() &&
+      CSM == CXXSpecialMemberKind::Destructor)
+    return true;
+
   if (CSM == CXXSpecialMemberKind::DefaultConstructor) {
     // For a default constructor, all references must be initialized in-class
     // and, if a union, it must have a non-const member.
diff --git a/clang/test/CXX/special/class.dtor/p7.cpp 
b/clang/test/CXX/special/class.dtor/p7.cpp
index b9b2e2bde5676..1b50bdc3920e0 100644
--- a/clang/test/CXX/special/class.dtor/p7.cpp
+++ b/clang/test/CXX/special/class.dtor/p7.cpp
@@ -16,27 +16,27 @@ union U1 {
     U1(int);
     NonTrivial nt;
 };
-U1 u1(1); // expected-error {{deleted destructor}}
+U1 u1(1); // expected-error {{deleted function}}
 
 // or selects a constructor that is either deleted or not trivial, or
 union U2 {
     U2() : nt(2) { }
     NonTrivial nt;
 };
-U2 u2; // expected-error {{deleted destructor}}
+U2 u2; // expected-error {{deleted function}}
 
 union U3 {
     U3() = delete;
     U3(int);
     NonTrivial nt;
 };
-U3 u3(1); // expected-error {{deleted destructor}}
+U3 u3(1); // expected-error {{deleted function}}
 
 // or X has a variant member V of class type M (or possibly multi-dimensional 
array thereof) where V has a default member initializer and M has a destructor 
that is non-trivial,
 union U4 {
     NonTrivial nt = 1;
 };
-U4 u4; // expected-error {{deleted destructor}}
+U4 u4; // expected-error {{deleted function}}
 
 union U5 {
   NonTrivial nt;

>From 5eb68c59001ccb8fbe502b07b14dc70749c931da Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.rev...@gmail.com>
Date: Thu, 3 Jul 2025 10:26:30 -0500
Subject: [PATCH 4/5] More accurate

---
 clang/lib/Sema/SemaDeclCXX.cpp              | 45 +++++++++++++++------
 clang/test/CXX/special/class.dtor/p5-0x.cpp | 28 ++++++-------
 clang/test/CXX/special/class.dtor/p7.cpp    | 43 +++++++++++---------
 3 files changed, 71 insertions(+), 45 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0a7e71cfcf0fe..089ffa1d2dea2 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9511,15 +9511,6 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   CXXMethodDecl *Decl = SMOR.getMethod();
   FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
 
-  // P3074: default ctor and dtor for unions are not deleted, regardless of
-  // whether the underlying fields have non-trivial or deleted versions of 
those
-  // members
-  if (S.Context.getLangOpts().CPlusPlus26)
-    if (Field && Field->getParent()->isUnion() &&
-        (CSM == CXXSpecialMemberKind::DefaultConstructor ||
-         CSM == CXXSpecialMemberKind::Destructor))
-      return false;
-
   int DiagKind = -1;
 
   if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9552,6 +9543,35 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
   if (DiagKind == -1)
     return false;
 
+  if (this->S.Context.getLangOpts().CPlusPlus26 && inUnion() &&
+      CSM == CXXSpecialMemberKind::Destructor) {
+    // CXXRecordDecl *FieldRecord = Subobj.dyn_cast<CXXRecordDecl*>();
+    // [class.dtor]/7 In C++26, a destructor for a union X is only deleted 
under
+    // the additional conditions that:
+
+    // 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 not trivial, or
+    // or X has a variant member V of class type M (or possibly
+    // multi-dimensional array thereof) where V has a default member 
initializer
+    // and M has a destructor that is non-trivial,
+
+    Sema::SpecialMemberOverloadResult SMOR =
+        S.LookupSpecialMember(dyn_cast<CXXRecordDecl>(Field->getParent()),
+                              CXXSpecialMemberKind::DefaultConstructor, false,
+                              false, false, false, false);
+    if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Success) {
+      CXXConstructorDecl *Ctor = 
dyn_cast<CXXConstructorDecl>(SMOR.getMethod());
+      if (Ctor->isTrivial()) {
+        return false;
+      }
+
+      if (!Ctor->isUserProvided() && !Field->hasInClassInitializer()) {
+        return false;
+      }
+    }
+  }
+
   if (Diagnose) {
     if (Field) {
       S.Diag(Field->getLocation(),
@@ -9705,10 +9725,9 @@ bool 
SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
   if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD))
     return true;
 
-  if (S.Context.getLangOpts().CPlusPlus26 && FD->hasInClassInitializer() &&
-      FieldRecord && !FieldRecord->hasTrivialDestructor() &&
-      CSM == CXXSpecialMemberKind::Destructor)
-    return true;
+  if (inUnion() && S.Context.getLangOpts().CPlusPlus26 &&
+      CSM == CXXSpecialMemberKind::DefaultConstructor)
+    return false;
 
   if (CSM == CXXSpecialMemberKind::DefaultConstructor) {
     // For a default constructor, all references must be initialized in-class
diff --git a/clang/test/CXX/special/class.dtor/p5-0x.cpp 
b/clang/test/CXX/special/class.dtor/p5-0x.cpp
index 7616383515e0a..b8ebb41b24ed7 100644
--- a/clang/test/CXX/special/class.dtor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.dtor/p5-0x.cpp
@@ -17,28 +17,28 @@ class InaccessibleDtor {
 // destructor.
 union A1 {
   A1();
-  NonTrivDtor n; // until26-note {{destructor of 'A1' is implicitly deleted 
because variant field 'n' has a non-trivial destructor}}
+  NonTrivDtor n; // expected-note {{destructor of 'A1' is implicitly deleted 
because variant field 'n' has a non-trivial destructor}}
 };
-A1 a1; // until26-error {{deleted function}}
+A1 a1; // expected-error {{deleted function}}
 struct A2 {
   A2();
   union {
-    NonTrivDtor n; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
+    NonTrivDtor n; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
   };
 };
-A2 a2; // until26-error {{deleted function}}
+A2 a2; // expected-error {{deleted function}}
 union A3 {
   A3();
-  NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
+  NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
 };
-A3 a3; // until26-error {{deleted function}}
+A3 a3; // expected-error {{deleted function}}
 struct A4 {
   A4();
   union {
-    NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a 
non-trivial destructor}}
+    NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a 
non-trivial destructor}}
   };
 };
-A4 a4; // until26-error {{deleted function}}
+A4 a4; // expected-error {{deleted function}}
 
 // -- any of the non-static data members has class type M (or array thereof) 
and
 // M has a deleted or inaccessible destructor.
@@ -64,18 +64,18 @@ struct B4 {
 B4 b4; // expected-error {{deleted function}}
 union B5 {
   B5();
-  union { // until26-note-re {{because field 'B5::(anonymous union at {{.+}})' 
has a deleted destructor}}
-    DeletedDtor a; // until26-note {{because field 'a' has a deleted 
destructor}}
+  union { // expected-note-re {{because field 'B5::(anonymous union at 
{{.+}})' has a deleted destructor}}
+    DeletedDtor a; // expected-note {{because field 'a' has a deleted 
destructor}}
   };
 };
-B5 b5; // until26-error {{deleted function}}
+B5 b5; // expected-error {{deleted function}}
 union B6 {
   B6();
-  union { // until26-note-re {{because field 'B6::(anonymous union at {{.+}})' 
has a deleted destructor}}
-    InaccessibleDtor a; // until26-note {{because field 'a' has an 
inaccessible destructor}}
+  union { // expected-note-re {{because field 'B6::(anonymous union at 
{{.+}})' has a deleted destructor}}
+    InaccessibleDtor a; // expected-note {{because field 'a' has an 
inaccessible destructor}}
   };
 };
-B6 b6; // until26-error {{deleted function}}
+B6 b6; // expected-error {{deleted function}}
 
 // -- any direct or virtual base class has a deleted or inaccessible 
destructor.
 struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} 
expected-note {{base class 'DeletedDtor' has a deleted destructor}}
diff --git a/clang/test/CXX/special/class.dtor/p7.cpp 
b/clang/test/CXX/special/class.dtor/p7.cpp
index 1b50bdc3920e0..c19bfcc5b119e 100644
--- a/clang/test/CXX/special/class.dtor/p7.cpp
+++ b/clang/test/CXX/special/class.dtor/p7.cpp
@@ -1,42 +1,42 @@
 // RUN: %clang_cc1 -verify -std=c++26 %s -Wno-defaulted-function-deleted 
-triple x86_64-linux-gnu
 
 struct NonTrivial {
-    NonTrivial(int) { }
-    ~NonTrivial() { }
+  NonTrivial(int) { }
+  ~NonTrivial() { }
 };
 
 union U0 {
-    NonTrivial nt;
-    int i;
-  };
-  U0 u0;
+  NonTrivial nt;
+  int i;
+};
+U0 u0;
 
 // overload resolution to select a constructor to default-initialize an object 
of type X either fails
 union U1 {
-    U1(int);
-    NonTrivial nt;
+  U1(int);
+  NonTrivial nt; // #1
 };
-U1 u1(1); // expected-error {{deleted function}}
+U1 u1(1); // expected-error {{deleted function}} expected-note@#1 
{{non-trivial destructor}}
 
 // or selects a constructor that is either deleted or not trivial, or
 union U2 {
-    U2() : nt(2) { }
-    NonTrivial nt;
+  U2() : nt(2) { }
+  NonTrivial nt; // #2
 };
-U2 u2; // expected-error {{deleted function}}
+U2 u2; // expected-error {{deleted function}} expected-note@#2 {{non-trivial 
destructor}}
 
 union U3 {
-    U3() = delete;
-    U3(int);
-    NonTrivial nt;
+  U3() = delete;
+  U3(int);
+  NonTrivial nt; // #3
 };
-U3 u3(1); // expected-error {{deleted function}}
+U3 u3(1); // expected-error {{deleted function}} expected-note@#3 
{{non-trivial destructor}}
 
 // or X has a variant member V of class type M (or possibly multi-dimensional 
array thereof) where V has a default member initializer and M has a destructor 
that is non-trivial,
 union U4 {
-    NonTrivial nt = 1;
+  NonTrivial nt = 1; // #4
 };
-U4 u4; // expected-error {{deleted function}}
+U4 u4; // expected-error {{deleted function}} expected-note@#4 {{non-trivial 
destructor}}
 
 union U5 {
   NonTrivial nt;
@@ -44,5 +44,12 @@ union U5 {
 };
 U5 u5;
 
+union U6 {
+  U6() = default;
+  NonTrivial nt;
+  U6* next = nullptr;
+};
+U6 u6;
+
 
 

>From 80e24760503a1935ea8f2d83f34561f95c9cbf52 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.rev...@gmail.com>
Date: Thu, 3 Jul 2025 10:29:19 -0500
Subject: [PATCH 5/5] Test fixup

---
 clang/test/CXX/drs/cwg6xx.cpp               |  8 ++++++--
 clang/test/CXX/special/class.ctor/p5-0x.cpp | 15 ++++++++-------
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index dd54bb5295b56..d7437fab1c183 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -4,7 +4,7 @@
 // RUN: %clang_cc1 -std=c++17 %s 
-verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 
-fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,cxx26 
-fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions 
-fcxx-exceptions -pedantic-errors
 
 #if __cplusplus == 199711L
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -922,7 +922,11 @@ namespace cwg667 { // cwg667: 8
 
   struct B { ~B() = delete; };
   union C { B b; };
-  static_assert(!__is_trivially_destructible(C), ""); // cxx26-error {{failed}}
+  #if __cplusplus > 202302L
+  static_assert(__is_trivially_destructible(C), "");
+  #else
+  static_assert(!__is_trivially_destructible(C), "");
+  #endif
 
   struct D { D(const D&) = delete; };
   struct E : D {};
diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp 
b/clang/test/CXX/special/class.ctor/p5-0x.cpp
index 97a8b035a0705..f00ec4ddc6350 100644
--- a/clang/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11-23 %s -std=c++11 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11-23 %s -std=c++23 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
 // RUN: %clang_cc1 -fsyntax-only -verify=expected %s -std=c++26 
-Wno-deprecated-builtins -Wno-defaulted-function-deleted
 
 struct DefaultedDefCtor1 {};
@@ -24,8 +25,8 @@ int n;
 
 // - X is a union-like class that has a variant member with a non-trivial
 // default constructor,
-union Deleted1a { UserProvidedDefCtor u; }; // until26-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
-Deleted1a d1a; // until26-error {{implicitly-deleted default constructor}}
+union Deleted1a { UserProvidedDefCtor u; }; // cxx11-23-note {{default 
constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has 
a non-trivial default constructor}}
+Deleted1a d1a; // cxx11-23-error {{implicitly-deleted default constructor}}
 union NotDeleted1a { DefaultedDefCtor1 nu; };
 NotDeleted1a nd1a;
 union NotDeleted1b { DefaultedDefCtor2 nu; };
@@ -87,19 +88,19 @@ NotDeleted3i nd3i;
 union Deleted4a {
   const int a;
   const int b;
-  const UserProvidedDefCtor c; // until26-note {{because variant field 'c' has 
a non-trivial default constructor}}
+  const UserProvidedDefCtor c; // cxx11-23-note {{because variant field 'c' 
has a non-trivial default constructor}}
 };
-Deleted4a d4a; // until26-error {{implicitly-deleted default constructor}}
+Deleted4a d4a; // cxx11-23-error {{implicitly-deleted default constructor}}
 union NotDeleted4a { const int a; int b; };
 NotDeleted4a nd4a;
 
 // - X is a non-union class and all members of any anonymous union member are 
of
 // const-qualified type (or array thereof),
 struct Deleted5a {
-  union { const int a; }; // until26-note {{because all data members of an 
anonymous union member are const-qualified}}
+  union { const int a; }; // cxx11-23-note {{because all data members of an 
anonymous union member are const-qualified}}
   union { int b; };
 };
-Deleted5a d5a; // until26-error {{implicitly-deleted default constructor}}
+Deleted5a d5a; // cxx11-23-error {{implicitly-deleted default constructor}}
 struct NotDeleted5a { union { const int a; int b; }; union { const int c; int 
d; }; };
 NotDeleted5a nd5a;
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to