aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard@metafoo.co.uk>2020-06-04 19:16:05 -0700
committerRichard Smith <richard@metafoo.co.uk>2020-06-04 19:19:01 -0700
commitc57f8a3a20540fcf9fbf98c0a73f381ec32fce2a (patch)
tree20a1ad1ab9f3c0b5fc4cf1bdaac96698a3fc6852 /clang/lib
parentc13dd74e311d2ac70dd3ea663d800307d1aa5b6b (diff)
downloadllvm-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.cpp2
-rw-r--r--clang/lib/AST/DeclCXX.cpp38
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp1
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp1
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp4
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);