[clang] [Clang] Implement the core language parts of P2786 - Trivial relocation (PR #127636)

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 24 05:41:58 PST 2025


================
@@ -7258,6 +7261,228 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
   }
 }
 
+static bool hasSuitableConstructorForRelocation(CXXRecordDecl *D,
+                                                bool AllowUserDefined) {
+  assert(D->hasDefinition() && !D->isInvalidDecl());
+
+  bool HasDeletedMoveConstructor = false;
+  bool HasDeletedCopyConstructor = false;
+  bool HasMoveConstructor = D->needsImplicitMoveConstructor();
+  bool HasCopyConstructor = D->needsImplicitCopyConstructor();
+  bool HasDefaultedMoveConstructor = D->needsImplicitMoveConstructor();
+  bool HasDefaultedCopyConstructor = D->needsImplicitCopyConstructor();
+
+  for (const Decl *D : D->decls()) {
+    auto *MD = dyn_cast<CXXConstructorDecl>(D);
+    if (!MD || MD->isIneligibleOrNotSelected())
+      continue;
+
+    if (MD->isMoveConstructor()) {
+      HasMoveConstructor = true;
+      if (MD->isDefaulted())
+        HasDefaultedMoveConstructor = true;
+      if (MD->isDeleted())
+        HasDeletedMoveConstructor = true;
+    } else if (MD->isCopyConstructor()) {
+      HasCopyConstructor = true;
+      if (MD->isDefaulted())
+        HasDefaultedCopyConstructor = true;
+      if (MD->isDeleted())
+        HasDeletedCopyConstructor = true;
+    }
+  }
+
+  if (HasMoveConstructor)
+    return !HasDeletedMoveConstructor &&
+           (AllowUserDefined ? true : HasDefaultedMoveConstructor);
+  return HasCopyConstructor && !HasDeletedCopyConstructor &&
+         (AllowUserDefined ? true : HasDefaultedCopyConstructor);
+}
+
+static bool
+hasSuitableMoveAssignmentOperatorForRelocation(CXXRecordDecl *D,
+                                               bool AllowUserDefined) {
+  assert(D->hasDefinition() && !D->isInvalidDecl());
+
+  if (D->hasExplicitlyDeletedMoveAssignment())
+    return false;
+
+  bool HasDeletedMoveAssignment = false;
+  bool HasDeletedCopyAssignment = false;
+  bool HasMoveAssignment = D->needsImplicitMoveAssignment();
+  bool HasDefaultedMoveAssignment = D->needsImplicitMoveAssignment();
+  bool HasDefaultedCopyAssignment = D->needsImplicitCopyAssignment();
+
+  for (const Decl *D : D->decls()) {
+    auto *MD = dyn_cast<CXXMethodDecl>(D);
+    if (!MD || MD->isIneligibleOrNotSelected())
+      continue;
+
+    if (MD->isMoveAssignmentOperator()) {
+      HasMoveAssignment = true;
+      if (MD->isDefaulted())
+        HasDefaultedMoveAssignment = true;
+      if (MD->isDeleted())
+        HasDeletedMoveAssignment = true;
+    } else if (MD->isCopyAssignmentOperator()) {
+      if (MD->isDefaulted())
+        HasDefaultedCopyAssignment = true;
+      if (MD->isDeleted())
+        HasDeletedCopyAssignment = true;
+    }
+  }
+
+  if (HasMoveAssignment)
+    return !HasDeletedMoveAssignment &&
+           (AllowUserDefined ? true : HasDefaultedMoveAssignment);
+  return !HasDeletedCopyAssignment &&
+         (AllowUserDefined ? true : HasDefaultedCopyAssignment);
+}
+
+static bool isDefaultMovable(CXXRecordDecl *D) {
+  if (!hasSuitableConstructorForRelocation(D, /*AllowUserDefined*/ false))
+    return false;
+
+  if (!hasSuitableMoveAssignmentOperatorForRelocation(
+          D, /*AllowUserDefined*/ false))
+    return false;
+
+  const auto *Dtr = D->getDestructor();
+  if (!Dtr)
+    return true;
+
+  if (Dtr->isUserProvided() && (!Dtr->isDefaulted() || Dtr->isDeleted()))
+    return false;
+
+  return !Dtr->isDeleted();
+}
+
+static bool hasDeletedDestructor(CXXRecordDecl *D) {
----------------
Fznamznon wrote:

Does it make sense to make `hasDeletedDestructor` a method of `CXXRecordDecl`? Maybe it will end up bein useful around codebase.

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


More information about the cfe-commits mailing list