From: Douglas Gregor Date: Mon, 27 Sep 2010 22:06:20 +0000 (+0000) Subject: Centralize the handling of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=27c08ab4859d071efa158a256f7e47e13d924443;p=clang Centralize the handling of CXXRecordDecl::DefinitionData::DeclaredCopyAssignment, for copy-assignment operators. Another step toward . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114899 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index da32239b75..be5ec06471 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -406,13 +406,12 @@ class CXXRecordDecl : public RecordDecl { friend class DeclContext; - /// \brief Notify the class that another constructor has - /// been added. + /// \brief Notify the class that member has been added. /// /// This routine helps maintain information about the class based on which - /// constructors have been added. It will be invoked by DeclContext::addDecl() - /// whenever a constructor is added to this record. - void addedConstructor(CXXConstructorDecl *ConDecl); + /// members have been added. It will be invoked by DeclContext::addDecl() + /// whenever a member is added to this record. + void addedMember(Decl *D); protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -610,11 +609,6 @@ public: return data().DeclaredCopyConstructor; } - /// addedAssignmentOperator - Notify the class that another assignment - /// operator has been added. This routine helps maintain information about the - /// class based on which operators have been added. - void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl); - /// hasUserDeclaredCopyAssignment - Whether this class has a /// user-declared copy assignment operator. When false, a copy /// assigment operator will be implicitly declared. @@ -630,12 +624,6 @@ public: return data().DeclaredCopyAssignment; } - /// \brief Note whether this class has already had its copy assignment - /// operator declared. - void setDeclaredCopyAssignment(bool DCA) { - data().DeclaredCopyAssignment = DCA; - } - /// hasUserDeclaredDestructor - Whether this class has a /// user-declared destructor. When false, a destructor will be /// implicitly declared. diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 207edde592..26ab9250d7 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -778,14 +778,11 @@ void DeclContext::addHiddenDecl(Decl *D) { } else { FirstDecl = LastDecl = D; } - - if (CXXRecordDecl *Record = dyn_cast(this)) { - Decl *InnerD = D; - if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) - InnerD = FunTmpl->getTemplatedDecl(); - if (CXXConstructorDecl *Constructor = dyn_cast(InnerD)) - Record->addedConstructor(Constructor); - } + + // Notify a C++ record declaration that we've added a member, so it can + // update it's class-specific state. + if (CXXRecordDecl *Record = dyn_cast(this)) + Record->addedMember(D); } void DeclContext::addDecl(Decl *D) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ffdb98d751..1b89ab6bed 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -259,99 +259,126 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { } void -CXXRecordDecl::addedConstructor(CXXConstructorDecl *Constructor) { - // Ignore friends. - if (Constructor->getFriendObjectKind()) +CXXRecordDecl::addedMember(Decl *D) { + // Ignore friends and invalid declarations. + if (D->getFriendObjectKind() || D->isInvalidDecl()) return; - if (Constructor->isImplicit()) { - // If this is the implicit default constructor, note that we have now - // declared it. - 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; + FunctionTemplateDecl *FunTmpl = dyn_cast(D); + if (FunTmpl) + D = FunTmpl->getTemplatedDecl(); + + if (D->isImplicit()) { + if (CXXConstructorDecl *Constructor = dyn_cast(D)) { + // If this is the implicit default constructor, note that we have now + // declared it. + 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; + } + // FIXME: Destructors + else if (CXXMethodDecl *Method = dyn_cast(D)) { + // If this is the implicit copy constructor, note that we have now + // declared it. + // FIXME: Move constructors + if (Method->getOverloadedOperator() == OO_Equal) { + data().DeclaredCopyAssignment = true; + Method->setCopyAssignment(true); + } + } - // Nothing else to do for implicitly-declared constructors. + // Nothing else to do for implicitly-declared members. return; } - // Note that we have a user-declared constructor. - data().UserDeclaredConstructor = true; - - // Note that we have no need of an implicitly-declared default constructor. - data().DeclaredDefaultConstructor = true; - - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class (clause 9) with no - // user-declared constructors (12.1) [...]. - data().Aggregate = false; + // Handle (user-declared) constructors. + if (CXXConstructorDecl *Constructor = dyn_cast(D)) { + // Note that we have a user-declared constructor. + data().UserDeclaredConstructor = true; - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - data().PlainOldData = false; - - // C++ [class.ctor]p5: - // A constructor is trivial if it is an implicitly-declared default - // constructor. - // FIXME: C++0x: don't do this for "= default" default constructors. - data().HasTrivialConstructor = false; - - // Note when we have a user-declared copy constructor, which will - // suppress the implicit declaration of a copy constructor. - if (!Constructor->getDescribedFunctionTemplate() && - Constructor->isCopyConstructor()) { - data().UserDeclaredCopyConstructor = true; - data().DeclaredCopyConstructor = true; + // Note that we have no need of an implicitly-declared default constructor. + data().DeclaredDefaultConstructor = true; - // C++ [class.copy]p6: - // A copy constructor is trivial if it is implicitly declared. - // FIXME: C++0x: don't do this for "= default" copy constructors. - data().HasTrivialCopyConstructor = false; + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with no + // user-declared constructors (12.1) [...]. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + data().PlainOldData = false; + + // C++ [class.ctor]p5: + // A constructor is trivial if it is an implicitly-declared default + // constructor. + // FIXME: C++0x: don't do this for "= default" default constructors. + data().HasTrivialConstructor = false; + + // Note when we have a user-declared copy constructor, which will + // suppress the implicit declaration of a copy constructor. + if (!FunTmpl && Constructor->isCopyConstructor()) { + data().UserDeclaredCopyConstructor = true; + data().DeclaredCopyConstructor = true; + + // C++ [class.copy]p6: + // A copy constructor is trivial if it is implicitly declared. + // FIXME: C++0x: don't do this for "= default" copy constructors. + data().HasTrivialCopyConstructor = false; + } + + return; } -} -void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, - CXXMethodDecl *OpDecl) { - // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType = OpDecl->getType()->getAs(); - assert(FnType && "Overloaded operator has no proto function type."); - assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + // FIXME: Destructors. - // Copy assignment operators must be non-templates. - if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) - return; - - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAs()) - ArgType = Ref->getPointeeType(); - - ArgType = ArgType.getUnqualifiedType(); - QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( - const_cast(this))); - - if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) + if (CXXMethodDecl *Method = dyn_cast(D)) { + if (Method->getOverloadedOperator() == OO_Equal) { + // We're interested specifically in copy assignment operators. + const FunctionProtoType *FnType + = Method->getType()->getAs(); + 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 ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref =ArgType->getAs()) + ArgType = Ref->getPointeeType(); + + ArgType = ArgType.getUnqualifiedType(); + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast(this))); + + if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) + return; + + // This is a copy assignment operator. + // Note on the decl that it is a copy assignment operator. + Method->setCopyAssignment(true); + + // Suppress the implicit declaration of a copy constructor. + data().UserDeclaredCopyAssignment = true; + data().DeclaredCopyAssignment = true; + + // C++ [class.copy]p11: + // A copy assignment operator is trivial if it is implicitly declared. + // FIXME: C++0x: don't do this for "= default" copy operators. + data().HasTrivialCopyAssignment = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class that [...] has no user-defined copy + // assignment operator [...]. + data().PlainOldData = false; + } + return; - - // This is a copy assignment operator. - // Note on the decl that it is a copy assignment operator. - OpDecl->setCopyAssignment(true); - - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = true; - - // C++ [class.copy]p11: - // A copy assignment operator is trivial if it is implicitly declared. - // FIXME: C++0x: don't do this for "= default" copy operators. - data().HasTrivialCopyAssignment = false; - - // C++ [class]p4: - // A POD-struct is an aggregate class that [...] has no user-defined copy - // assignment operator [...]. - data().PlainOldData = false; + } } static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 48e36a9dc4..48beca71cf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -544,7 +544,9 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { if (const CXXConstructorDecl *CD = dyn_cast(D)) return CD->isCopyConstructor(); - return D->isCopyAssignment(); + if (const CXXMethodDecl *Method = dyn_cast(D)) + return Method->isCopyAssignmentOperator(); + return false; } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 025ac3bed9..92655da609 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4942,7 +4942,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setParams(&FromParam, 1); // Note that we have added this copy-assignment operator. - ClassDecl->setDeclaredCopyAssignment(true); ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) @@ -5952,15 +5951,6 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { << LastParam->getType() << (Op == OO_MinusMinus); } - // Notify the class if it got an assignment operator. - if (Op == OO_Equal) { - // Would have returned earlier otherwise. - assert(isa(FnDecl) && - "Overloaded = not member, but not filtered."); - CXXMethodDecl *Method = cast(FnDecl); - Method->getParent()->addedAssignmentOperator(Context, Method); - } - return false; }