diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 74b0647f38795..caf357e557cec 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 16d42d27d3b4e..b37f93ed9cbb1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9546,14 +9546,32 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( CXXMethodDecl *Decl = SMOR.getMethod(); FieldDecl *Field = Subobj.dyn_cast(); - 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(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. @@ -9569,13 +9587,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( // initializer const auto *RD = cast(Field->getParent()); if (!RD->hasInClassInitializer()) - DiagKind = 4; + DiagKind = NonTrivialDecl; } else { - DiagKind = 4; + DiagKind = NonTrivialDecl; } } - if (DiagKind == -1) + if (DiagKind == NotSet) return false; if (Diagnose) { @@ -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; diff --git a/clang/test/CXX/drs/cwg20xx.cpp b/clang/test/CXX/drs/cwg20xx.cpp index 141a1012aef93..bd233bb09522f 100644 --- a/clang/test/CXX/drs/cwg20xx.cpp +++ b/clang/test/CXX/drs/cwg20xx.cpp @@ -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 struct X; template void f(X&); diff --git a/clang/test/CodeGen/union-non-trivial-member.cpp b/clang/test/CodeGen/union-non-trivial-member.cpp index fdc9fd16911e1..8b055a9970fc7 100644 --- a/clang/test/CodeGen/union-non-trivial-member.cpp +++ b/clang/test/CodeGen/union-non-trivial-member.cpp @@ -15,14 +15,25 @@ 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 @@ -30,8 +41,14 @@ void f() { // 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 diff --git a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp index 4bb012f6e4247..1eb7e3a2dea8b 100644 --- a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp +++ b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp @@ -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