diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 5e3f891e486b..19b5694f0a8e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1327,6 +1327,13 @@ public: // Statistics //===--------------------------------------------------------------------===// + /// \brief The number of implicitly-declared copy constructors. + static unsigned NumImplicitCopyConstructors; + + /// \brief The number of implicitly-declared constructors for + /// which declarations were built. + static unsigned NumImplicitCopyConstructorsDeclared; + /// \brief The number of implicitly-declared copy assignment operators. static unsigned NumImplicitCopyAssignmentOperators; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 624bf631197e..90302afc4c59 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -319,6 +319,9 @@ class CXXRecordDecl : public RecordDecl { /// already computed and are available. bool ComputedVisibleConversions : 1; + /// \brief Whether we have already declared the copy constructor. + bool DeclaredCopyConstructor : 1; + /// \brief Whether we have already declared the copy-assignment operator. bool DeclaredCopyAssignment : 1; @@ -576,6 +579,20 @@ public: return data().UserDeclaredCopyConstructor; } + /// \brief Determine whether this class has had its copy constructor + /// declared, either via the user or via an implicit declaration. + /// + /// This value is used for lazy creation of copy constructors. + bool hasDeclaredCopyConstructor() const { + return data().DeclaredCopyConstructor; + } + + /// \brief Note whether this class has already had its copy constructor + /// declared. + void setDeclaredCopyConstructor(bool DCC) { + data().DeclaredCopyConstructor = DCC; + } + /// 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. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f44eb6572150..4737abc3e35a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -31,6 +31,8 @@ using namespace clang; +unsigned ASTContext::NumImplicitCopyConstructors; +unsigned ASTContext::NumImplicitCopyConstructorsDeclared; unsigned ASTContext::NumImplicitCopyAssignmentOperators; unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; unsigned ASTContext::NumImplicitDestructors; @@ -259,6 +261,9 @@ void ASTContext::PrintStats() const { fprintf(stderr, "Total bytes = %d\n", int(TotalBytes)); // Implicit special member functions. + fprintf(stderr, " %u/%u implicit copy constructors created\n", + NumImplicitCopyConstructorsDeclared, + NumImplicitCopyConstructors); fprintf(stderr, " %u/%u implicit copy assignment operators created\n", NumImplicitCopyAssignmentOperatorsDeclared, NumImplicitCopyAssignmentOperators); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index b54f0e2ca60f..4b1909e57c66 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -32,6 +32,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) Abstract(false), HasTrivialConstructor(true), HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), + DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), DeclaredDestructor(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), Definition(D), FirstFriend(0) { @@ -295,11 +296,13 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, // suppress the implicit declaration of a copy constructor. if (ConDecl->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; + } } diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 211032be8a5b..a7b092abb93d 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -657,6 +657,7 @@ void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { Data.HasTrivialCopyAssignment = Record[Idx++]; Data.HasTrivialDestructor = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; + Data.DeclaredCopyConstructor = Record[Idx++]; Data.DeclaredCopyAssignment = Record[Idx++]; Data.DeclaredDestructor = Record[Idx++]; diff --git a/clang/lib/Frontend/PCHWriterDecl.cpp b/clang/lib/Frontend/PCHWriterDecl.cpp index 411a125f5e9c..3a053e283d14 100644 --- a/clang/lib/Frontend/PCHWriterDecl.cpp +++ b/clang/lib/Frontend/PCHWriterDecl.cpp @@ -654,6 +654,7 @@ void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { Record.push_back(Data.HasTrivialCopyAssignment); Record.push_back(Data.HasTrivialDestructor); Record.push_back(Data.ComputedVisibleConversions); + Record.push_back(Data.DeclaredCopyConstructor); Record.push_back(Data.DeclaredCopyAssignment); Record.push_back(Data.DeclaredDestructor); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 93caad669d96..5c98e2b1db26 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2657,7 +2657,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { DeclareImplicitDefaultConstructor(ClassDecl); if (!ClassDecl->hasUserDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(ClassDecl); + ++ASTContext::NumImplicitCopyConstructors; if (!ClassDecl->hasUserDeclaredCopyAssignment()) { ++ASTContext::NumImplicitCopyAssignmentOperators; @@ -5065,8 +5065,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( if (Base->isVirtual()) continue; - const CXXRecordDecl *BaseClassDecl + CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); + if (!BaseClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(BaseClassDecl); + HasConstCopyConstructor = BaseClassDecl->hasConstCopyConstructor(Context); } @@ -5075,8 +5078,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( BaseEnd = ClassDecl->vbases_end(); HasConstCopyConstructor && Base != BaseEnd; ++Base) { - const CXXRecordDecl *BaseClassDecl + CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); + if (!BaseClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(BaseClassDecl); + HasConstCopyConstructor = BaseClassDecl->hasConstCopyConstructor(Context); } @@ -5091,8 +5097,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (const RecordType *FieldClassType = FieldType->getAs()) { - const CXXRecordDecl *FieldClassDecl + CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); + if (!FieldClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(FieldClassDecl); + HasConstCopyConstructor = FieldClassDecl->hasConstCopyConstructor(Context); } @@ -5121,8 +5130,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( if (Base->isVirtual()) continue; - const CXXRecordDecl *BaseClassDecl + CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); + if (!BaseClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(BaseClassDecl); + if (CXXConstructorDecl *CopyConstructor = BaseClassDecl->getCopyConstructor(Context, Quals)) ExceptSpec.CalledDecl(CopyConstructor); @@ -5131,8 +5143,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { - const CXXRecordDecl *BaseClassDecl + CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); + if (!BaseClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(BaseClassDecl); + if (CXXConstructorDecl *CopyConstructor = BaseClassDecl->getCopyConstructor(Context, Quals)) ExceptSpec.CalledDecl(CopyConstructor); @@ -5143,8 +5158,11 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (const RecordType *FieldClassType = FieldType->getAs()) { - const CXXRecordDecl *FieldClassDecl + CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); + if (!FieldClassDecl->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(FieldClassDecl); + if (CXXConstructorDecl *CopyConstructor = FieldClassDecl->getCopyConstructor(Context, Quals)) ExceptSpec.CalledDecl(CopyConstructor); @@ -5175,6 +5193,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setImplicit(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); + // Note that we have declared this constructor. + ClassDecl->setDeclaredCopyConstructor(true); + ++ASTContext::NumImplicitCopyConstructorsDeclared; + // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassDecl->getLocation(), @@ -5184,9 +5206,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( VarDecl::None, 0); CopyConstructor->setParams(&FromParam, 1); if (Scope *S = getScopeForContext(ClassDecl)) - PushOnScopeChains(CopyConstructor, S, true); - else - ClassDecl->addDecl(CopyConstructor); + PushOnScopeChains(CopyConstructor, S, false); + ClassDecl->addDecl(CopyConstructor); return CopyConstructor; } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 6d590893bdcc..b13deec19abb 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -464,14 +464,19 @@ static bool CanDeclareSpecialMemberFunction(ASTContext &Context, } void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { + if (!CanDeclareSpecialMemberFunction(Context, Class)) + return; + + // If the copy constructor has not yet been declared, do so now. + if (!Class->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(Class); + // If the copy assignment operator has not yet been declared, do so now. - if (CanDeclareSpecialMemberFunction(Context, Class) && - !Class->hasDeclaredCopyAssignment()) + if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); // If the destructor has not yet been declared, do so now. - if (CanDeclareSpecialMemberFunction(Context, Class) && - !Class->hasDeclaredDestructor()) + if (!Class->hasDeclaredDestructor()) DeclareImplicitDestructor(Class); } @@ -479,6 +484,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; @@ -501,12 +507,18 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, return; switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + if (const CXXRecordDecl *Record = dyn_cast(DC)) + if (Record->getDefinition() && !Record->hasDeclaredCopyConstructor() && + CanDeclareSpecialMemberFunction(S.Context, Record)) + S.DeclareImplicitCopyConstructor(const_cast(Record)); + break; + case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && !Record->hasDeclaredDestructor() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitDestructor(const_cast(Record)); - break; case DeclarationName::CXXOperatorName: @@ -1992,9 +2004,11 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { - if (!Class->getDefinition()) - return DeclContext::lookup_result(); - + // If the copy constructor has not yet been declared, do so now. + if (CanDeclareSpecialMemberFunction(Context, Class) && + !Class->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(Class); + CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name);