aboutsummaryrefslogtreecommitdiff
path: root/lib/AST
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-12-15 05:27:12 +0000
committerDouglas Gregor <dgregor@apple.com>2011-12-15 05:27:12 +0000
commit2e5c15be82f362611c5928ce853d0685ff98c766 (patch)
tree8b23e367ea5a70ddf92adc54293271df5f5c1d08 /lib/AST
parentfa39f5b76bafdf536c5e305f821eb1b7f11079bd (diff)
Move the definition-specific data of ObjCInterfaceDecl into a
separately-allocated DefinitionData structure, which we manage the same way as CXXRecordDecl::DefinitionData. This prepares the way for making ObjCInterfaceDecls redeclarable, to more accurately model forward declarations of Objective-C classes and eliminate the mutation of ObjCInterfaceDecl that causes us serious trouble in the AST reader. Note that ObjCInterfaceDecl's accessors are fairly robust against being applied to forward declarations, because Clang (and Sema in particular) doesn't perform RequireCompleteType/hasDefinition() checks everywhere it has to. Each of these overly-robust cases is marked with a FIXME, which we can tackle over time. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146644 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/ASTImporter.cpp140
-rw-r--r--lib/AST/DeclObjC.cpp108
-rw-r--r--lib/AST/DeclPrinter.cpp5
3 files changed, 152 insertions, 101 deletions
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index e409f0a1d3..949db7972a 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -3178,7 +3178,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
}
ObjCInterfaceDecl *ToIface = MergeWithIface;
- if (!ToIface || ToIface->isForwardDecl()) {
+ if (!ToIface || !ToIface->hasDefinition()) {
if (!ToIface) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
@@ -3187,88 +3187,98 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
- if (D->isInitiallyForwardDecl() && !D->isForwardDecl())
- ToIface->completedForwardDecl();
}
Importer.Imported(D, ToIface);
- if (D->getSuperClass()) {
- ObjCInterfaceDecl *Super
- = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
- if (!Super)
- return 0;
+ if (D->hasDefinition()) {
+ if (!ToIface->hasDefinition())
+ ToIface->startDefinition();
- ToIface->setSuperClass(Super);
- ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
- }
-
- // Import protocols
- SmallVector<ObjCProtocolDecl *, 4> Protocols;
- SmallVector<SourceLocation, 4> ProtocolLocs;
- ObjCInterfaceDecl::protocol_loc_iterator
- FromProtoLoc = D->protocol_loc_begin();
-
- // FIXME: Should we be usng all_referenced_protocol_begin() here?
- for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(),
- FromProtoEnd = D->protocol_end();
- FromProto != FromProtoEnd;
- ++FromProto, ++FromProtoLoc) {
- ObjCProtocolDecl *ToProto
- = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
- if (!ToProto)
- return 0;
- Protocols.push_back(ToProto);
- ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ if (D->getSuperClass()) {
+ ObjCInterfaceDecl *Super
+ = cast_or_null<ObjCInterfaceDecl>(
+ Importer.Import(D->getSuperClass()));
+ if (!Super)
+ return 0;
+
+ ToIface->setSuperClass(Super);
+ ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
+ }
+
+ // Import protocols
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
+ ObjCInterfaceDecl::protocol_loc_iterator
+ FromProtoLoc = D->protocol_loc_begin();
+
+ for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(),
+ FromProtoEnd = D->protocol_end();
+ FromProto != FromProtoEnd;
+ ++FromProto, ++FromProtoLoc) {
+ ObjCProtocolDecl *ToProto
+ = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+ if (!ToProto)
+ return 0;
+ Protocols.push_back(ToProto);
+ ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ }
+
+ // FIXME: If we're merging, make sure that the protocol list is the same.
+ ToIface->setProtocolList(Protocols.data(), Protocols.size(),
+ ProtocolLocs.data(), Importer.getToContext());
}
- // FIXME: If we're merging, make sure that the protocol list is the same.
- ToIface->setProtocolList(Protocols.data(), Protocols.size(),
- ProtocolLocs.data(), Importer.getToContext());
-
// Import @end range
ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
} else {
Importer.Imported(D, ToIface);
- // Check for consistency of superclasses.
- DeclarationName FromSuperName, ToSuperName;
-
- // If the superclass hasn't been imported yet, do so before checking.
- ObjCInterfaceDecl *DSuperClass = D->getSuperClass();
- ObjCInterfaceDecl *ToIfaceSuperClass = ToIface->getSuperClass();
-
- if (DSuperClass && !ToIfaceSuperClass) {
- Decl *ImportedSuperClass = Importer.Import(DSuperClass);
- ObjCInterfaceDecl *ImportedSuperIface = cast<ObjCInterfaceDecl>(ImportedSuperClass);
- ToIface->setSuperClass(ImportedSuperIface);
- }
+ if (D->hasDefinition()) {
+ // Check for consistency of superclasses.
+ DeclarationName FromSuperName, ToSuperName;
+
+ // If the superclass hasn't been imported yet, do so before checking.
+ ObjCInterfaceDecl *DSuperClass = D->getSuperClass();
+ ObjCInterfaceDecl *ToIfaceSuperClass = ToIface->getSuperClass();
+
+ if (DSuperClass && !ToIfaceSuperClass) {
+ Decl *ImportedSuperClass = Importer.Import(DSuperClass);
+ ObjCInterfaceDecl *ImportedSuperIface
+ = cast<ObjCInterfaceDecl>(ImportedSuperClass);
+
+ ToIface->setSuperClass(ImportedSuperIface);
+ }
- if (D->getSuperClass())
- FromSuperName = Importer.Import(D->getSuperClass()->getDeclName());
- if (ToIface->getSuperClass())
- ToSuperName = ToIface->getSuperClass()->getDeclName();
- if (FromSuperName != ToSuperName) {
- Importer.ToDiag(ToIface->getLocation(),
- diag::err_odr_objc_superclass_inconsistent)
- << ToIface->getDeclName();
+ if (D->getSuperClass())
+ FromSuperName = Importer.Import(D->getSuperClass()->getDeclName());
if (ToIface->getSuperClass())
- Importer.ToDiag(ToIface->getSuperClassLoc(),
- diag::note_odr_objc_superclass)
- << ToIface->getSuperClass()->getDeclName();
- else
+ ToSuperName = ToIface->getSuperClass()->getDeclName();
+ if (FromSuperName != ToSuperName) {
Importer.ToDiag(ToIface->getLocation(),
- diag::note_odr_objc_missing_superclass);
- if (D->getSuperClass())
- Importer.FromDiag(D->getSuperClassLoc(),
+ diag::err_odr_objc_superclass_inconsistent)
+ << ToIface->getDeclName();
+ if (ToIface->getSuperClass())
+ Importer.ToDiag(ToIface->getSuperClassLoc(),
diag::note_odr_objc_superclass)
- << D->getSuperClass()->getDeclName();
- else
- Importer.FromDiag(D->getLocation(),
+ << ToIface->getSuperClass()->getDeclName();
+ else
+ Importer.ToDiag(ToIface->getLocation(),
diag::note_odr_objc_missing_superclass);
- return 0;
+ if (D->getSuperClass())
+ Importer.FromDiag(D->getSuperClassLoc(),
+ diag::note_odr_objc_superclass)
+ << D->getSuperClass()->getDeclName();
+ else
+ Importer.FromDiag(D->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ return 0;
+ }
}
}
+ if (!D->hasDefinition())
+ return ToIface;
+
// Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
for (ObjCCategoryDecl *FromCat = D->getCategoryList(); FromCat;
@@ -3279,7 +3289,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
ImportDeclContext(D);
// If we have an @implementation, import it as well.
- if (D->getImplementation()) {
+ if ( D->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
Importer.Import(D->getImplementation()));
if (!Impl)
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 38efadf3b5..decbd54c6d 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -154,7 +154,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
if (ObjCPropertyDecl *PD =
@@ -175,11 +179,12 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
{
- if (ExternallyCompleted)
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
- AllReferencedProtocols.set(ExtList, ExtNum, C);
+ if (data().AllReferencedProtocols.empty() &&
+ data().ReferencedProtocols.empty()) {
+ data().AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
}
@@ -214,12 +219,16 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ProtocolRefs.push_back(*p);
}
- AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C);
+ data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
}
-void ObjCInterfaceDecl::completedForwardDecl() {
- assert(isForwardDecl() && "Only valid to call for forward refs");
- ForwardDecl = false;
+void ObjCInterfaceDecl::allocateDefinitionData() {
+ assert(!hasDefinition() && "ObjC class already has a definition");
+ Definition = new (getASTContext()) DefinitionData();
+}
+
+void ObjCInterfaceDecl::startDefinition() {
+ allocateDefinitionData();
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->CompletedObjCForwardRef(this);
}
@@ -244,7 +253,11 @@ const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
@@ -271,7 +284,11 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
/// the it returns NULL.
ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
const IdentifierInfo*ICName) {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
@@ -287,10 +304,14 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
/// the class, its categories, and its super classes (using a linear search).
ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
bool isInstance) const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
- if (ExternallyCompleted)
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
while (ClassDecl != NULL) {
@@ -328,7 +349,11 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
const Selector &Sel,
bool Instance) {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCMethodDecl *Method = 0;
@@ -651,16 +676,14 @@ ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
- TypeForDecl(0), SuperClass(0),
- CategoryList(0), IvarList(0),
- InitiallyForwardDecl(FD), ForwardDecl(FD),
- ExternallyCompleted(false) {
+ TypeForDecl(0), Definition(), InitiallyForwardDecl(FD)
+{
setImplicit(isInternal);
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
- assert(ExternallyCompleted && "Class is not externally completed");
- ExternallyCompleted = false;
+ assert(data().ExternallyCompleted && "Class is not externally completed");
+ data().ExternallyCompleted = false;
getASTContext().getExternalSource()->CompleteType(
const_cast<ObjCInterfaceDecl *>(this));
}
@@ -668,13 +691,17 @@ void ObjCInterfaceDecl::LoadExternalDefinition() const {
void ObjCInterfaceDecl::setExternallyCompleted() {
assert(getASTContext().getExternalSource() &&
"Class can't be externally completed without an external source");
- assert(!ForwardDecl &&
+ assert(hasDefinition() &&
"Forward declarations can't be externally completed");
- ExternallyCompleted = true;
+ data().ExternallyCompleted = true;
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
return getASTContext().getObjCImplementation(
@@ -689,14 +716,18 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
/// its extensions and its implementation. Lazily build the list on first
/// access.
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
- if (IvarList)
- return IvarList;
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().IvarList)
+ return data().IvarList;
ObjCIvarDecl *curIvar = 0;
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- IvarList = (*I); ++I;
- for (curIvar = IvarList; I != E; curIvar = *I, ++I)
+ data().IvarList = (*I); ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
@@ -705,9 +736,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!CDecl->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
E = CDecl->ivar_end();
- if (!IvarList) {
- IvarList = (*I); ++I;
- curIvar = IvarList;
+ if (!data().IvarList) {
+ data().IvarList = (*I); ++I;
+ curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
@@ -718,15 +749,15 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!ImplDecl->ivar_empty()) {
ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end();
- if (!IvarList) {
- IvarList = (*I); ++I;
- curIvar = IvarList;
+ if (!data().IvarList) {
+ data().IvarList = (*I); ++I;
+ curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
}
- return IvarList;
+ return data().IvarList;
}
/// FindCategoryDeclaration - Finds category declaration in the list of
@@ -735,7 +766,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
- if (ExternallyCompleted)
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
for (ObjCCategoryDecl *Category = getCategoryList();
@@ -770,6 +801,9 @@ ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
bool lookupCategory,
bool RHSIsQualifiedID) {
+ if (!hasDefinition())
+ return false;
+
ObjCInterfaceDecl *IDecl = this;
// 1st, look up the class.
const ObjCList<ObjCProtocolDecl> &Protocols =
@@ -997,9 +1031,11 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryList();
- IDecl->setCategoryList(CatDecl);
- if (ASTMutationListener *L = C.getASTMutationListener())
- L->AddedObjCCategoryToInterface(CatDecl, IDecl);
+ if (IDecl->hasDefinition()) {
+ IDecl->setCategoryList(CatDecl);
+ if (ASTMutationListener *L = C.getASTMutationListener())
+ L->AddedObjCCategoryToInterface(CatDecl, IDecl);
+ }
}
return CatDecl;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 91b011fbda..ec7d6de71a 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -905,6 +905,11 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
else
Out << "@interface " << I;
+ if (OID->isForwardDecl()) {
+ Out << "@end";
+ return;
+ }
+
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
if (!Protocols.empty()) {