From bd51b8745c7424fb95abb91370d1a38a24451a6e Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 20 Sep 2007 20:26:44 +0000 Subject: [PATCH] Handle forward declaration of classes and prevent re-instantiation of ObjcInterfaceClass Objects. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42172 91177308-0d34-0410-b5e6-96231b3b80d8 --- Sema/SemaDecl.cpp | 40 ++++++++++++++++++++-------------- include/clang/AST/ASTContext.h | 8 +++---- include/clang/AST/Decl.h | 3 +++ test/Sema/forward-class-1.m | 22 +++++++++++++++++++ 4 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 test/Sema/forward-class-1.m diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index ca39e6e606..f46ec42cbd 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -869,22 +869,28 @@ Sema::DeclTy *Sema::ObjcStartClassInterface(SourceLocation AtInterfaceLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); - ObjcInterfaceDecl* IDecl; + ObjcInterfaceDecl* IDecl = Context.getObjCInterfaceDecl(ClassName); - if (Context.getObjCInterfaceDecl(ClassName)) - Diag(AtInterfaceLoc, diag::err_duplicate_class_def, ClassName->getName()); - - IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, ClassName); + if (IDecl) { + // Class already seen. Is it a forward declaration? + if (!IDecl->getIsForwardDecl()) + Diag(AtInterfaceLoc, diag::err_duplicate_class_def, ClassName->getName()); + else + IDecl->setIsForwardDecl(false); + } + else { + IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, ClassName); - // Chain & install the interface decl into the identifier. - IDecl->setNext(ClassName->getFETokenInfo()); - ClassName->setFETokenInfo(IDecl); + // Chain & install the interface decl into the identifier. + IDecl->setNext(ClassName->getFETokenInfo()); + ClassName->setFETokenInfo(IDecl); + } if (SuperName) { const ObjcInterfaceDecl* SuperClassEntry = Context.getObjCInterfaceDecl(SuperName); - if (!SuperClassEntry) { + if (!SuperClassEntry || SuperClassEntry->getIsForwardDecl()) { Diag(AtInterfaceLoc, diag::err_undef_superclass, SuperName->getName(), ClassName->getName()); } @@ -925,6 +931,7 @@ Sema::DeclTy *Sema::ObjcStartCatInterface(SourceLocation AtInterfaceLoc, cast(D)->setNext(CDecl); return CDecl; } + /// ObjcClassDeclaration - /// Scope will always be top level file scope. Action::DeclTy * @@ -934,13 +941,14 @@ Sema::ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, for (unsigned i = 0; i != NumElts; ++i) { ObjcInterfaceDecl *IDecl; - - // FIXME: before we create one, look up the interface decl in a hash table. - IDecl = new ObjcInterfaceDecl(SourceLocation(), IdentList[i], true); - // Chain & install the interface decl into the identifier. - IDecl->setNext(IdentList[i]->getFETokenInfo()); - IdentList[i]->setFETokenInfo(IDecl); - + IDecl = Context.getObjCInterfaceDecl(IdentList[i]); + if (!IDecl) {// Already seen? + IDecl = new ObjcInterfaceDecl(SourceLocation(), IdentList[i], true); + // Chain & install the interface decl into the identifier. + IDecl->setNext(IdentList[i]->getFETokenInfo()); + IdentList[i]->setFETokenInfo(IDecl); + Context.setObjCInterfaceDecl(IdentList[i], IDecl); + } // Remember that this needs to be removed when the scope is popped. S->AddDecl(IdentList[i]); diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f9a33e5795..0e4bab1eab 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -37,7 +37,7 @@ class ASTContext { llvm::FoldingSet FunctionTypeNoProtos; llvm::FoldingSet FunctionTypeProtos; llvm::DenseMap RecordLayoutInfo; - llvm::DenseMap ClassNameInfo; + llvm::DenseMap ClassNameInfo; RecordDecl *CFConstantStringTypeDecl; public: @@ -159,10 +159,10 @@ public: /// position information. const RecordLayout &getRecordLayout(const RecordDecl *D, SourceLocation L); - const ObjcInterfaceDecl* getObjCInterfaceDecl(const IdentifierInfo* ClassName) - { return ClassNameInfo[ClassName]; } + ObjcInterfaceDecl* getObjCInterfaceDecl(const IdentifierInfo* ClassName) + { return ClassNameInfo[ClassName]; } void setObjCInterfaceDecl(const IdentifierInfo* ClassName, - const ObjcInterfaceDecl* InterfaceDecl) + ObjcInterfaceDecl* InterfaceDecl) { ClassNameInfo[ClassName] = InterfaceDecl; } //===--------------------------------------------------------------------===// diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 67f5ebd756..40607cfd4f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -564,6 +564,9 @@ public: void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers, ObjcMethodDecl **clsMethods, unsigned numClsMembers); + bool getIsForwardDecl() const { return isForwardDecl; } + void setIsForwardDecl(bool val) { isForwardDecl = val; } + static bool classof(const Decl *D) { return D->getKind() == ObjcInterface; } diff --git a/test/Sema/forward-class-1.m b/test/Sema/forward-class-1.m new file mode 100644 index 0000000000..4e4e319c83 --- /dev/null +++ b/test/Sema/forward-class-1.m @@ -0,0 +1,22 @@ +@class FOO, BAR; +@class FOO, BAR; + +@interface INTF : FOO // expected-error {{cannot find interface declaration for 'FOO', superclass of 'INTF'}} +@end + +@interface FOO +- (BAR*) Meth1; +- (FOO*) Meth2; +@end + +@interface INTF1 : FOO +@end + +@interface INTF2 : INTF1 +@end + + +@class INTF1, INTF2; + +@interface INTF2 : INTF1 // expected-error {{duplicate interface declaration for class 'INTF2'}} +@end -- 2.50.1