================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits