[clang] Sema: Fix CXXRecordDecl::isTriviallyCopyable() for classes with all deleted special functions. (PR #94831)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 7 20:14:28 PDT 2024
https://github.com/pcc created https://github.com/llvm/llvm-project/pull/94831
C++17 added the following requirement for a class to be trivially
copyable: "that has at least one non-deleted copy constructor,
move constructor, copy assignment operator, or move assignment
operator". However, this was not implemented. Fix it.
>From f725de0cd89b0dd90ce5209cb6b3d9632a52f3c9 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <pcc at google.com>
Date: Fri, 7 Jun 2024 20:14:15 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
=?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.6-beta.1
---
.../clang/AST/CXXRecordDeclDefinitionBits.def | 3 +++
clang/lib/AST/DeclCXX.cpp | 25 ++++++++++++++++---
clang/test/SemaCXX/type-traits.cpp | 8 ++++++
3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
index cdf0804680ad0..55cd45348d29d 100644
--- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
+++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
@@ -249,4 +249,7 @@ FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR)
/// base classes or fields have a no-return destructor
FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE)
+/// The special members of this class which were deleted.
+FIELD(HasDeletedSpecialMembers, 6, MERGE_OR)
+
#undef FIELD
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7f2c786547b9b..a3de4d3654006 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -109,9 +109,9 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- IsAnyDestructorNoReturn(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
- HasODRHash(false), Definition(D) {}
+ IsAnyDestructorNoReturn(false), HasDeletedSpecialMembers(0),
+ IsLambda(false), IsParsingBaseSpecifiers(false),
+ ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
@@ -586,6 +586,14 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
if (hasNonTrivialMoveAssignment()) return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor()) return false;
+ // C++17 [class]p6: that has at least one non-deleted copy constructor, move
+ // constructor, copy assignment operator, or move assignment operator,
+ if (getASTContext().getLangOpts().CPlusPlus17 &&
+ (data().HasDeletedSpecialMembers &
+ (SMF_CopyAssignment | SMF_CopyConstructor | SMF_MoveAssignment |
+ SMF_MoveConstructor)) == (SMF_CopyAssignment | SMF_CopyConstructor |
+ SMF_MoveAssignment | SMF_MoveConstructor))
+ return false;
return true;
}
@@ -1446,7 +1454,10 @@ void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD,
// out whether it's trivial yet (not until we get to the end of the
// class). We'll handle this method in
// finishedDefaultedOrDeletedMember.
- } else if (MD->isTrivial()) {
+ return;
+ }
+
+ if (MD->isTrivial()) {
data().HasTrivialSpecialMembers |= SMKind;
data().HasTrivialSpecialMembersForCall |= SMKind;
} else if (MD->isTrivialForCall()) {
@@ -1462,6 +1473,10 @@ void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD,
if (!MD->isUserProvided())
data().DeclaredNonTrivialSpecialMembersForCall |= SMKind;
}
+
+ if (MD->isDeleted()) {
+ data().HasDeletedSpecialMembers |= SMKind;
+ }
}
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
@@ -1499,6 +1514,8 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
data().HasTrivialSpecialMembers |= SMKind;
else
data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ if (D->isDeleted())
+ data().HasDeletedSpecialMembers |= SMKind;
}
}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index d40605f56f1ed..27b0d204d5690 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1377,7 +1377,11 @@ void is_trivial2()
static_assert(__is_trivial(UnionAr));
static_assert(__is_trivial(TrivialStruct));
static_assert(__is_trivial(AllDefaulted));
+#if __cplusplus >= 201703L
+ static_assert(!__is_trivial(AllDeleted));
+#else
static_assert(__is_trivial(AllDeleted));
+#endif
static_assert(!__is_trivial(void));
static_assert(!__is_trivial(NonTrivialStruct));
@@ -1419,7 +1423,11 @@ void is_trivially_copyable2()
static_assert(__is_trivially_copyable(TrivialStruct));
static_assert(__is_trivially_copyable(NonTrivialStruct));
static_assert(__is_trivially_copyable(AllDefaulted));
+#if __cplusplus >= 201703L
+ static_assert(!__is_trivially_copyable(AllDeleted));
+#else
static_assert(__is_trivially_copyable(AllDeleted));
+#endif
static_assert(!__is_trivially_copyable(void));
static_assert(!__is_trivially_copyable(SuperNonTrivialStruct));
More information about the cfe-commits
mailing list