Skip to content
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,8 @@ Bug Fixes to C++ Support
- Correctly deduce return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319) (#GH161196)
- Fixed a crash in the pre-C++23 warning for attributes before a lambda declarator (#GH161070).
- Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604)
- Fix for clang incorrectly rejecting the default construction of a union with
nontrivial member when another member has an initializer. (#GH81774)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
42 changes: 30 additions & 12 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9546,14 +9546,32 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
CXXMethodDecl *Decl = SMOR.getMethod();
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();

int DiagKind = -1;

if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
DiagKind = !Decl ? 0 : 1;
else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = 2;
enum {
NotSet = -1,
NoDecl,
DeletedDecl,
MultipleDecl,
InaccessibleDecl,
NonTrivialDecl
} DiagKind = NotSet;

if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) {
if (CSM == CXXSpecialMemberKind::DefaultConstructor && Field &&
Field->getParent()->isUnion()) {
// [class.default.ctor]p2:
// A defaulted default constructor for class X is defined as deleted if
// - X is a union that has a variant member with a non-trivial default
// constructor and no variant member of X has a default member
// initializer
const auto *RD = cast<CXXRecordDecl>(Field->getParent());
if (RD->hasInClassInitializer())
return false;
}
DiagKind = !Decl ? NoDecl : DeletedDecl;
} else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = MultipleDecl;
else if (!isAccessible(Subobj, Decl))
DiagKind = 3;
DiagKind = InaccessibleDecl;
else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() &&
!Decl->isTrivial()) {
// A member of a union must have a trivial corresponding special member.
Expand All @@ -9569,13 +9587,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
// initializer
const auto *RD = cast<CXXRecordDecl>(Field->getParent());
if (!RD->hasInClassInitializer())
DiagKind = 4;
DiagKind = NonTrivialDecl;
} else {
DiagKind = 4;
DiagKind = NonTrivialDecl;
}
}

if (DiagKind == -1)
if (DiagKind == NotSet)
return false;

if (Diagnose) {
Expand All @@ -9593,9 +9611,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
<< /*IsObjCPtr*/ false;
}

if (DiagKind == 1)
if (DiagKind == DeletedDecl)
S.NoteDeletedFunction(Decl);
// FIXME: Explain inaccessibility if DiagKind == 3.
// FIXME: Explain inaccessibility if DiagKind == InaccessibleDecl.
}

return true;
Expand Down
9 changes: 9 additions & 0 deletions clang/test/CXX/drs/cwg20xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ namespace cwg2083 { // cwg2083: partial
#endif
} // namespace cwg2083

namespace cwg2084 { // cwg2084: 3.1
struct S {
S();
};
union U {
S s{}; // cxx98-error {{function definition does not declare parameters}}
} u;
} // namespace cwg2084

namespace cwg2091 { // cwg2091: 10
template<int &> struct X;
template<int &N> void f(X<N>&);
Expand Down
17 changes: 17 additions & 0 deletions clang/test/CodeGen/union-non-trivial-member.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,40 @@ union UnionNonTrivial {
non_trivial_constructor b{};
};

struct Handle {
Handle(int) {}
};

union UnionNonTrivialEqualInit {
int NoState = 0;
Handle CustomState;
};

void f() {
UnionInt u1;
UnionNonTrivial u2;
UnionNonTrivialEqualInit u3;
}

// CHECK: define dso_local void @_Z1fv()
// CHECK: call void @_ZN8UnionIntC1Ev
// CHECK-NEXT: call void @_ZN15UnionNonTrivialC1Ev
// CHECK-NEXT: call void @_ZN24UnionNonTrivialEqualInitC1Ev

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

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

// CHECK: define {{.*}}void @_ZN24UnionNonTrivialEqualInitC1Ev
// CHECK: call void @_ZN24UnionNonTrivialEqualInitC2Ev

// CHECK: define {{.*}}void @_ZN8UnionIntC2Ev
// CHECK: store i32 1000

// CHECK: define {{.*}}void @_ZN15UnionNonTrivialC2Ev
// CHECK: call void @_ZN23non_trivial_constructorC1Ev

// CHECK: define {{.*}}void @_ZN24UnionNonTrivialEqualInitC2Ev
// CHECK: store i32 0
11 changes: 11 additions & 0 deletions clang/test/SemaCXX/cxx0x-nontrivial-union.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,14 @@ static_assert(U2().b.x == 100, "");
static_assert(U3().b.x == 100, "");

} // namespace GH48416

namespace GH81774 {
struct Handle {
Handle(int) {}
};
// Should be well-formed because NoState has a brace-or-equal-initializer.
union a {
int NoState = 0;
Handle CustomState;
} b;
} // namespace GH81774