@@ -533,11 +533,61 @@ bool IsConvertibleMoveAssignment(const clang::CXXMethodDecl *method) {
533533 HasFieldWithMoveAssign (parent);
534534}
535535
536+ static bool IsTranslatedCopyAssignment (const clang::CXXMethodDecl *method) {
537+ if (!method->isCopyAssignmentOperator () || method->isDeleted () ||
538+ method->isVirtual ()) {
539+ return false ;
540+ }
541+ return (method->isUserProvided () && IsUserDefinedDecl (method) &&
542+ method->hasBody ()) ||
543+ IsConvertibleCopyAssignment (method);
544+ }
545+
546+ bool HasCopyAssignOperator (const clang::RecordDecl *decl) {
547+ auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
548+ return cxx && llvm::any_of (cxx->methods (), [](auto *method) {
549+ return IsTranslatedCopyAssignment (method) &&
550+ CanUseCopyOrMoveName (method, " copy_assign" );
551+ });
552+ }
553+
554+ bool HasMoveAssignOperator (const clang::RecordDecl *decl) {
555+ auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
556+ return cxx && llvm::any_of (cxx->methods (), [](auto *method) {
557+ return IsConvertibleMoveAssignment (method) && !method->isVirtual () &&
558+ CanUseCopyOrMoveName (method, " move_assign" );
559+ });
560+ }
561+
562+ // Whether a defaulted copy assignment of decl isn't an assignment of a clone
563+ // of the source, which runs the copy constructors of the record and of its
564+ // fields: when the record has a copy constructor, or a field (or element of
565+ // an array field) has a copy assignment operator.
566+ static bool NeedsDefaultedCopyAssignment (const clang::CXXRecordDecl *decl) {
567+ return GetUserDefinedCopyConstructor (decl) ||
568+ llvm::any_of (decl->fields (), [](const clang::FieldDecl *field) {
569+ auto *record =
570+ field->getType ()->getBaseElementTypeUnsafe ()->getAsRecordDecl ();
571+ return record && HasCopyAssignOperator (record);
572+ });
573+ }
574+
575+ bool IsConvertibleCopyAssignment (const clang::CXXMethodDecl *method) {
576+ auto *parent = method->getParent ();
577+ if (!method->isCopyAssignmentOperator () || method->isUserProvided () ||
578+ method->isDeleted () || !method->hasBody () ||
579+ !IsConvertibleImplicitMemberParent (parent)) {
580+ return false ;
581+ }
582+ return NeedsDefaultedCopyAssignment (parent);
583+ }
584+
536585bool IsConvertibleImplicitMember (const clang::CXXMethodDecl *method) {
537586 if (auto *ctor = clang::dyn_cast<clang::CXXConstructorDecl>(method)) {
538587 return IsConvertibleMoveConstructor (ctor);
539588 }
540- return IsConvertibleMoveAssignment (method);
589+ return IsConvertibleMoveAssignment (method) ||
590+ IsConvertibleCopyAssignment (method);
541591}
542592
543593bool IsDefaultedMoveConstructor (const clang::CXXConstructorDecl *ctor) {
@@ -1263,7 +1313,7 @@ bool IsImplicitAssignmentCall(const clang::CallExpr *expr) {
12631313 if (method->isUserProvided () && IsUserDefinedDecl (method)) {
12641314 return false ;
12651315 }
1266- return !IsConvertibleMoveAssignment (method);
1316+ return !IsConvertibleImplicitMember (method);
12671317}
12681318
12691319const clang::CXXRecordDecl *AsLambdaClass (clang::QualType type) {
@@ -1421,7 +1471,7 @@ bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
14211471 return IsUserDefinedDecl (owner);
14221472 }
14231473 if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(callee);
1424- method && IsConvertibleMoveAssignment (method)) {
1474+ method && IsConvertibleImplicitMember (method)) {
14251475 return true ;
14261476 }
14271477 if (!callee->isUserProvided () || !IsUserDefinedDecl (callee)) {
@@ -1554,6 +1604,11 @@ void DefineImplicitMembers(clang::Sema &sema, clang::CXXRecordDecl *decl) {
15541604 !HasDefaultedCopyAssignment (decl)) {
15551605 sema.DefineImplicitMoveAssignment (decl->getLocation (), method);
15561606 }
1607+ if (method->isCopyAssignmentOperator () && !method->isUserProvided () &&
1608+ !method->doesThisDeclarationHaveABody () && !method->isDeleted () &&
1609+ NeedsDefaultedCopyAssignment (decl)) {
1610+ sema.DefineImplicitCopyAssignment (decl->getLocation (), method);
1611+ }
15571612 }
15581613 auto define_defaulted_comparison = [&](clang::FunctionDecl *fn) {
15591614 if (!fn || !IsComparisonOperator (fn) || !fn->isDefaulted () ||
0 commit comments