Lazily declare default constructors. We now delay the construction of
declarations for implicit default constructors, copy constructors,
copy assignment operators, and destructors. On a "simple" translation
unit that includes a bunch of C++ standard library headers, we
generate relatively few of these implicit declarations now:
4/159 implicit default constructors created
18/236 implicit copy constructors created
70/241 implicit copy assignment operators created
0/173 implicit destructors created
And, on this translation unit, this optimization doesn't really
provide any benefit. I'll do some more performance measurements soon,
but this completes the implementation work for <rdar://problem/8151045>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107551 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4737abc..2d52bd0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -31,6 +31,8 @@
using namespace clang;
+unsigned ASTContext::NumImplicitDefaultConstructors;
+unsigned ASTContext::NumImplicitDefaultConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyConstructors;
unsigned ASTContext::NumImplicitCopyConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyAssignmentOperators;
@@ -261,6 +263,9 @@
fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
// Implicit special member functions.
+ fprintf(stderr, " %u/%u implicit default constructors created\n",
+ NumImplicitDefaultConstructorsDeclared,
+ NumImplicitDefaultConstructors);
fprintf(stderr, " %u/%u implicit copy constructors created\n",
NumImplicitCopyConstructorsDeclared,
NumImplicitCopyConstructors);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 1c41e5a..8020916 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -975,6 +975,12 @@
CreateStoredDeclsMap(*C);
}
+ // If there is an external AST source, load any declarations it knows about
+ // with this declaration's name.
+ if (ExternalASTSource *Source = getParentASTContext().getExternalSource())
+ if (hasExternalVisibleStorage())
+ Source->FindExternalVisibleDeclsByName(this, D->getDeclName());
+
// Insert this declaration into the map.
StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
if (DeclNameEntries.isNull()) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 4b1909e..7ce9c64 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -32,7 +32,7 @@
Abstract(false), HasTrivialConstructor(true),
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
- DeclaredCopyConstructor(false),
+ DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
DeclaredCopyAssignment(false), DeclaredDestructor(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
Definition(D), FirstFriend(0) {
@@ -277,6 +277,9 @@
// 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) [...].
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index a7b092a..8e0d635 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -657,6 +657,7 @@
Data.HasTrivialCopyAssignment = Record[Idx++];
Data.HasTrivialDestructor = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
+ Data.DeclaredDefaultConstructor = Record[Idx++];
Data.DeclaredCopyConstructor = Record[Idx++];
Data.DeclaredCopyAssignment = Record[Idx++];
Data.DeclaredDestructor = Record[Idx++];
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 3a053e2..2383a75 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -654,6 +654,7 @@
Record.push_back(Data.HasTrivialCopyAssignment);
Record.push_back(Data.HasTrivialDestructor);
Record.push_back(Data.ComputedVisibleConversions);
+ Record.push_back(Data.DeclaredDefaultConstructor);
Record.push_back(Data.DeclaredCopyConstructor);
Record.push_back(Data.DeclaredCopyAssignment);
Record.push_back(Data.DeclaredDestructor);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 5c98e2b..4dd5e3f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2654,7 +2654,7 @@
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (!ClassDecl->hasUserDeclaredConstructor())
- DeclareImplicitDefaultConstructor(ClassDecl);
+ ++ASTContext::NumImplicitDefaultConstructors;
if (!ClassDecl->hasUserDeclaredCopyConstructor())
++ASTContext::NumImplicitCopyConstructors;
@@ -4156,6 +4156,19 @@
// user-declared constructor for class X, a default constructor is
// implicitly declared. An implicitly-declared default constructor
// is an inline public member of its class.
+ assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ "Should not build implicit default constructor!");
+
+ // FIXME: HACK HACK HACK
+ if (Context.getExternalSource()) {
+ // This hack ensures that, when using precompiled headers, the lookup
+ // table in the DeclContext has already loaded the constructor declarations
+ // so that we can add a new one. The real fix will go into DeclContext,
+ // when I figure out what that is.
+ CanQualType T
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ ClassDecl->lookup(Context.DeclarationNames.getCXXConstructorName(T));
+ }
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
@@ -4169,20 +4182,28 @@
if (B->isVirtual()) // Handled below.
continue;
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
- if (CXXConstructorDecl *Constructor
- = cast<CXXRecordDecl>(BaseType->getDecl())->getDefaultConstructor())
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (!BaseClassDecl->hasDeclaredDefaultConstructor())
+ ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
+ else if (CXXConstructorDecl *Constructor
+ = BaseClassDecl->getDefaultConstructor())
ExceptSpec.CalledDecl(Constructor);
+ }
}
// Virtual base-class destructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
BEnd = ClassDecl->vbases_end();
B != BEnd; ++B) {
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
- if (CXXConstructorDecl *Constructor
- = cast<CXXRecordDecl>(BaseType->getDecl())->getDefaultConstructor())
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (!BaseClassDecl->hasDeclaredDefaultConstructor())
+ ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
+ else if (CXXConstructorDecl *Constructor
+ = BaseClassDecl->getDefaultConstructor())
ExceptSpec.CalledDecl(Constructor);
+ }
}
// Field destructors.
@@ -4190,10 +4211,15 @@
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>())
- if (CXXConstructorDecl *Constructor
- = cast<CXXRecordDecl>(RecordTy->getDecl())->getDefaultConstructor())
+ = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!FieldClassDecl->hasDeclaredDefaultConstructor())
+ ExceptSpec.CalledDecl(
+ DeclareImplicitDefaultConstructor(FieldClassDecl));
+ else if (CXXConstructorDecl *Constructor
+ = FieldClassDecl->getDefaultConstructor())
ExceptSpec.CalledDecl(Constructor);
+ }
}
@@ -4219,10 +4245,15 @@
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
+
+ // Note that we have declared this constructor.
+ ClassDecl->setDeclaredDefaultConstructor(true);
+ ++ASTContext::NumImplicitDefaultConstructorsDeclared;
+
if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(DefaultCon, S, true);
- else
- ClassDecl->addDecl(DefaultCon);
+ PushOnScopeChains(DefaultCon, S, false);
+ ClassDecl->addDecl(DefaultCon);
+
return DefaultCon;
}
@@ -4612,7 +4643,17 @@
// 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.
- //
+
+
+ // FIXME: HACK HACK HACK
+ if (Context.getExternalSource()) {
+ // This hack ensures that, when using precompiled headers, the lookup
+ // table in the DeclContext has already loaded the assignment operator
+ // declarations so that we can add a new one. The real fix will go into
+ // DeclContext, when I figure out what that is.
+ ClassDecl->lookup(Context.DeclarationNames.getCXXOperatorName(OO_Equal));
+ }
+
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
// assignment operator, one is declared implicitly.
@@ -5045,6 +5086,17 @@
// If the class definition does not explicitly declare a copy
// constructor, one is declared implicitly.
+ // FIXME: HACK HACK HACK
+ if (Context.getExternalSource()) {
+ // This hack ensures that, when using precompiled headers, the lookup
+ // table in the DeclContext has already loaded the constructor declarations
+ // so that we can add a new one. The real fix will go into DeclContext,
+ // when I figure out what that is.
+ CanQualType T
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ ClassDecl->lookup(Context.DeclarationNames.getCXXConstructorName(T));
+ }
+
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
// have the form
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index b13deec..c11e3b3 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -466,6 +466,10 @@
void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
if (!CanDeclareSpecialMemberFunction(Context, Class))
return;
+
+ // If the default constructor has not yet been declared, do so now.
+ if (!Class->hasDeclaredDefaultConstructor())
+ DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
if (!Class->hasDeclaredCopyConstructor())
@@ -509,9 +513,14 @@
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));
+ if (Record->getDefinition() &&
+ CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ if (!Record->hasDeclaredDefaultConstructor())
+ S.DeclareImplicitDefaultConstructor(
+ const_cast<CXXRecordDecl *>(Record));
+ if (!Record->hasDeclaredCopyConstructor())
+ S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record));
+ }
break;
case DeclarationName::CXXDestructorName:
@@ -2005,9 +2014,12 @@
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the copy constructor has not yet been declared, do so now.
- if (CanDeclareSpecialMemberFunction(Context, Class) &&
- !Class->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(Class);
+ if (CanDeclareSpecialMemberFunction(Context, Class)) {
+ if (!Class->hasDeclaredDefaultConstructor())
+ DeclareImplicitDefaultConstructor(Class);
+ if (!Class->hasDeclaredCopyConstructor())
+ DeclareImplicitCopyConstructor(Class);
+ }
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T);