Fix chaining of ObjCInterfaceDecl redeclarations
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146722 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 9f20782..c272580 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -853,7 +853,8 @@
QualType getPackExpansionType(QualType Pattern,
llvm::Optional<unsigned> NumExpansions);
- QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const;
+ QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ ObjCInterfaceDecl *PrevDecl = 0) const;
QualType getObjCObjectType(QualType Base,
ObjCProtocolDecl * const *Protocols,
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index d333522..c13e1ba 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -614,9 +614,12 @@
static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
+ ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc = SourceLocation(),
bool isInternal = false);
+ static ObjCInterfaceDecl *CreateEmpty(ASTContext &C);
+
virtual SourceRange getSourceRange() const {
if (isThisDeclarationADefinition())
return ObjCContainerDecl::getSourceRange();
@@ -916,8 +919,6 @@
return getFirstDeclaration();
}
- void setPreviousDeclaration(ObjCInterfaceDecl *PrevDecl);
-
// Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index f65888f..de0250c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2808,11 +2808,17 @@
/// 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) const {
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ ObjCInterfaceDecl *PrevDecl) const {
if (Decl->TypeForDecl)
return QualType(Decl->TypeForDecl, 0);
- // FIXME: redeclarations?
+ if (PrevDecl) {
+ assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
+ Decl->TypeForDecl = PrevDecl->TypeForDecl;
+ return QualType(PrevDecl->TypeForDecl, 0);
+ }
+
void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
Decl->TypeForDecl = T;
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index ac3b536..963643e 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -3182,7 +3182,8 @@
if (!ToIface) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
- Name.getAsIdentifierInfo(), Loc,
+ Name.getAsIdentifierInfo(),
+ /*PrevDecl=*/0,Loc,
D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d420b2b..317dc95 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -225,18 +225,19 @@
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
Data = new (getASTContext()) DefinitionData();
- Data->Definition = this;
-
+ Data->Definition = this;
+}
+
+void ObjCInterfaceDecl::startDefinition() {
+ allocateDefinitionData();
+
// Update all of the declarations with a pointer to the definition.
for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
RD != RDEnd; ++RD) {
if (*RD != this)
RD->Data = Data;
}
-}
-void ObjCInterfaceDecl::startDefinition() {
- allocateDefinitionData();
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->CompletedObjCForwardRef(this);
}
@@ -674,9 +675,24 @@
DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
+ ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
bool isInternal){
- return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, isInternal);
+ ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
+ isInternal);
+ C.getObjCInterfaceType(Result, PrevDecl);
+
+ if (PrevDecl) {
+ Result->Data = PrevDecl->Data;
+ Result->setPreviousDeclaration(PrevDecl);
+ }
+
+ return Result;
+}
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::CreateEmpty(ASTContext &C) {
+ return new (C) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
+ false);
}
ObjCInterfaceDecl::
@@ -851,14 +867,6 @@
return false;
}
-void ObjCInterfaceDecl::setPreviousDeclaration(ObjCInterfaceDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
-
- // Inherit the 'Data' pointer from the previous declaration.
- if (PrevDecl)
- Data = PrevDecl->Data;
-}
-
//===----------------------------------------------------------------------===//
// ObjCIvarDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 2b7be7e..c95cf22 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -82,6 +82,7 @@
ObjCInterfaceDecl *ProtocolDecl =
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("Protocol"),
+ /*PrevDecl=*/0,
SourceLocation(), true);
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
PushOnScopeChains(ProtocolDecl, TUScope, false);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 02a83e5..4f87db4 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -366,11 +366,11 @@
}
// Create a declaration to describe this @interface.
+ ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
- ClassLoc);
+ PrevIDecl, ClassLoc);
- ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
@@ -379,9 +379,6 @@
Diag(Def->getLocation(), diag::note_previous_definition);
IDecl->setInvalidDecl();
}
-
- // Link to the previous declaration.
- IDecl->setPreviousDeclaration(PrevIDecl);
}
if (AttrList)
@@ -870,9 +867,8 @@
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
- if (RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
- diag::warn_undef_interface))
- IDecl = 0;
+ RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
+ diag::warn_undef_interface);
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
@@ -928,7 +924,8 @@
// FIXME: Do we support attributes on the @implementation? If so we should
// copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
- ClassName, ClassLoc, true);
+ ClassName, /*PrevDecl=*/0, ClassLoc,
+ true);
IDecl->startDefinition();
if (SDecl) {
IDecl->setSuperClass(SDecl);
@@ -1774,16 +1771,13 @@
}
// Create a declaration to describe this forward declaration.
+ ObjCInterfaceDecl *PrevIDecl
+ = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i], IdentLocs[i], true);
+ IdentList[i], PrevIDecl, IdentLocs[i], true);
IDecl->setAtEndRange(IdentLocs[i]);
- // If there was a previous declaration, link to it.
- if (ObjCInterfaceDecl *PrevIDecl
- = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))
- IDecl->setPreviousDeclaration(PrevIDecl);
-
// Create the forward declaration. Note that we intentionally do this
// before we add the ObjCInterfaceDecl we just created, so that the
// rewriter sees the ObjCClassDecl first.
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index cacacd2..5e5f1cb 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -223,6 +223,9 @@
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ // if we have a fully initialized TypeDecl, we can safely read its type now.
+ ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
if (Record[Idx++])
@@ -556,7 +559,7 @@
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
VisitRedeclarable(ID);
VisitObjCContainerDecl(ID);
- ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
+ TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
ObjCInterfaceDecl *Def = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
if (ID == Def) {
@@ -621,13 +624,13 @@
// pending references were linked.
Reader.PendingForwardRefs.erase(ID);
#endif
- } else if (Def) {
- if (Def->Data) {
- ID->Data = Def->Data;
- } else {
- // The definition is still initializing.
- Reader.PendingForwardRefs[Def].push_back(ID);
- }
+ }
+ } else if (Def) {
+ if (Def->Data) {
+ ID->Data = Def->Data;
+ } else {
+ // The definition is still initializing.
+ Reader.PendingForwardRefs[Def].push_back(ID);
}
}
}
@@ -1561,6 +1564,8 @@
FD->RedeclLink.setPointer(cast<FunctionDecl>(previous));
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
VD->RedeclLink.setPointer(cast<VarDecl>(previous));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(previous)) {
+ ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
@@ -1736,7 +1741,7 @@
Selector(), QualType(), 0, 0);
break;
case DECL_OBJC_INTERFACE:
- D = ObjCInterfaceDecl::Create(Context, 0, SourceLocation(), 0);
+ D = ObjCInterfaceDecl::CreateEmpty(Context);
break;
case DECL_OBJC_IVAR:
D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
diff --git a/test/Modules/Inputs/decl2.h b/test/Modules/Inputs/decl2.h
new file mode 100644
index 0000000..decf6e0
--- /dev/null
+++ b/test/Modules/Inputs/decl2.h
@@ -0,0 +1 @@
+@class A;
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 6b93a6a..f7cc7d4 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -39,5 +39,6 @@
module decldef {
explicit module Decl { header "decl.h" }
+ explicit module Decl2 { header "decl2.h" }
explicit module Def { header "def.h" }
}
\ No newline at end of file
diff --git a/test/SemaObjC/forward-class-1.m b/test/SemaObjC/forward-class-1.m
index f5ce889..e8c3695 100644
--- a/test/SemaObjC/forward-class-1.m
+++ b/test/SemaObjC/forward-class-1.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@class FOO, BAR;
@class FOO, BAR; // expected-note {{forward declaration of class here}}
+@class FOO, BAR;
@interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}}
@end