Skip to content

Commit 40290a9

Browse files
committed
[P3074] Implementing part of trivial unions
1 parent ff4faaa commit 40290a9

File tree

6 files changed

+63
-42
lines changed

6 files changed

+63
-42
lines changed

clang/lib/AST/DeclCXX.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
12171217
// those because they are always unnamed.
12181218
bool IsZeroSize = Field->isZeroSize(Context);
12191219

1220+
// P3074
1221+
const bool TrivialUnion = Context.getLangOpts().CPlusPlus26 && isUnion();
1222+
12201223
if (const auto *RecordTy = T->getAs<RecordType>()) {
12211224
auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
12221225
if (FieldRec->getDefinition()) {
@@ -1277,7 +1280,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
12771280
// -- for all the non-static data members of its class that are of
12781281
// class type (or array thereof), each such class has a trivial
12791282
// default constructor.
1280-
if (!FieldRec->hasTrivialDefaultConstructor())
1283+
if (!FieldRec->hasTrivialDefaultConstructor() && !TrivialUnion)
12811284
data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
12821285

12831286
// C++0x [class.copy]p13:
@@ -1315,9 +1318,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
13151318
if (!FieldRec->hasTrivialMoveAssignment())
13161319
data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
13171320

1318-
if (!FieldRec->hasTrivialDestructor())
1321+
if (!FieldRec->hasTrivialDestructor() && !TrivialUnion)
13191322
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
1320-
if (!FieldRec->hasTrivialDestructorForCall())
1323+
if (!FieldRec->hasTrivialDestructorForCall() && !TrivialUnion)
13211324
data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
13221325
if (!FieldRec->hasIrrelevantDestructor())
13231326
data().HasIrrelevantDestructor = false;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9511,6 +9511,15 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
95119511
CXXMethodDecl *Decl = SMOR.getMethod();
95129512
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
95139513

9514+
// P3074: default ctor and dtor for unions are not deleted, regardless of
9515+
// whether the underlying fields have non-trivial or deleted versions of those
9516+
// members
9517+
if (S.Context.getLangOpts().CPlusPlus26)
9518+
if (Field && Field->getParent()->isUnion() &&
9519+
(CSM == CXXSpecialMemberKind::DefaultConstructor ||
9520+
CSM == CXXSpecialMemberKind::Destructor))
9521+
return false;
9522+
95149523
int DiagKind = -1;
95159524

95169525
if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
@@ -9774,7 +9783,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
97749783

97759784
// At least one member in each anonymous union must be non-const
97769785
if (CSM == CXXSpecialMemberKind::DefaultConstructor &&
9777-
AllVariantFieldsAreConst && !FieldRecord->field_empty()) {
9786+
AllVariantFieldsAreConst && !FieldRecord->field_empty() &&
9787+
!S.Context.getLangOpts().CPlusPlus26) {
97789788
if (Diagnose)
97799789
S.Diag(FieldRecord->getLocation(),
97809790
diag::note_deleted_default_ctor_all_const)
@@ -9804,6 +9814,10 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
98049814
// default constructor. Don't do that.
98059815
if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() &&
98069816
AllFieldsAreConst) {
9817+
9818+
if (S.Context.getLangOpts().CPlusPlus26)
9819+
return false;
9820+
98079821
bool AnyFields = false;
98089822
for (auto *F : MD->getParent()->fields())
98099823
if ((AnyFields = !F->isUnnamedBitField()))

clang/test/CXX/drs/cwg6xx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,cxx11-20,cxx98-17,cxx11-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
55
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx11-20,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
66
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
7-
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
7+
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,cxx26 -fexceptions -fcxx-exceptions -pedantic-errors
88

99
#if __cplusplus == 199711L
1010
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -922,7 +922,7 @@ namespace cwg667 { // cwg667: 8
922922

923923
struct B { ~B() = delete; };
924924
union C { B b; };
925-
static_assert(!__is_trivially_destructible(C), "");
925+
static_assert(!__is_trivially_destructible(C), ""); // cxx26-error {{failed}}
926926

927927
struct D { D(const D&) = delete; };
928928
struct E : D {};

clang/test/CXX/special/class.ctor/p5-0x.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-deprecated-builtins -Wno-defaulted-function-deleted
1+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11 -Wno-deprecated-builtins -Wno-defaulted-function-deleted
2+
// RUN: %clang_cc1 -fsyntax-only -verify=expected %s -std=c++26 -Wno-deprecated-builtins -Wno-defaulted-function-deleted
23

34
struct DefaultedDefCtor1 {};
45
struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
@@ -23,8 +24,8 @@ int n;
2324

2425
// - X is a union-like class that has a variant member with a non-trivial
2526
// default constructor,
26-
union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{default constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has a non-trivial default constructor}}
27-
Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}}
27+
union Deleted1a { UserProvidedDefCtor u; }; // until26-note {{default constructor of 'Deleted1a' is implicitly deleted because variant field 'u' has a non-trivial default constructor}}
28+
Deleted1a d1a; // until26-error {{implicitly-deleted default constructor}}
2829
union NotDeleted1a { DefaultedDefCtor1 nu; };
2930
NotDeleted1a nd1a;
3031
union NotDeleted1b { DefaultedDefCtor2 nu; };
@@ -86,19 +87,19 @@ NotDeleted3i nd3i;
8687
union Deleted4a {
8788
const int a;
8889
const int b;
89-
const UserProvidedDefCtor c; // expected-note {{because variant field 'c' has a non-trivial default constructor}}
90+
const UserProvidedDefCtor c; // until26-note {{because variant field 'c' has a non-trivial default constructor}}
9091
};
91-
Deleted4a d4a; // expected-error {{implicitly-deleted default constructor}}
92+
Deleted4a d4a; // until26-error {{implicitly-deleted default constructor}}
9293
union NotDeleted4a { const int a; int b; };
9394
NotDeleted4a nd4a;
9495

9596
// - X is a non-union class and all members of any anonymous union member are of
9697
// const-qualified type (or array thereof),
9798
struct Deleted5a {
98-
union { const int a; }; // expected-note {{because all data members of an anonymous union member are const-qualified}}
99+
union { const int a; }; // until26-note {{because all data members of an anonymous union member are const-qualified}}
99100
union { int b; };
100101
};
101-
Deleted5a d5a; // expected-error {{implicitly-deleted default constructor}}
102+
Deleted5a d5a; // until26-error {{implicitly-deleted default constructor}}
102103
struct NotDeleted5a { union { const int a; int b; }; union { const int c; int d; }; };
103104
NotDeleted5a nd5a;
104105

clang/test/CXX/special/class.ctor/p6-0x.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
1+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,until26 %s -std=c++11
2+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx26 %s -std=c++26
23

34
// Implicitly-defined default constructors are constexpr if the implicit
45
// definition would be.
@@ -15,8 +16,9 @@ constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call construct
1516
constexpr int nc2_a = NonConstexpr2().nl.a; // ok
1617
constexpr int nc2a_a = NonConstexpr2a().a; // ok
1718
struct Helper {
18-
friend constexpr NonConstexpr1::NonConstexpr1(); // expected-error {{follows non-constexpr declaration}}
19-
friend constexpr NonConstexpr2::NonConstexpr2(); // expected-error {{follows non-constexpr declaration}}
19+
friend constexpr NonConstexpr1::NonConstexpr1(); // until26-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}}
20+
friend constexpr NonConstexpr2::NonConstexpr2(); // until26-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}}
21+
2022
};
2123

2224
struct Constexpr1 {};
@@ -31,14 +33,14 @@ constexpr Constexpr2 c2 = Constexpr2(); // ok
3133

3234
int n;
3335
struct Member {
34-
Member() : a(n) {}
36+
Member() : a(n) {} // cxx26-note {{here}}
3537
constexpr Member(int&a) : a(a) {}
3638
int &a;
3739
};
38-
struct NonConstexpr4 { // expected-note {{here}}
40+
struct NonConstexpr4 { // until26-note {{here}} cxx26-note {{non-constexpr constructor}}
3941
Member m;
4042
};
41-
constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}}
43+
constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} until26-note {{non-constexpr constructor 'NonConstexpr4'}} cxx26-note {{in call to}}
4244
struct Constexpr3 {
4345
constexpr Constexpr3() : m(n) {}
4446
Member m;
@@ -53,11 +55,11 @@ constexpr Constexpr4 c4 = Constexpr4(); // ok
5355
// This rule breaks some legal C++98 programs!
5456
struct A {}; // expected-note {{here}}
5557
struct B {
56-
friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows constexpr declaration}}
58+
friend A::A(); // until26-error {{non-constexpr declaration of 'A' follows constexpr declaration}} cxx26-error {{missing exception specification}}
5759
};
5860

5961
namespace UnionCtors {
60-
union A { // expected-note {{here}}
62+
union A { // until26-note {{here}}
6163
int a;
6264
int b;
6365
};
@@ -79,19 +81,19 @@ namespace UnionCtors {
7981
int d = 5;
8082
};
8183
};
82-
struct E { // expected-note {{here}}
84+
struct E { // until26-note {{here}}
8385
union {
8486
int a;
8587
int b;
8688
};
8789
};
8890

8991
struct Test {
90-
friend constexpr A::A() noexcept; // expected-error {{follows non-constexpr declaration}}
92+
friend constexpr A::A() noexcept; // until26-error {{follows non-constexpr declaration}}
9193
friend constexpr B::B() noexcept;
9294
friend constexpr C::C() noexcept;
9395
friend constexpr D::D() noexcept;
94-
friend constexpr E::E() noexcept; // expected-error {{follows non-constexpr declaration}}
96+
friend constexpr E::E() noexcept; // until26-error {{follows non-constexpr declaration}}
9597
};
9698
}
9799

@@ -122,6 +124,6 @@ namespace PR48763 {
122124

123125
struct G { G(); };
124126
struct H : D { using D::D; H(int); G g; };
125-
union V { H h; }; // expected-note {{field 'h' has a non-trivial default constructor}}
126-
V v; // expected-error {{deleted}}
127+
union V { H h; }; // until26-note {{field 'h' has a non-trivial default constructor}}
128+
V v; // until26-error {{deleted}}
127129
}

clang/test/CXX/special/class.dtor/p5-0x.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// RUN: %clang_cc1 -verify -std=c++11 %s -Wno-defaulted-function-deleted -triple x86_64-linux-gnu
1+
// RUN: %clang_cc1 -verify=expected,until26 -std=c++11 %s -Wno-defaulted-function-deleted -triple x86_64-linux-gnu
2+
// RUN: %clang_cc1 -verify=expected -std=c++26 %s -Wno-defaulted-function-deleted -triple x86_64-linux-gnu
23

34
struct NonTrivDtor {
45
~NonTrivDtor();
56
};
67
struct DeletedDtor {
7-
~DeletedDtor() = delete; // expected-note 5 {{deleted here}}
8+
~DeletedDtor() = delete; // expected-note 4+ {{deleted here}}
89
};
910
class InaccessibleDtor {
1011
~InaccessibleDtor() = default;
@@ -16,28 +17,28 @@ class InaccessibleDtor {
1617
// destructor.
1718
union A1 {
1819
A1();
19-
NonTrivDtor n; // expected-note {{destructor of 'A1' is implicitly deleted because variant field 'n' has a non-trivial destructor}}
20+
NonTrivDtor n; // until26-note {{destructor of 'A1' is implicitly deleted because variant field 'n' has a non-trivial destructor}}
2021
};
21-
A1 a1; // expected-error {{deleted function}}
22+
A1 a1; // until26-error {{deleted function}}
2223
struct A2 {
2324
A2();
2425
union {
25-
NonTrivDtor n; // expected-note {{because variant field 'n' has a non-trivial destructor}}
26+
NonTrivDtor n; // until26-note {{because variant field 'n' has a non-trivial destructor}}
2627
};
2728
};
28-
A2 a2; // expected-error {{deleted function}}
29+
A2 a2; // until26-error {{deleted function}}
2930
union A3 {
3031
A3();
31-
NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a non-trivial destructor}}
32+
NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a non-trivial destructor}}
3233
};
33-
A3 a3; // expected-error {{deleted function}}
34+
A3 a3; // until26-error {{deleted function}}
3435
struct A4 {
3536
A4();
3637
union {
37-
NonTrivDtor n[3]; // expected-note {{because variant field 'n' has a non-trivial destructor}}
38+
NonTrivDtor n[3]; // until26-note {{because variant field 'n' has a non-trivial destructor}}
3839
};
3940
};
40-
A4 a4; // expected-error {{deleted function}}
41+
A4 a4; // until26-error {{deleted function}}
4142

4243
// -- any of the non-static data members has class type M (or array thereof) and
4344
// M has a deleted or inaccessible destructor.
@@ -63,18 +64,18 @@ struct B4 {
6364
B4 b4; // expected-error {{deleted function}}
6465
union B5 {
6566
B5();
66-
union { // expected-note-re {{because field 'B5::(anonymous union at {{.+}})' has a deleted destructor}}
67-
DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
67+
union { // until26-note-re {{because field 'B5::(anonymous union at {{.+}})' has a deleted destructor}}
68+
DeletedDtor a; // until26-note {{because field 'a' has a deleted destructor}}
6869
};
6970
};
70-
B5 b5; // expected-error {{deleted function}}
71+
B5 b5; // until26-error {{deleted function}}
7172
union B6 {
7273
B6();
73-
union { // expected-note-re {{because field 'B6::(anonymous union at {{.+}})' has a deleted destructor}}
74-
InaccessibleDtor a; // expected-note {{because field 'a' has an inaccessible destructor}}
74+
union { // until26-note-re {{because field 'B6::(anonymous union at {{.+}})' has a deleted destructor}}
75+
InaccessibleDtor a; // until26-note {{because field 'a' has an inaccessible destructor}}
7576
};
7677
};
77-
B6 b6; // expected-error {{deleted function}}
78+
B6 b6; // until26-error {{deleted function}}
7879

7980
// -- any direct or virtual base class has a deleted or inaccessible destructor.
8081
struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} expected-note {{base class 'DeletedDtor' has a deleted destructor}}

0 commit comments

Comments
 (0)