diff options
author | Richard Smith <richard@metafoo.co.uk> | 2020-06-04 19:16:05 -0700 |
---|---|---|
committer | Richard Smith <richard@metafoo.co.uk> | 2020-06-04 19:19:01 -0700 |
commit | c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a (patch) | |
tree | 20a1ad1ab9f3c0b5fc4cf1bdaac96698a3fc6852 /clang/lib | |
parent | c13dd74e311d2ac70dd3ea663d800307d1aa5b6b (diff) | |
download | llvm-c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a.zip llvm-c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a.tar.gz llvm-c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a.tar.bz2 |
PR46209: properly determine whether a copy assignment operator is
trivial.
We previously took a shortcut by assuming that if a subobject had a
trivial copy assignment operator (with a few side-conditions), we would
always invoke it, and could avoid going through overload resolution.
That turns out to not be correct in the presenve of ref-qualifiers (and
also won't be the case for copy-assignments with requires-clauses
either). Use the same logic for lazy declaration of copy-assignments
that we use for all other special member functions.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 38 | ||||
-rw-r--r-- | clang/lib/AST/JSONNodeDumper.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/TextNodeDumper.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 4 |
5 files changed, 35 insertions, 11 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index a2a712e..8b96e20 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2795,7 +2795,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { return CDeclOrErr.takeError(); D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr, DCXX->hasKnownLambdaInternalLinkage()); - } else if (DCXX->isInjectedClassName()) { + } else if (DCXX->isInjectedClassName()) { // We have to be careful to do a similar dance to the one in // Sema::ActOnStartCXXMemberDeclarations const bool DelayTypeCreation = true; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 4d184b5..6f1fd2f 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -84,10 +84,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasInheritedConstructor(false), HasInheritedAssignment(false), NeedOverloadResolutionForCopyConstructor(false), NeedOverloadResolutionForMoveConstructor(false), + NeedOverloadResolutionForCopyAssignment(false), NeedOverloadResolutionForMoveAssignment(false), NeedOverloadResolutionForDestructor(false), DefaultedCopyConstructorIsDeleted(false), DefaultedMoveConstructorIsDeleted(false), + DefaultedCopyAssignmentIsDeleted(false), DefaultedMoveAssignmentIsDeleted(false), DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), HasTrivialSpecialMembersForCall(SMF_All), @@ -435,10 +437,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); // Keep track of the presence of mutable fields. - if (BaseClassDecl->hasMutableFields()) { + if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; - data().NeedOverloadResolutionForCopyConstructor = true; - } if (BaseClassDecl->hasUninitializedReferenceMember()) data().HasUninitializedReferenceMember = true; @@ -511,6 +511,8 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // -- a direct or virtual base class B that cannot be copied/moved [...] // -- a non-static data member of class type M (or array thereof) // that cannot be copied or moved [...] + if (!Subobj->hasSimpleCopyAssignment()) + data().NeedOverloadResolutionForCopyAssignment = true; if (!Subobj->hasSimpleMoveAssignment()) data().NeedOverloadResolutionForMoveAssignment = true; @@ -978,10 +980,8 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Keep track of the presence of mutable fields. - if (Field->isMutable()) { + if (Field->isMutable()) data().HasMutableFields = true; - data().NeedOverloadResolutionForCopyConstructor = true; - } // C++11 [class.union]p8, DR1460: // If X is a union, a non-static data member of X that is not an anonymous @@ -1025,10 +1025,12 @@ void CXXRecordDecl::addedMember(Decl *D) { if (isUnion()) { data().DefaultedCopyConstructorIsDeleted = true; data().DefaultedMoveConstructorIsDeleted = true; + data().DefaultedCopyAssignmentIsDeleted = true; data().DefaultedMoveAssignmentIsDeleted = true; data().DefaultedDestructorIsDeleted = true; data().NeedOverloadResolutionForCopyConstructor = true; data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForCopyAssignment = true; data().NeedOverloadResolutionForMoveAssignment = true; data().NeedOverloadResolutionForDestructor = true; } @@ -1095,8 +1097,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // A defaulted copy/move assignment operator for a class X is defined // as deleted if X has: // -- a non-static data member of reference type - if (T->isReferenceType()) + if (T->isReferenceType()) { + data().DefaultedCopyAssignmentIsDeleted = true; data().DefaultedMoveAssignmentIsDeleted = true; + } // Bitfields of length 0 are also zero-sized, but we already bailed out for // those because they are always unnamed. @@ -1115,6 +1119,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // parameter. data().NeedOverloadResolutionForCopyConstructor = true; data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForCopyAssignment = true; data().NeedOverloadResolutionForMoveAssignment = true; } @@ -1128,6 +1133,8 @@ void CXXRecordDecl::addedMember(Decl *D) { data().DefaultedCopyConstructorIsDeleted = true; if (FieldRec->hasNonTrivialMoveConstructor()) data().DefaultedMoveConstructorIsDeleted = true; + if (FieldRec->hasNonTrivialCopyAssignment()) + data().DefaultedCopyAssignmentIsDeleted = true; if (FieldRec->hasNonTrivialMoveAssignment()) data().DefaultedMoveAssignmentIsDeleted = true; if (FieldRec->hasNonTrivialDestructor()) @@ -1141,6 +1148,8 @@ void CXXRecordDecl::addedMember(Decl *D) { FieldRec->data().NeedOverloadResolutionForCopyConstructor; data().NeedOverloadResolutionForMoveConstructor |= FieldRec->data().NeedOverloadResolutionForMoveConstructor; + data().NeedOverloadResolutionForCopyAssignment |= + FieldRec->data().NeedOverloadResolutionForCopyAssignment; data().NeedOverloadResolutionForMoveAssignment |= FieldRec->data().NeedOverloadResolutionForMoveAssignment; data().NeedOverloadResolutionForDestructor |= @@ -1238,9 +1247,15 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Keep track of the presence of mutable fields. - if (FieldRec->hasMutableFields()) { + if (FieldRec->hasMutableFields()) data().HasMutableFields = true; + + if (Field->isMutable()) { + // Our copy constructor/assignment might call something other than + // the subobject's copy constructor/assignment if it's mutable and of + // class type. data().NeedOverloadResolutionForCopyConstructor = true; + data().NeedOverloadResolutionForCopyAssignment = true; } // C++11 [class.copy]p13: @@ -1296,8 +1311,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // as deleted if X has: // -- a non-static data member of const non-class type (or array // thereof) - if (T.isConstQualified()) + if (T.isConstQualified()) { + data().DefaultedCopyAssignmentIsDeleted = true; data().DefaultedMoveAssignmentIsDeleted = true; + } } // C++14 [meta.unary.prop]p4: @@ -1382,6 +1399,9 @@ void CXXRecordDecl::setCaptures(ArrayRef<LambdaCapture> Captures) { *ToCapture++ = Captures[I]; } + + if (!lambdaIsDefaultConstructibleAndAssignable()) + Data.DefaultedCopyAssignmentIsDeleted = true; } void CXXRecordDecl::setTrivialForCallFlags(CXXMethodDecl *D) { diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 8edfed6..2f7aab0 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -386,6 +386,7 @@ static llvm::json::Object createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) { llvm::json::Object Ret; + FIELD2("simple", hasSimpleCopyAssignment); FIELD2("trivial", hasTrivialCopyAssignment); FIELD2("nonTrivial", hasNonTrivialCopyAssignment); FIELD2("hasConstParam", hasCopyAssignmentWithConstParam); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 1e567e2..72f0ba3 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1663,6 +1663,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { ColorScope Color(OS, ShowColors, DeclKindNameColor); OS << "CopyAssignment"; } + FLAG(hasSimpleCopyAssignment, simple); FLAG(hasTrivialCopyAssignment, trivial); FLAG(hasNonTrivialCopyAssignment, non_trivial); FLAG(hasCopyAssignmentWithConstParam, has_const_param); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a137e6c..ed12b6c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13789,8 +13789,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); - if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) + if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) { + ClassDecl->setImplicitCopyAssignmentIsDeleted(); SetDeclDeleted(CopyAssignment, ClassLoc); + } if (S) PushOnScopeChains(CopyAssignment, S, false); |