From 5fcaeaddccc0f7e370bf7bebce113d8d52e1b1bd Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Tue, 20 Feb 2024 11:22:39 -0800 Subject: [PATCH] [Clang][Sema] Fix incorrect rejection default construction of union with nontrivial member In 765d8a192180f8f33618087b15c022fe758044af 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: https://github.com/llvm/llvm-project/issues/81774 --- clang/lib/Sema/SemaDeclCXX.cpp | 18 +++++++++++++++--- .../test/CodeGen/union-non-trivial-member.cpp | 17 +++++++++++++++++ clang/test/SemaCXX/cxx0x-nontrivial-union.cpp | 11 +++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 79263bc3ff671..25a4b4381ca25 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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(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; 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 c7cdf76d850db..833642b3d739a 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