Skip to content

Commit 435d084

Browse files
authored
[Clang][Sema] Fix incorrect rejection default construction of union with nontrivial member (#82407)
In 765d8a1 we impelemented a fix for incorrect deletion of default constructors in unions. This fix missed a case and so this PR will extend the fix to cover the additional case. Fixes: #81774
1 parent efda523 commit 435d084

File tree

5 files changed

+69
-12
lines changed

5 files changed

+69
-12
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ Bug Fixes to C++ Support
445445
- Correctly deduce return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319) (#GH161196)
446446
- Fixed a crash in the pre-C++23 warning for attributes before a lambda declarator (#GH161070).
447447
- Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604)
448+
- Fix for clang incorrectly rejecting the default construction of a union with
449+
nontrivial member when another member has an initializer. (#GH81774)
448450

449451
Bug Fixes to AST Handling
450452
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9546,14 +9546,32 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
95469546
CXXMethodDecl *Decl = SMOR.getMethod();
95479547
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
95489548

9549-
int DiagKind = -1;
9550-
9551-
if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
9552-
DiagKind = !Decl ? 0 : 1;
9553-
else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
9554-
DiagKind = 2;
9549+
enum {
9550+
NotSet = -1,
9551+
NoDecl,
9552+
DeletedDecl,
9553+
MultipleDecl,
9554+
InaccessibleDecl,
9555+
NonTrivialDecl
9556+
} DiagKind = NotSet;
9557+
9558+
if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) {
9559+
if (CSM == CXXSpecialMemberKind::DefaultConstructor && Field &&
9560+
Field->getParent()->isUnion()) {
9561+
// [class.default.ctor]p2:
9562+
// A defaulted default constructor for class X is defined as deleted if
9563+
// - X is a union that has a variant member with a non-trivial default
9564+
// constructor and no variant member of X has a default member
9565+
// initializer
9566+
const auto *RD = cast<CXXRecordDecl>(Field->getParent());
9567+
if (RD->hasInClassInitializer())
9568+
return false;
9569+
}
9570+
DiagKind = !Decl ? NoDecl : DeletedDecl;
9571+
} else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
9572+
DiagKind = MultipleDecl;
95559573
else if (!isAccessible(Subobj, Decl))
9556-
DiagKind = 3;
9574+
DiagKind = InaccessibleDecl;
95579575
else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() &&
95589576
!Decl->isTrivial()) {
95599577
// A member of a union must have a trivial corresponding special member.
@@ -9569,13 +9587,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
95699587
// initializer
95709588
const auto *RD = cast<CXXRecordDecl>(Field->getParent());
95719589
if (!RD->hasInClassInitializer())
9572-
DiagKind = 4;
9590+
DiagKind = NonTrivialDecl;
95739591
} else {
9574-
DiagKind = 4;
9592+
DiagKind = NonTrivialDecl;
95759593
}
95769594
}
95779595

9578-
if (DiagKind == -1)
9596+
if (DiagKind == NotSet)
95799597
return false;
95809598

95819599
if (Diagnose) {
@@ -9593,9 +9611,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
95939611
<< /*IsObjCPtr*/ false;
95949612
}
95959613

9596-
if (DiagKind == 1)
9614+
if (DiagKind == DeletedDecl)
95979615
S.NoteDeletedFunction(Decl);
9598-
// FIXME: Explain inaccessibility if DiagKind == 3.
9616+
// FIXME: Explain inaccessibility if DiagKind == InaccessibleDecl.
95999617
}
96009618

96019619
return true;

clang/test/CXX/drs/cwg20xx.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,15 @@ namespace cwg2083 { // cwg2083: partial
401401
#endif
402402
} // namespace cwg2083
403403

404+
namespace cwg2084 { // cwg2084: 3.1
405+
struct S {
406+
S();
407+
};
408+
union U {
409+
S s{}; // cxx98-error {{function definition does not declare parameters}}
410+
} u;
411+
} // namespace cwg2084
412+
404413
namespace cwg2091 { // cwg2091: 10
405414
template<int &> struct X;
406415
template<int &N> void f(X<N>&);

clang/test/CodeGen/union-non-trivial-member.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,40 @@ union UnionNonTrivial {
1515
non_trivial_constructor b{};
1616
};
1717

18+
struct Handle {
19+
Handle(int) {}
20+
};
21+
22+
union UnionNonTrivialEqualInit {
23+
int NoState = 0;
24+
Handle CustomState;
25+
};
26+
1827
void f() {
1928
UnionInt u1;
2029
UnionNonTrivial u2;
30+
UnionNonTrivialEqualInit u3;
2131
}
2232

2333
// CHECK: define dso_local void @_Z1fv()
2434
// CHECK: call void @_ZN8UnionIntC1Ev
2535
// CHECK-NEXT: call void @_ZN15UnionNonTrivialC1Ev
36+
// CHECK-NEXT: call void @_ZN24UnionNonTrivialEqualInitC1Ev
2637

2738
// CHECK: define {{.*}}void @_ZN8UnionIntC1Ev
2839
// CHECK: call void @_ZN8UnionIntC2Ev
2940

3041
// CHECK: define {{.*}}void @_ZN15UnionNonTrivialC1Ev
3142
// CHECK: call void @_ZN15UnionNonTrivialC2Ev
3243

44+
// CHECK: define {{.*}}void @_ZN24UnionNonTrivialEqualInitC1Ev
45+
// CHECK: call void @_ZN24UnionNonTrivialEqualInitC2Ev
46+
3347
// CHECK: define {{.*}}void @_ZN8UnionIntC2Ev
3448
// CHECK: store i32 1000
3549

3650
// CHECK: define {{.*}}void @_ZN15UnionNonTrivialC2Ev
3751
// CHECK: call void @_ZN23non_trivial_constructorC1Ev
52+
53+
// CHECK: define {{.*}}void @_ZN24UnionNonTrivialEqualInitC2Ev
54+
// CHECK: store i32 0

clang/test/SemaCXX/cxx0x-nontrivial-union.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,14 @@ static_assert(U2().b.x == 100, "");
188188
static_assert(U3().b.x == 100, "");
189189

190190
} // namespace GH48416
191+
192+
namespace GH81774 {
193+
struct Handle {
194+
Handle(int) {}
195+
};
196+
// Should be well-formed because NoState has a brace-or-equal-initializer.
197+
union a {
198+
int NoState = 0;
199+
Handle CustomState;
200+
} b;
201+
} // namespace GH81774

0 commit comments

Comments
 (0)