diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-11-28 06:23:12 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-11-28 06:23:12 +0000 |
commit | acf796b4797c5b3e9e237148fa622afdc04b3eff (patch) | |
tree | 6c271132920ce500bffd5b7d570b9f537eba17ac /lib/AST/DeclCXX.cpp | |
parent | 3881866dc782c5e13b21031bd363e93fbf367167 (diff) |
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
Diffstat (limited to 'lib/AST/DeclCXX.cpp')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 247 |
1 files changed, 140 insertions, 107 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index d661aa04af..a3c0bab8b8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -55,9 +55,14 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, 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 @@ void CXXRecordDecl::addedMember(Decl *D) { 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; - } -NotASpecialMember:; - // Any other implicit declarations are handled like normal declarations. - } - - // Handle (user-declared) constructors. + // 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); + + // 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 @@ NotASpecialMember:; 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; 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; + + // 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; + } - return; + 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 @@ NotASpecialMember:; // 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 @@ NotASpecialMember:; data().Conversions.addDecl(getASTContext(), Conversion); } } - + return; } @@ -902,6 +917,24 @@ NotASpecialMember:; // 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. |