From d3c359041bce38e2a117b82a5bb37eba7f68b0c8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 1 Jul 2010 16:36:15 +0000 Subject: [PATCH] Move the implicit declaration of a class's copy-assignment operator into a separate routine. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107402 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 14 ++- lib/Sema/SemaDeclCXX.cpp | 199 ++++++++++++++++++++------------------- 2 files changed, 114 insertions(+), 99 deletions(-) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 93e6a06ef8..2e52bfcb94 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2236,7 +2236,19 @@ public: CXXConstructorDecl *Constructor, unsigned TypeQuals); - /// \brief Defined and implicitly-declared copy assignment operator. + /// \brief Declare the implicit copy assignment operator for the given class. + /// + /// \param S The scope of the class, which may be NULL if this is a + /// template instantiation. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy-assignment operator will be added. + /// + /// \returns The implicitly-declared copy assignment operator. + CXXMethodDecl *DeclareImplicitCopyAssignment(Scope *S, + CXXRecordDecl *ClassDecl); + + /// \brief Defined an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 94d00b2697..130aa576b6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2779,104 +2779,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, ClassDecl->addDecl(CopyConstructor); } - if (!ClassDecl->hasUserDeclaredCopyAssignment()) { - // Note: The following rules are largely analoguous to the copy - // constructor rules. Note that virtual bases are not taken into account - // for determining the argument type of the operator. Note also that - // operators taking an object instead of a reference are allowed. - // - // C++ [class.copy]p10: - // If the class definition does not explicitly declare a copy - // assignment operator, one is declared implicitly. - // The implicitly-defined copy assignment operator for a class X - // will have the form - // - // X& X::operator=(const X&) - // - // if - bool HasConstCopyAssignment = true; - - // -- each direct base class B of X has a copy assignment operator - // whose parameter is of type const B&, const volatile B& or B, - // and - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - BaseEnd = ClassDecl->bases_end(); - HasConstCopyAssignment && Base != BaseEnd; ++Base) { - assert(!Base->getType()->isDependentType() && - "Cannot generate implicit members for class with dependent bases."); - const CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - const CXXMethodDecl *MD = 0; - HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context, - MD); - } - - // -- for all the nonstatic 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. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - HasConstCopyAssignment && Field != FieldEnd; - ++Field) { - QualType FieldType = (*Field)->getType(); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs()) { - const CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - const CXXMethodDecl *MD = 0; - HasConstCopyAssignment - = FieldClassDecl->hasConstCopyAssignment(Context, MD); - } - } - - // Otherwise, the implicitly declared copy assignment operator will - // have the form - // - // X& X::operator=(X&) - QualType ArgType = ClassType; - QualType RetType = Context.getLValueReferenceType(ArgType); - if (HasConstCopyAssignment) - ArgType = ArgType.withConst(); - ArgType = Context.getLValueReferenceType(ArgType); - - // An implicitly-declared copy assignment operator is an inline public - // member of its class. - DeclarationName Name = - Context.DeclarationNames.getCXXOperatorName(OO_Equal); - CXXMethodDecl *CopyAssignment = - CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, - Context.getFunctionType(RetType, &ArgType, 1, - false, 0, - /*FIXME: hasExceptionSpec*/false, - false, 0, 0, - FunctionType::ExtInfo()), - /*TInfo=*/0, /*isStatic=*/false, - /*StorageClassAsWritten=*/FunctionDecl::None, - /*isInline=*/true); - CopyAssignment->setAccess(AS_public); - CopyAssignment->setImplicit(); - CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); - CopyAssignment->setCopyAssignment(true); - - // Add the parameter to the operator. - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, - ClassDecl->getLocation(), - /*Id=*/0, - ArgType, /*TInfo=*/0, - VarDecl::None, - VarDecl::None, 0); - CopyAssignment->setParams(&FromParam, 1); - - // Don't call addedAssignmentOperator. There is no way to distinguish an - // implicit from an explicit assignment operator. - if (S) - PushOnScopeChains(CopyAssignment, S, true); - else - ClassDecl->addDecl(CopyAssignment); - AddOverriddenMethods(ClassDecl, CopyAssignment); - } + if (!ClassDecl->hasUserDeclaredCopyAssignment()) + DeclareImplicitCopyAssignment(S, ClassDecl); if (!ClassDecl->hasUserDeclaredDestructor()) { // C++ [class.dtor]p2: @@ -4661,6 +4565,105 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Loc, move(Copy)); } +CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(Scope *S, + CXXRecordDecl *ClassDecl) { + // Note: The following rules are largely analoguous to the copy + // constructor rules. Note that virtual bases are not taken into account + // for determining the argument type of the operator. Note also that + // operators taking an object instead of a reference are allowed. + // + // C++ [class.copy]p10: + // If the class definition does not explicitly declare a copy + // assignment operator, one is declared implicitly. + // The implicitly-defined copy assignment operator for a class X + // will have the form + // + // X& X::operator=(const X&) + // + // if + bool HasConstCopyAssignment = true; + + // -- each direct base class B of X has a copy assignment operator + // whose parameter is of type const B&, const volatile B& or B, + // and + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + BaseEnd = ClassDecl->bases_end(); + HasConstCopyAssignment && Base != BaseEnd; ++Base) { + assert(!Base->getType()->isDependentType() && + "Cannot generate implicit members for class with dependent bases."); + const CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + const CXXMethodDecl *MD = 0; + HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context, + MD); + } + + // -- for all the nonstatic 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. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + HasConstCopyAssignment && Field != FieldEnd; + ++Field) { + QualType FieldType = Context.getBaseElementType((*Field)->getType()); + if (const RecordType *FieldClassType = FieldType->getAs()) { + const CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + const CXXMethodDecl *MD = 0; + HasConstCopyAssignment + = FieldClassDecl->hasConstCopyAssignment(Context, MD); + } + } + + // Otherwise, the implicitly declared copy assignment operator will + // have the form + // + // X& X::operator=(X&) + QualType ArgType = Context.getTypeDeclType(ClassDecl); + QualType RetType = Context.getLValueReferenceType(ArgType); + if (HasConstCopyAssignment) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + + // An implicitly-declared copy assignment operator is an inline public + // member of its class. + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + CXXMethodDecl *CopyAssignment + = CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, + Context.getFunctionType(RetType, &ArgType, 1, + false, 0, + /*FIXME: hasExceptionSpec*/false, + false, 0, 0, + FunctionType::ExtInfo()), + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/FunctionDecl::None, + /*isInline=*/true); + CopyAssignment->setAccess(AS_public); + CopyAssignment->setImplicit(); + CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); + CopyAssignment->setCopyAssignment(true); + + // Add the parameter to the operator. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, + ClassDecl->getLocation(), + /*Id=*/0, + ArgType, /*TInfo=*/0, + VarDecl::None, + VarDecl::None, 0); + CopyAssignment->setParams(&FromParam, 1); + + // Don't call addedAssignmentOperator. The class does not need to know about + // the implicitly-declared copy assignment operator. + if (S) + PushOnScopeChains(CopyAssignment, S, true); + else + ClassDecl->addDecl(CopyAssignment); + + AddOverriddenMethods(ClassDecl, CopyAssignment); + return CopyAssignment; +} + void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { assert((CopyAssignOperator->isImplicit() && -- 2.40.0