[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:56 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (pcc)

<details>
<summary>Changes</summary>

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.


---
Full diff: https://github.com/llvm/llvm-project/pull/94831.diff


3 Files Affected:

- (modified) clang/include/clang/AST/CXXRecordDeclDefinitionBits.def (+3) 
- (modified) clang/lib/AST/DeclCXX.cpp (+21-4) 
- (modified) clang/test/SemaCXX/type-traits.cpp (+8) 


``````````diff
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));

``````````

</details>


https://github.com/llvm/llvm-project/pull/94831


More information about the cfe-commits mailing list