Skip to content
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ Bug Fixes to C++ Support
Fixes (`#82941 <https://github.com/llvm/llvm-project/issues/82941>`_),
(`#42411 <https://github.com/llvm/llvm-project/issues/42411>`_), and
(`#18121 <https://github.com/llvm/llvm-project/issues/18121>`_).
- Fix for clang incorrectly rejecting the default construction of a union with
nontrivial member when another member has an initializer.
(`#81774 <https://github.com/llvm/llvm-project/issues/81774>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
18 changes: 15 additions & 3 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9442,9 +9442,21 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(

int DiagKind = -1;

if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
DiagKind = !Decl ? 0 : 1;
else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) {
if (CSM == Sema::CXXDefaultConstructor && 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())
DiagKind = !Decl ? 0 : 1;
} else {
DiagKind = !Decl ? 0 : 1;
}
} else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = 2;
else if (!isAccessible(Subobj, Decl))
DiagKind = 3;
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