- Make ObjCInterfaceDecl redeclarable, and create separate decl nodes for forward declarations and the definition.
- Eagerly create ObjCInterfaceTypes for declarations.
- The two above changes lead to a 0.5% increase in memory use and no speed regression when parsing Cocoa.h. On the other hand, now chained PCH works when there's a forward declaration in one PCH and the interface definition in another.
- Add HandleInterestingDecl to ASTConsumer. PCHReader passes the "interesting" decls it finds to this function instead of HandleTopLevelDecl. The default implementation forwards to HandleTopLevelDecl, but ASTUnit's handler for example ignores them. This fixes a potential crash when lazy loading of PCH data would cause ASTUnit's "top level" declaration collection to change while being iterated.
llvm-svn: 110610
diff --git a/clang/lib/AST/ASTConsumer.cpp b/clang/lib/AST/ASTConsumer.cpp
index f37cbde..04a084a 100644
--- a/clang/lib/AST/ASTConsumer.cpp
+++ b/clang/lib/AST/ASTConsumer.cpp
@@ -17,3 +17,6 @@
void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {}
+void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
+ HandleTopLevelDecl(D);
+}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 7d15926..83cee5c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -872,7 +872,7 @@
/// CollectNonClassIvars -
/// This routine collects all other ivars which are not declared in the class.
/// This includes synthesized ivars (via @synthesize) and those in
-// class's @implementation.
+/// class's @implementation.
///
void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
@@ -2212,18 +2212,24 @@
return QualType(QType, 0);
}
-/// getObjCInterfaceType - Return the unique reference to the type for the
-/// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
- if (Decl->TypeForDecl)
- return QualType(Decl->TypeForDecl, 0);
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ const ObjCInterfaceDecl *PrevDecl) {
+ assert(Decl && "Passed null for Decl param");
- // FIXME: redeclarations?
- void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
- ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
- Decl->TypeForDecl = T;
- Types.push_back(T);
- return QualType(T, 0);
+ if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+
+ if (PrevDecl) {
+ assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
+ Decl->TypeForDecl = PrevDecl->TypeForDecl;
+ return QualType(PrevDecl->TypeForDecl, 0);
+ }
+
+ assert(!Decl->getPreviousDeclaration() &&
+ "interface has previous declaration");
+
+ Decl->TypeForDecl = new (*this, TypeAlignment) ObjCInterfaceType(Decl);
+ Types.push_back(Decl->TypeForDecl);
+ return QualType(Decl->TypeForDecl, 0);
}
/// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 5e8586f..6242d40 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2467,6 +2467,18 @@
}
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // If this interface has a definition in the translation unit we're coming
+ // from, but this particular declaration is not that definition, import the
+ // definition and map to that.
+ ObjCInterfaceDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
// Import the major distinguishing characteristics of an @interface.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -2491,7 +2503,7 @@
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(),
DC, Loc,
Name.getAsIdentifierInfo(),
- Importer.Import(D->getClassLoc()),
+ Importer.Import(D->getClassLoc()), 0,
D->isForwardDecl(),
D->isImplicitInterfaceDecl());
ToIface->setForwardDecl(D->isForwardDecl());
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 32f9433..0720b20 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -45,6 +45,14 @@
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
+ObjCInterfaceDecl *ObjCInterfaceDecl::getDefinition() {
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if (I->isDefinition())
+ return *I;
+ }
+ return 0;
+}
+
/// getIvarDecl - This method looks up an ivar in this ContextDecl.
///
ObjCIvarDecl *
@@ -432,18 +440,30 @@
SourceLocation atLoc,
IdentifierInfo *Id,
SourceLocation ClassLoc,
+ ObjCInterfaceDecl *PrevDecl,
bool ForwardDecl, bool isInternal){
- return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl,
- isInternal);
+ ObjCInterfaceDecl *D = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
+ PrevDecl, ForwardDecl,
+ isInternal);
+ C.getObjCInterfaceType(D, PrevDecl);
+ return D;
+}
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, EmptyShell) {
+ return new (C) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
+ 0, false, false);
}
ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
- SourceLocation CLoc, bool FD, bool isInternal)
+ SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+ bool FD, bool isInternal)
: ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
TypeForDecl(0), SuperClass(0),
CategoryList(0), ForwardDecl(FD), InternalInterface(isInternal),
ClassLoc(CLoc) {
+ if (PrevDecl)
+ setPreviousDeclaration(PrevDecl);
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index fae1e72..d3ebc8f 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -727,12 +727,19 @@
void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
std::string I = OID->getNameAsString();
+
+ if (OID->isForwardDecl()) {
+ // These shouldn't be directly visited, but in case they are, write them
+ // as an @class declaration.
+ Out << "@class " << I;
+ return;
+ }
+
ObjCInterfaceDecl *SID = OID->getSuperClass();
+ Out << "@interface " << I;
if (SID)
- Out << "@interface " << I << " : " << SID;
- else
- Out << "@interface " << I;
+ Out << " : " << SID;
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 31af6fb..4f88498 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -360,6 +360,17 @@
return 0;
}
+ObjCInterfaceDecl *ObjCInterfaceType::getDecl() const {
+ for (ObjCInterfaceDecl::redecl_iterator I = Decl->redecls_begin(),
+ E = Decl->redecls_end();
+ I != E; ++I) {
+ if (I->isDefinition())
+ return *I;
+ }
+ // If we can't find a definition, return whatever we have.
+ return Decl;
+}
+
const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
if (const PointerType *PT = getAs<PointerType>())
if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>())