]> granicus.if.org Git - clang/commitdiff
Handle forward declaration of classes and prevent re-instantiation of
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 20 Sep 2007 20:26:44 +0000 (20:26 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 20 Sep 2007 20:26:44 +0000 (20:26 +0000)
ObjcInterfaceClass Objects.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42172 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/SemaDecl.cpp
include/clang/AST/ASTContext.h
include/clang/AST/Decl.h
test/Sema/forward-class-1.m [new file with mode: 0644]

index ca39e6e606bb2e710a279bc18823047f46683204..f46ec42cbdd9f298cdcfaaa73745e6e4f671fc7a 100644 (file)
@@ -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<ScopedDecl>());
-  ClassName->setFETokenInfo(IDecl);
+    // Chain & install the interface decl into the identifier.
+    IDecl->setNext(ClassName->getFETokenInfo<ScopedDecl>());
+    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<ObjcInterfaceDecl>(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<ScopedDecl>());
-    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<ScopedDecl>());
+      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]);
     
index f9a33e57950789d399d4b497a53f373f43dffe4d..0e4bab1eab07e9f0f9bdb369b8d2de989284a4bc 100644 (file)
@@ -37,7 +37,7 @@ class ASTContext {
   llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
   llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
   llvm::DenseMap<const RecordDecl*, const RecordLayout*> RecordLayoutInfo;
-  llvm::DenseMap<const IdentifierInfo*, const ObjcInterfaceDecl*> ClassNameInfo;
+  llvm::DenseMap<const IdentifierInfo*, ObjcInterfaceDecl*> 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; }
   
   //===--------------------------------------------------------------------===//
index 67f5ebd756676a303e5aa1e91736e52935ad2e1c..40607cfd4f994127053db03fce8a79c343f162fc 100644 (file)
@@ -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 (file)
index 0000000..4e4e319
--- /dev/null
@@ -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