[clang] [P3074] Partial implementation of support for trivial unions (PR #146815)
Barry Revzin via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 3 12:14:33 PDT 2025
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.revzin at gmail.com>
Date: Fri, 27 Jun 2025 17:29:45 -0500
Subject: [PATCH 1/8] [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.revzin at gmail.com>
Date: Wed, 2 Jul 2025 23:04:59 -0500
Subject: [PATCH 2/8] 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.revzin at gmail.com>
Date: Wed, 2 Jul 2025 23:27:25 -0500
Subject: [PATCH 3/8] 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.revzin at gmail.com>
Date: Thu, 3 Jul 2025 10:26:30 -0500
Subject: [PATCH 4/8] 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.revzin at gmail.com>
Date: Thu, 3 Jul 2025 10:29:19 -0500
Subject: [PATCH 5/8] 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;
>From 9972d7ef237d9621dcebe80a049700ef6ab464b9 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.revzin at gmail.com>
Date: Thu, 3 Jul 2025 10:52:17 -0500
Subject: [PATCH 6/8] Uh... this cannot be right
---
clang/lib/Sema/SemaDeclCXX.cpp | 14 ++++++++++++--
clang/test/CXX/special/class.dtor/p7.cpp | 16 +++++++++++++++-
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 089ffa1d2dea2..0edb40163bc80 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9545,7 +9545,6 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
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:
@@ -9556,8 +9555,19 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
// multi-dimensional array thereof) where V has a default member initializer
// and M has a destructor that is non-trivial,
+ RecordDecl *Parent = Field->getParent();
+ while (Parent &&
+ (Parent->isAnonymousStructOrUnion() ||
+ (Parent->isUnion() && Parent->getIdentifier() == nullptr))) {
+ if (auto RD = dyn_cast_or_null<RecordDecl>(Parent->getParent())) {
+ Parent = RD;
+ } else {
+ break;
+ }
+ }
+
Sema::SpecialMemberOverloadResult SMOR =
- S.LookupSpecialMember(dyn_cast<CXXRecordDecl>(Field->getParent()),
+ S.LookupSpecialMember(dyn_cast<CXXRecordDecl>(Parent),
CXXSpecialMemberKind::DefaultConstructor, false,
false, false, false, false);
if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Success) {
diff --git a/clang/test/CXX/special/class.dtor/p7.cpp b/clang/test/CXX/special/class.dtor/p7.cpp
index c19bfcc5b119e..480fa0a989abb 100644
--- a/clang/test/CXX/special/class.dtor/p7.cpp
+++ b/clang/test/CXX/special/class.dtor/p7.cpp
@@ -52,4 +52,18 @@ union U6 {
U6 u6;
-
+struct DeletedDtor {
+ ~DeletedDtor() = delete; // expected-note 2 {{deleted here}}
+};
+union B1 {
+ B1();
+ DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
+};
+B1 b1; // expected-error {{deleted function}}
+union B2 {
+ B2();
+ union { // expected-note {{deleted destructor}}
+ DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
+ };
+};
+B2 b2; // expected-error {{deleted function}}
\ No newline at end of file
>From c2f3a05826cb6601b125a94af9c7d2a8861dd79e Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.revzin at gmail.com>
Date: Thu, 3 Jul 2025 10:56:39 -0500
Subject: [PATCH 7/8] More test fixups
---
clang/test/CXX/special/class.ctor/p6-0x.cpp | 24 ++++++++++-----------
clang/test/CXX/special/class.dtor/p5-0x.cpp | 4 ++--
clang/test/CXX/special/class.dtor/p7.cpp | 2 +-
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/clang/test/CXX/special/class.ctor/p6-0x.cpp b/clang/test/CXX/special/class.ctor/p6-0x.cpp
index 6ce1b06841ab4..3ad7ae32c1314 100644
--- a/clang/test/CXX/special/class.ctor/p6-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p6-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11-23 %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
@@ -16,8 +16,8 @@ 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(); // 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}}
+ friend constexpr NonConstexpr1::NonConstexpr1(); // cxx11-23-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}}
+ friend constexpr NonConstexpr2::NonConstexpr2(); // cxx11-23-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}}
};
@@ -37,10 +37,10 @@ struct Member {
constexpr Member(int&a) : a(a) {}
int &a;
};
-struct NonConstexpr4 { // until26-note {{here}} cxx26-note {{non-constexpr constructor}}
+struct NonConstexpr4 { // cxx11-23-note {{here}} cxx26-note {{non-constexpr constructor}}
Member m;
};
-constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} until26-note {{non-constexpr constructor 'NonConstexpr4'}} cxx26-note {{in call to}}
+constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} cxx11-23-note {{non-constexpr constructor 'NonConstexpr4'}} cxx26-note {{in call to}}
struct Constexpr3 {
constexpr Constexpr3() : m(n) {}
Member m;
@@ -55,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(); // until26-error {{non-constexpr declaration of 'A' follows constexpr declaration}} cxx26-error {{missing exception specification}}
+ friend A::A(); // cxx11-23-error {{non-constexpr declaration of 'A' follows constexpr declaration}} cxx26-error {{missing exception specification}}
};
namespace UnionCtors {
- union A { // until26-note {{here}}
+ union A { // cxx11-23-note {{here}}
int a;
int b;
};
@@ -81,7 +81,7 @@ namespace UnionCtors {
int d = 5;
};
};
- struct E { // until26-note {{here}}
+ struct E { // cxx11-23-note {{here}}
union {
int a;
int b;
@@ -89,11 +89,11 @@ namespace UnionCtors {
};
struct Test {
- friend constexpr A::A() noexcept; // until26-error {{follows non-constexpr declaration}}
+ friend constexpr A::A() noexcept; // cxx11-23-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; // until26-error {{follows non-constexpr declaration}}
+ friend constexpr E::E() noexcept; // cxx11-23-error {{follows non-constexpr declaration}}
};
}
@@ -124,6 +124,6 @@ namespace PR48763 {
struct G { G(); };
struct H : D { using D::D; H(int); G g; };
- union V { H h; }; // until26-note {{field 'h' has a non-trivial default constructor}}
- V v; // until26-error {{deleted}}
+ union V { H h; }; // cxx11-23-note {{field 'h' has a non-trivial default constructor}}
+ V v; // cxx11-23-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 b8ebb41b24ed7..655ffda48dcae 100644
--- a/clang/test/CXX/special/class.dtor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.dtor/p5-0x.cpp
@@ -1,11 +1,11 @@
-// 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++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 4+ {{deleted here}}
+ ~DeletedDtor() = delete; // expected-note 5 {{deleted here}}
};
class InaccessibleDtor {
~InaccessibleDtor() = default;
diff --git a/clang/test/CXX/special/class.dtor/p7.cpp b/clang/test/CXX/special/class.dtor/p7.cpp
index 480fa0a989abb..5324dfd13faa9 100644
--- a/clang/test/CXX/special/class.dtor/p7.cpp
+++ b/clang/test/CXX/special/class.dtor/p7.cpp
@@ -66,4 +66,4 @@ union B2 {
DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
};
};
-B2 b2; // expected-error {{deleted function}}
\ No newline at end of file
+B2 b2; // expected-error {{deleted function}}
>From 1283ddb76500a8858e80859c3031199484387b58 Mon Sep 17 00:00:00 2001
From: Barry Revzin <barry.revzin at gmail.com>
Date: Thu, 3 Jul 2025 14:14:08 -0500
Subject: [PATCH 8/8] What, really, this is good?
---
clang/lib/Sema/SemaDeclCXX.cpp | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0edb40163bc80..9661bad658e9c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9566,18 +9566,22 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
}
}
- Sema::SpecialMemberOverloadResult SMOR =
- S.LookupSpecialMember(dyn_cast<CXXRecordDecl>(Parent),
- 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;
- }
+ auto ParentDecl = dyn_cast<CXXRecordDecl>(Parent);
+ if (ParentDecl->getDefinition() && !ParentDecl->isDependentContext() &&
+ !ParentDecl->isBeingDefined()) {
+ Sema::SpecialMemberOverloadResult SMOR = S.LookupSpecialMember(
+ ParentDecl, 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 (!Ctor->isUserProvided() && !Field->hasInClassInitializer()) {
+ return false;
+ }
}
}
}
More information about the cfe-commits
mailing list