diff options
author | Alexis Hunt <alercah@gmail.com> | 2011-05-25 20:50:04 +0000 |
---|---|---|
committer | Alexis Hunt <alercah@gmail.com> | 2011-05-25 20:50:04 +0000 |
commit | fcaeae492940662da16b2a75dbf3be494150b82f (patch) | |
tree | 042e4e2367d39e6b43b0ee0655c65422ab47cbb4 /clang/lib | |
parent | 9a26f0f260c1c12905358edb16661de21734dc0d (diff) | |
download | bcm5719-llvm-fcaeae492940662da16b2a75dbf3be494150b82f.tar.gz bcm5719-llvm-fcaeae492940662da16b2a75dbf3be494150b82f.zip |
Implement a little bit of cleanup and a lot more of the base work
behind implicit moves. We now correctly identify move constructors and
assignment operators and update bits on the record correctly. Generation
of implicit moves (declarations or definitions) is not yet supported.
llvm-svn: 132080
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 14 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 162 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 15 |
4 files changed, 127 insertions, 82 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d5003be5dea..1535efec984 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 43cea51e93c..9e82a1a84c8 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 41e05d5cdb5..8b0ee7057a7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e8f2f57a220..1e3baa26f33 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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); } } |