Lazily declare implicit copy constructors.
llvm-svn: 107543
This commit is contained in:
parent
3701fcd759
commit
a6d695057c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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++];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
|
||||
const CXXRecordDecl *FieldClassDecl
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
|
||||
const CXXRecordDecl *FieldClassDecl
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(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;
|
||||
}
|
||||
|
|
|
@ -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<CXXRecordDecl>(DC))
|
||||
if (Record->getDefinition() && !Record->hasDeclaredCopyConstructor() &&
|
||||
CanDeclareSpecialMemberFunction(S.Context, Record))
|
||||
S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record));
|
||||
break;
|
||||
|
||||
case DeclarationName::CXXDestructorName:
|
||||
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
|
||||
if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
|
||||
CanDeclareSpecialMemberFunction(S.Context, Record))
|
||||
S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(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);
|
||||
|
|
Loading…
Reference in New Issue