diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 14 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 162 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 18 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 15 |
4 files changed, 127 insertions, 82 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d5003be5de..1535efec98 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -39,8 +39,12 @@ unsigned ASTContext::NumImplicitDefaultConstructors; unsigned ASTContext::NumImplicitDefaultConstructorsDeclared; unsigned ASTContext::NumImplicitCopyConstructors; unsigned ASTContext::NumImplicitCopyConstructorsDeclared; +unsigned ASTContext::NumImplicitMoveConstructors; +unsigned ASTContext::NumImplicitMoveConstructorsDeclared; unsigned ASTContext::NumImplicitCopyAssignmentOperators; unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; +unsigned ASTContext::NumImplicitMoveAssignmentOperators; +unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; @@ -318,9 +322,17 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %u/%u implicit copy constructors created\n", NumImplicitCopyConstructorsDeclared, NumImplicitCopyConstructors); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move constructors created\n", + NumImplicitMoveConstructorsDeclared, + NumImplicitMoveConstructors); fprintf(stderr, " %u/%u implicit copy assignment operators created\n", NumImplicitCopyAssignmentOperatorsDeclared, NumImplicitCopyAssignmentOperators); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move assignment operators created\n", + NumImplicitMoveAssignmentOperatorsDeclared, + NumImplicitMoveAssignmentOperators); fprintf(stderr, " %u/%u implicit destructors created\n", NumImplicitDestructorsDeclared, NumImplicitDestructors); @@ -3717,7 +3729,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const { if (getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - return RD->hasConstCopyConstructor(*this); + return RD->hasConstCopyConstructor(); } } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 43cea51e93..9e82a1a84c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -29,7 +29,8 @@ using namespace clang; CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), - UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), + UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false), + UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), @@ -39,7 +40,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasTrivialMoveAssignment(true), HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), - DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), + DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), + DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) { } @@ -268,8 +270,8 @@ bool CXXRecordDecl::hasAnyDependentBases() const { return !forallBases(SawBase, 0); } -bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const { - return getCopyConstructor(Context, Qualifiers::Const) != 0; +bool CXXRecordDecl::hasConstCopyConstructor() const { + return getCopyConstructor(Qualifiers::Const) != 0; } bool CXXRecordDecl::isTriviallyCopyable() const { @@ -312,8 +314,8 @@ GetBestOverloadCandidateSimple( return Cands[Best].first; } -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context, - unsigned TypeQuals) const{ +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{ + ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); DeclarationName ConstructorName @@ -343,6 +345,14 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context, GetBestOverloadCandidateSimple(Found)); } +CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const { + for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I) + if (I->isMoveConstructor()) + return *I; + + return 0; +} + CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { ASTContext &Context = getASTContext(); QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); @@ -393,6 +403,14 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { return GetBestOverloadCandidateSimple(Found); } +CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const { + for (method_iterator I = method_begin(), E = method_end(); I != E; ++I) + if (I->isMoveAssignmentOperator()) + return *I; + + return 0; +} + void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. @@ -459,33 +477,32 @@ void CXXRecordDecl::addedMember(Decl *D) { 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 this is the implicit default constructor, note that we have now - // declared it. - if (Constructor->isDefaultConstructor()) { + if (Constructor->isDefaultConstructor()) data().DeclaredDefaultConstructor = true; - } - // If this is the implicit copy constructor, note that we have now - // declared it. else if (Constructor->isCopyConstructor()) data().DeclaredCopyConstructor = true; + else if (Constructor->isMoveConstructor()) + data().DeclaredMoveConstructor = true; + else + goto NotASpecialMember; return; - } - - if (isa<CXXDestructorDecl>(D)) { + } else if (isa<CXXDestructorDecl>(D)) { data().DeclaredDestructor = true; return; - } - - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - // If this is the implicit copy constructor, note that we have now - // declared it. - // FIXME: Move constructors - if (Method->getOverloadedOperator() == OO_Equal) + } 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. } @@ -524,6 +541,9 @@ void CXXRecordDecl::addedMember(Decl *D) { UserProvided = true; } } else if (Constructor->isMoveConstructor()) { + data().UserDeclaredMoveConstructor = true; + data().DeclaredMoveConstructor = true; + // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if it is not // user-provided [...] @@ -579,61 +599,42 @@ void CXXRecordDecl::addedMember(Decl *D) { // Handle (user-declared) member functions. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (Method->getOverloadedOperator() == OO_Equal) { - // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType - = Method->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Overloaded operator has no proto function type."); - assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); - - // Copy assignment operators must be non-templates. - if (Method->getPrimaryTemplate() || FunTmpl) - return; - - ASTContext &Context = getASTContext(); - QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( - const_cast<CXXRecordDecl*>(this))); - - bool isRValueRefArg = false; - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = - ArgType->getAs<LValueReferenceType>()) { - ArgType = Ref->getPointeeType(); - } else if (const RValueReferenceType *Ref = - ArgType->getAs<RValueReferenceType>()) { - ArgType = Ref->getPointeeType(); - isRValueRefArg = true; - } - if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) - return; - + 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; - if (!isRValueRefArg) { - // This is a copy assignment operator. + // This is a copy assignment operator. - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = true; + // 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; - } else { - // This is a move assignment operator. + // 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; - // 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; - } + return; + } + + 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; + 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; } // Keep the list of conversion functions up-to-date. @@ -1170,14 +1171,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { } bool CXXMethodDecl::isCopyAssignmentOperator() const { - // C++0x [class.copy]p19: + // C++0x [class.copy]p17: // A user-declared copy assignment operator X::operator= is a non-static // non-template member function of class X with exactly one parameter of // type X, X&, const X&, volatile X& or const volatile X&. if (/*operator=*/getOverloadedOperator() != OO_Equal || /*non-static*/ isStatic() || - /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || - /*exactly one parameter*/getNumParams() != 1) + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate()) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1190,6 +1190,26 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { return Context.hasSameUnqualifiedType(ClassType, ParamType); } +bool CXXMethodDecl::isMoveAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared move assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of type + // X&&, const X&&, volatile X&&, or const volatile X&&. + if (getOverloadedOperator() != OO_Equal || isStatic() || + getPrimaryTemplate() || getDescribedFunctionTemplate()) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (!isa<RValueReferenceType>(ParamType)) + return false; + ParamType = ParamType->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 41e05d5cdb..8b0ee7057a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7736,7 +7736,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXCopyConstructor: if (RD->hasUserDeclaredCopyConstructor()) { SourceLocation CtorLoc = - RD->getCopyConstructor(Context, 0)->getLocation(); + RD->getCopyConstructor(0)->getLocation(); + Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + + case CXXMoveConstructor: + if (RD->hasUserDeclaredMoveConstructor()) { + SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } @@ -7752,6 +7760,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } break; + case CXXMoveAssignment: + if (RD->hasUserDeclaredMoveAssignment()) { + SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation(); + Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + case CXXDestructor: if (RD->hasUserDeclaredDestructor()) { SourceLocation DtorLoc = LookupDestructor(RD)->getLocation(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e8f2f57a22..1e3baa26f3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7069,8 +7069,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (!BaseClassDecl->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(BaseClassDecl); - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + HasConstCopyConstructor = BaseClassDecl->hasConstCopyConstructor(); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7082,8 +7081,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (!BaseClassDecl->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(BaseClassDecl); - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + HasConstCopyConstructor= BaseClassDecl->hasConstCopyConstructor(); } // -- for all the nonstatic data members of X that are of a @@ -7101,8 +7099,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (!FieldClassDecl->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(FieldClassDecl); - HasConstCopyConstructor - = FieldClassDecl->hasConstCopyConstructor(Context); + HasConstCopyConstructor = FieldClassDecl->hasConstCopyConstructor(); } } // Otherwise, the implicitly declared copy constructor will have @@ -7129,7 +7126,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { DeclareImplicitCopyConstructor(BaseClassDecl); if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + = BaseClassDecl->getCopyConstructor(Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7142,7 +7139,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { DeclareImplicitCopyConstructor(BaseClassDecl); if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + = BaseClassDecl->getCopyConstructor(Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -7157,7 +7154,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { DeclareImplicitCopyConstructor(FieldClassDecl); if (CXXConstructorDecl *CopyConstructor - = FieldClassDecl->getCopyConstructor(Context, Quals)) + = FieldClassDecl->getCopyConstructor(Quals)) ExceptSpec.CalledDecl(CopyConstructor); } } |