Store on the CXXRecordDecl whether the class has, or would have, a copy
constructor/assignment operator with a const-qualified parameter type. The
prior method for determining this incorrectly used overload resolution.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168775 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 906cc3b..054cd96 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1950,6 +1950,14 @@
ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment;
ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment;
ToData.DeclaredDestructor = FromData.DeclaredDestructor;
+ ToData.ImplicitCopyConstructorHasConstParam
+ = FromData.ImplicitCopyConstructorHasConstParam;
+ ToData.ImplicitCopyAssignmentHasConstParam
+ = FromData.ImplicitCopyAssignmentHasConstParam;
+ ToData.HasDeclaredCopyConstructorWithConstParam
+ = FromData.HasDeclaredCopyConstructorWithConstParam;
+ ToData.HasDeclaredCopyAssignmentWithConstParam
+ = FromData.HasDeclaredCopyAssignmentWithConstParam;
ToData.FailedImplicitMoveConstructor
= FromData.FailedImplicitMoveConstructor;
ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d661aa0..a3c0bab 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -55,9 +55,14 @@
UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
- DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
- FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
- NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
+ DeclaredDestructor(false),
+ ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyAssignmentHasConstParam(true),
+ HasDeclaredCopyConstructorWithConstParam(false),
+ HasDeclaredCopyAssignmentWithConstParam(false),
+ FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
+ IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -184,15 +189,25 @@
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) {
VBases.push_back(VBase);
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each [...] virtual base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl())
+ if (!VBaseDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+ }
}
if (Base->isVirtual()) {
// Add this base if it's not already in the list.
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
- VBases.push_back(Base);
-
+ VBases.push_back(Base);
+
// C++0x [meta.unary.prop] is_empty:
// T is a class type, but not a union type, with ... no virtual base
// classes
@@ -276,6 +291,22 @@
if (!BaseClassDecl->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if each direct base class B
+ // of X has a copy assignment operator whose parameter is of type 'const
+ // B&', 'const volatile B&', or 'B' [...]
+ if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each direct [...] base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
@@ -522,51 +553,25 @@
data().IsStandardLayout = false;
}
}
-
- if (D->isImplicit()) {
- // Notify that an implicit member was added after the definition
- // was completed.
- if (!isBeingDefined())
- if (ASTMutationListener *L = getASTMutationListener())
- L->AddedCXXImplicitMember(data().Definition, D);
- // If this is a special member function, note that it was added and then
- // return early.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (Constructor->isConstexpr()) {
- data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
- } else if (Constructor->isCopyConstructor()) {
- data().DeclaredCopyConstructor = true;
- } else if (Constructor->isMoveConstructor()) {
- data().DeclaredMoveConstructor = true;
- } else
- goto NotASpecialMember;
- return;
- } else if (isa<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- return;
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->isCopyAssignmentOperator())
- data().DeclaredCopyAssignment = true;
- else if (Method->isMoveAssignmentOperator())
- data().DeclaredMoveAssignment = true;
- else
- goto NotASpecialMember;
- return;
- }
+ // Notify the listener if an implicit member was added after the definition
+ // was completed.
+ if (!isBeingDefined() && D->isImplicit())
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXImplicitMember(data().Definition, D);
-NotASpecialMember:;
- // Any other implicit declarations are handled like normal declarations.
- }
-
- // Handle (user-declared) constructors.
+ // Handle constructors.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (!Constructor->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+ }
// Technically, "user-provided" is only defined for special member
// functions, but the intent of the standard is clearly that it should apply
@@ -581,17 +586,17 @@
data().HasTrivialDefaultConstructor = false;
data().UserProvidedDefaultConstructor = true;
}
- if (Constructor->isConstexpr()) {
+ if (Constructor->isConstexpr())
data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
}
// Note when we have a user-declared copy or move constructor, which will
// suppress the implicit declaration of those constructors.
if (!FunTmpl) {
- if (Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ if (!Constructor->isImplicit())
+ data().UserDeclaredCopyConstructor = true;
data().DeclaredCopyConstructor = true;
// C++0x [class.copy]p13:
@@ -599,8 +604,12 @@
// user-provided [...]
if (UserProvided)
data().HasTrivialCopyConstructor = false;
+
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
} else if (Constructor->isMoveConstructor()) {
- data().UserDeclaredMoveConstructor = true;
+ if (!Constructor->isImplicit())
+ data().UserDeclaredMoveConstructor = true;
data().DeclaredMoveConstructor = true;
// C++0x [class.copy]p13:
@@ -610,11 +619,11 @@
data().HasTrivialMoveConstructor = false;
}
}
- if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
- // Record if we see any constexpr constructors which are neither copy
- // nor move constructors.
+
+ // Record if we see any constexpr constructors which are neither copy
+ // nor move constructors.
+ if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
data().HasConstexprNonCopyMoveConstructor = true;
- }
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-declared
@@ -622,31 +631,29 @@
// C++0x [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
- if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
+ if (getASTContext().getLangOpts().CPlusPlus0x
+ ? UserProvided : !Constructor->isImplicit())
data().Aggregate = false;
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- data().PlainOldData = false;
-
return;
}
- // Handle (user-declared) destructors.
+ // Handle destructors.
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
- data().UserDeclaredDestructor = true;
- data().HasIrrelevantDestructor = false;
- // C++ [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // destructor.
- // This bit is the C++03 POD bit, not the 0x one.
- data().PlainOldData = false;
-
- // C++11 [class.dtor]p5:
+ if (!DD->isImplicit()) {
+ data().UserDeclaredDestructor = true;
+ data().HasIrrelevantDestructor = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // destructor.
+ // This bit is the C++03 POD bit, not the 0x one.
+ data().PlainOldData = false;
+ }
+
+ // C++11 [class.dtor]p5:
// A destructor is trivial if it is not user-provided and if
// -- the destructor is not virtual.
if (DD->isUserProvided() || DD->isVirtual())
@@ -654,45 +661,53 @@
return;
}
-
- // Handle (user-declared) member functions.
+
+ // Handle member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isCopyAssignmentOperator()) {
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined
- // copy assignment operator [...].
- // This is the C++03 bit only.
- data().PlainOldData = false;
-
- // This is a copy assignment operator.
-
// Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
data().DeclaredCopyAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialCopyAssignment = false;
+ if (!Method->isImplicit()) {
+ data().UserDeclaredCopyAssignment = true;
- return;
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that [...] has no user-defined
+ // copy assignment operator [...].
+ // This is the C++03 bit only.
+ data().PlainOldData = false;
+
+ // C++11 [class.copy]p25:
+ // A copy/move assignment operator for class X is trivial if it is
+ // not user-provided [...]
+ // FIXME: This is bogus. Having one user-provided copy assignment
+ // doesn't stop another one from being trivial.
+ if (Method->isUserProvided())
+ data().HasTrivialCopyAssignment = false;
+ }
+
+ const ReferenceType *ParamTy =
+ Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
+ data().HasDeclaredCopyAssignmentWithConstParam = true;
}
-
- if (Method->isMoveAssignmentOperator()) {
- // This is an extension in C++03 mode, but we'll keep consistency by
- // taking a move assignment operator to induce non-POD-ness
- data().PlainOldData = false;
- // This is a move assignment operator.
- data().UserDeclaredMoveAssignment = true;
+ if (Method->isMoveAssignmentOperator()) {
data().DeclaredMoveAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialMoveAssignment = false;
+ if (!Method->isImplicit()) {
+ data().UserDeclaredMoveAssignment = true;
+
+ // This is an extension in C++03 mode, but we'll keep consistency by
+ // taking a move assignment operator to induce non-POD-ness
+ data().PlainOldData = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ if (Method->isUserProvided())
+ data().HasTrivialMoveAssignment = false;
+ }
}
// Keep the list of conversion functions up-to-date.
@@ -700,7 +715,7 @@
// We don't record specializations.
if (Conversion->getPrimaryTemplate())
return;
-
+
// FIXME: We intentionally don't use the decl's access here because it
// hasn't been set yet. That's really just a misdesign in Sema.
@@ -718,7 +733,7 @@
data().Conversions.addDecl(getASTContext(), Conversion);
}
}
-
+
return;
}
@@ -902,6 +917,24 @@
// The standard requires any in-class initializer to be a constant
// expression. We consider this to be a defect.
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if [...] for all the non-static data
+ // members of X that are of a class type M (or array thereof), each
+ // such class type has a copy constructor whose first parameter is
+ // of type 'const M&' or 'const volatile M&'.
+ if (!FieldRec->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if [...] for all the
+ // non-static data members of X that are of a class type M (or array
+ // thereof), each such class type has a copy assignment operator whose
+ // parameter is of type 'const M&', 'const volatile M&' or 'M'.
+ if (!FieldRec->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
}
} else {
// Base element type of field is a non-class type.