class FunctionTemplateDecl;
class ObjCCategoryDecl;
class ObjCInterfaceDecl;
+ class ObjCContainerDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
/// \brief A new objc category class was added for an interface.
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {}
+
+ /// \brief A objc interface or protocol forward reference was completed.
+ virtual void CompletedObjCForwardRef(const ObjCContainerDecl *D) {}
};
} // end namespace clang
bool isInitiallyForwardDecl() const { return InitiallyForwardDecl; }
bool isForwardDecl() const { return ForwardDecl; }
- void setForwardDecl(bool val) { ForwardDecl = val; }
+
+ void completedForwardDecl();
ObjCInterfaceDecl *getSuperClass() const {
if (ExternallyCompleted)
bool isInitiallyForwardDecl() const { return InitiallyForwardDecl; }
bool isForwardDecl() const { return isForwardProtoDecl; }
- void setForwardDecl(bool val) { isForwardProtoDecl = val; }
+
+ void completedForwardDecl();
// Location information, modeled after the Stmt API.
SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'protocol
void ResolveDeclUpdatesBlocks();
void WriteDeclUpdatesBlocks();
void WriteDeclReplacementsBlock();
- void ResolveChainedObjCCategories();
void WriteChainedObjCCategories();
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptions &Opts);
const_cast<Decl *>(D)->setChangedSinceDeserialization(false);
}
+ bool isRewritten(const Decl *D) const {
+ return DeclsToRewrite.count(D);
+ }
+
/// \brief Note that the identifier II occurs at the given offset
/// within the identifier table.
void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset);
virtual void StaticDataMemberInstantiated(const VarDecl *D);
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD);
+ virtual void CompletedObjCForwardRef(const ObjCContainerDecl *D);
};
/// \brief AST and semantic-analysis consumer that generates a
Name.getAsIdentifierInfo(), Loc,
Importer.Import(D->getAtStartLoc()),
D->isInitiallyForwardDecl());
- ToProto->setForwardDecl(D->isForwardDecl());
ToProto->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToProto);
+ if (D->isInitiallyForwardDecl() && !D->isForwardDecl())
+ ToProto->completedForwardDecl();
}
Importer.Imported(D, ToProto);
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
Name.getAsIdentifierInfo(), Loc,
- D->isForwardDecl(),
+ D->isInitiallyForwardDecl(),
D->isImplicitInterfaceDecl());
- ToIface->setForwardDecl(D->isForwardDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
+ if (D->isInitiallyForwardDecl() && !D->isForwardDecl())
+ ToIface->completedForwardDecl();
}
Importer.Imported(D, ToIface);
AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C);
}
+void ObjCInterfaceDecl::completedForwardDecl() {
+ assert(isForwardDecl() && "Only valid to call for forward refs");
+ ForwardDecl = false;
+ if (ASTMutationListener *L = getASTContext().getASTMutationListener())
+ L->CompletedObjCForwardRef(this);
+}
+
/// getFirstClassExtension - Find first class extension of the given class.
ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const {
for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl;
return NULL;
}
+void ObjCProtocolDecl::completedForwardDecl() {
+ assert(isForwardDecl() && "Only valid to call for forward refs");
+ isForwardProtoDecl = false;
+ if (ASTMutationListener *L = getASTContext().getASTMutationListener())
+ L->CompletedObjCForwardRef(this);
+}
+
//===----------------------------------------------------------------------===//
// ObjCClassDecl
//===----------------------------------------------------------------------===//
return ActOnObjCContainerStartDefinition(IDecl);
} else {
IDecl->setLocation(ClassLoc);
- IDecl->setForwardDecl(false);
IDecl->setAtStartLoc(AtInterfaceLoc);
- // If the forward decl was in a PCH, we need to write it again in a
- // dependent AST file.
- IDecl->setChangedSinceDeserialization(true);
// Since this ObjCInterfaceDecl was created by a forward declaration,
// we now add it to the DeclContext since it wasn't added before
// (see ActOnForwardClassDeclaration).
IDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(IDecl);
-
+
+ IDecl->completedForwardDecl();
+
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
}
// Make sure the cached decl gets a valid start location.
PDecl->setAtStartLoc(AtProtoInterfaceLoc);
PDecl->setLocation(ProtocolLoc);
- PDecl->setForwardDecl(false);
// Since this ObjCProtocolDecl was created by a forward declaration,
// we now add it to the DeclContext since it wasn't added before
PDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(PDecl);
- // Repeat in dependent AST files.
- PDecl->setChangedSinceDeserialization(true);
+ PDecl->completedForwardDecl();
} else {
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
ProtocolLoc, AtProtoInterfaceLoc,
/*isForwardDecl=*/false);
PushOnScopeChains(PDecl, TUScope);
- PDecl->setForwardDecl(false);
}
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
// Mark the interface as being completed, even if it was just as
// @class ....;
// declaration; the user cannot reopen it.
- IDecl->setForwardDecl(false);
+ if (IDecl->isForwardDecl())
+ IDecl->completedForwardDecl();
}
ObjCImplementationDecl* IMPDecl =
// We will rebuild this list lazily.
ID->setIvarList(0);
ID->InitiallyForwardDecl = Record[Idx++];
- ID->setForwardDecl(Record[Idx++]);
+ ID->ForwardDecl = Record[Idx++];
ID->setImplicitInterfaceDecl(Record[Idx++]);
ID->setSuperClassLoc(ReadSourceLocation(Record, Idx));
ID->setLocEnd(ReadSourceLocation(Record, Idx));
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
VisitObjCContainerDecl(PD);
PD->InitiallyForwardDecl = Record[Idx++];
- PD->setForwardDecl(Record[Idx++]);
+ PD->isForwardProtoDecl = Record[Idx++];
PD->setLocEnd(ReadSourceLocation(Record, Idx));
unsigned NumProtoRefs = Record[Idx++];
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
// Resolve any declaration pointers within the declaration updates block and
// chained Objective-C categories block to declaration IDs.
ResolveDeclUpdatesBlocks();
- ResolveChainedObjCCategories();
// Form the record of special types.
RecordData SpecialTypes;
const Decl *D = I->first;
UpdateRecord &URec = I->second;
- if (DeclsToRewrite.count(D))
+ if (isRewritten(D))
continue; // The decl will be written completely
unsigned Idx = 0, N = URec.size();
const Decl *D = I->first;
UpdateRecord &URec = I->second;
- if (DeclsToRewrite.count(D))
+ if (isRewritten(D))
continue; // The decl will be written completely,no need to store updates.
uint64_t Offset = Stream.GetCurrentBitNo();
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
}
-void ASTWriter::ResolveChainedObjCCategories() {
- for (SmallVector<ChainedObjCCategoriesData, 16>::iterator
- I = LocalChainedObjCCategories.begin(),
- E = LocalChainedObjCCategories.end(); I != E; ++I) {
- ChainedObjCCategoriesData &Data = *I;
- Data.InterfaceID = GetDeclRef(Data.Interface);
- Data.TailCategoryID = GetDeclRef(Data.TailCategory);
- }
-
-}
-
void ASTWriter::WriteChainedObjCCategories() {
if (LocalChainedObjCCategories.empty())
return;
I = LocalChainedObjCCategories.begin(),
E = LocalChainedObjCCategories.end(); I != E; ++I) {
ChainedObjCCategoriesData &Data = *I;
+ if (isRewritten(Data.Interface))
+ continue;
+
serialization::DeclID
HeadCatID = getDeclID(Data.Interface->getCategoryList());
assert(HeadCatID != 0 && "Category not written ?");
- Record.push_back(Data.InterfaceID);
+ Record.push_back(GetDeclRef(Data.Interface));
Record.push_back(HeadCatID);
- Record.push_back(Data.TailCategoryID);
+ Record.push_back(GetDeclRef(Data.TailCategory));
}
Stream.EmitRecord(OBJC_CHAINED_CATEGORIES, Record);
}
ChainedObjCCategoriesData Data = { IFD, CatD, 0, 0 };
LocalChainedObjCCategories.push_back(Data);
}
+
+void ASTWriter::CompletedObjCForwardRef(const ObjCContainerDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return; // Declaration not imported from PCH.
+
+ RewriteDecl(D);
+}
--- /dev/null
+// Test that infinite loop in rdar://10418538 was fixed.
+
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -include %s -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header
+
+@class I;
+
+//===----------------------------------------------------------------------===//
+#elif !defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header
+
+@interface I
+@end
+
+@interface I(Cat1)
+@end
+
+@interface I(Cat2)
+@end
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+void f(I* i) {
+ [i meth]; // expected-warning {{not found}}
+}
+
+//===----------------------------------------------------------------------===//
+#endif