summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-07-03 00:47:00 +0000
committerDouglas Gregor <dgregor@apple.com>2010-07-03 00:47:00 +0000
commit9672f92f7f2c5a58037ee6ee38004330d80f3372 (patch)
tree958a5b6191a0723112eab72105117d24b2975587 /clang/lib/Sema
parent0664a67fe1cf6bbf93b51153c8cd452409995efb (diff)
downloadbcm5719-llvm-9672f92f7f2c5a58037ee6ee38004330d80f3372.tar.gz
bcm5719-llvm-9672f92f7f2c5a58037ee6ee38004330d80f3372.zip
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>. llvm-svn: 107551
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp80
-rw-r--r--clang/lib/Sema/SemaLookup.cpp24
2 files changed, 84 insertions, 20 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5c98e2b1db2..4dd5e3f30dd 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2654,7 +2654,7 @@ namespace {
/// 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 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// 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 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
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 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
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 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
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 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// 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 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// 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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index b13deec19ab..c11e3b371d8 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -466,6 +466,10 @@ static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
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 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
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 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
/// \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);
OpenPOWER on IntegriCloud