-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[Clang][Sema] Fix incorrect rejection default construction of union with nontrivial member #82407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Shafik Yaghmour (shafik) ChangesIn 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 Full diff: https://github.com/llvm/llvm-project/pull/82407.diff 4 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5bca2c965c866b..452382eb6c4a1e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -292,6 +292,9 @@ Bug Fixes to C++ Support
was only accepted at namespace scope but not at local function scope.
- Clang no longer tries to call consteval constructors at runtime when they appear in a member initializer.
(`#782154 <https://github.com/llvm/llvm-project/issues/82154>`_`)
+- 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
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 79263bc3ff671d..25a4b4381ca25e 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<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;
diff --git a/clang/test/CodeGen/union-non-trivial-member.cpp b/clang/test/CodeGen/union-non-trivial-member.cpp
index fdc9fd16911e14..8b055a9970fc75 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 c7cdf76d850dbe..141fe96f512471 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 b/c NoState has a brace-or-equal-initializer
+union a {
+ int NoState = 0;
+ Handle CustomState;
+} b;
+} // namespace GH81774
|
// initializer | ||
const auto *RD = cast<CXXRecordDecl>(Field->getParent()); | ||
if (!RD->hasInClassInitializer()) | ||
DiagKind = !Decl ? 0 : 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what is going on here? this is the same value as its 'else' clause, and leaves DiagKind as -1 otherwise? I might suggest making this a single 'if' and getting rid of the 'else' here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have three different states I need to check, I can remove a check by setting DiagKind
unconditionally and then check if(RD->hasInClassInitializer())
instead and in that case set it back to -1
but that does not express the intent as clearly. So I think what I have now is more maintainable although slightly more verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I ran into exactly the same issue that Erich did in noticing that both branches do DiagKind = !Decl ? 0 : 1;
. That two of us ran into the same readability issue suggests that this should be modified to be more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can refactor it like this: MitalAshok@a119d89 and I would suggest changing to an enum for readability: MitalAshok@38ca82e (This can then be extracted out into a static function that returns the enum and each DiagKind = ...
can turn into return ...
, and the if
/else if
ladder can be dismantled)
…ith nontrivial member 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: llvm#81774
e1bf9ef
to
9894851
Compare
…incorrectdelofctoronsomeunionspart2
9894851
to
af9639f
Compare
…incorrectdelofctoronsomeunionspart2
ab431f4
to
3e5db7b
Compare
…incorrectdelofctoronsomeunionspart2
…incorrectdelofctoronsomeunionspart2
This is CWG2084. Could you also add some tests to CXX/drs/ so that www/cxx_dr_status.html can be updated? |
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