]> granicus.if.org Git - clang/commitdiff
Keep track of objc method redeclarations in the same interface.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 14 Oct 2011 06:48:06 +0000 (06:48 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 14 Oct 2011 06:48:06 +0000 (06:48 +0000)
Avoid possible infinite loop when iterating over an ObjCMethod's redeclarations.

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

include/clang/AST/ASTContext.h
lib/AST/DeclObjC.cpp
lib/Sema/SemaDeclObjC.cpp
test/PCH/method-redecls.m [new file with mode: 0644]

index 09defdb31e1058611c04deb59774ef8ad2ea8559..05311ff0bf37bebf9acd5ed9b304e36d42397c6f 100644 (file)
@@ -150,6 +150,10 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
   
   /// \brief Mapping from ObjCContainers to their ObjCImplementations.
   llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
+  
+  /// \brief Mapping from ObjCMethod to its duplicate declaration in the same
+  /// interface.
+  llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
 
   /// \brief Mapping from __block VarDecls to their copy initialization expr.
   llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
@@ -1585,6 +1589,21 @@ public:
   /// \brief Set the implementation of ObjCCategoryDecl.
   void setObjCImplementation(ObjCCategoryDecl *CatD,
                              ObjCCategoryImplDecl *ImplD);
+
+  /// \brief Get the duplicate declaration of a ObjCMethod in the same
+  /// interface, or null if non exists.
+  const ObjCMethodDecl *getObjCMethodRedeclaration(ObjCMethodDecl *MD) const {
+    llvm::DenseMap<const ObjCMethodDecl*, const ObjCMethodDecl*>::const_iterator
+      I = ObjCMethodRedecls.find(MD);
+    if (I == ObjCMethodRedecls.end())
+      return 0;
+    return I->second;
+  }
+
+  void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
+                                  const ObjCMethodDecl *Redecl) {
+    ObjCMethodRedecls[MD] = Redecl;
+  }
   
   /// \brief Set the copy inialization expression of a block var decl.
   void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
index 48fbbe0c2b41d456b5e1413e9c9bf6835979565f..7c1332ab103eb3e4b0a42de166718b334348a912 100644 (file)
@@ -392,7 +392,11 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C,
 /// Otherwise it will return itself.
 ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
   ASTContext &Ctx = getASTContext();
-  ObjCMethodDecl *Redecl = 0;
+  ObjCMethodDecl *Redecl =
+      const_cast<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this));
+  if (Redecl)
+    return Redecl;
+
   Decl *CtxD = cast<Decl>(getDeclContext());
 
   if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
index 82b5b17fa4df03a3987d81fa3e033a6cdb806086..bdf492bbc1e39fa5032a7f5679c086b086743075 100644 (file)
@@ -2167,6 +2167,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
           Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
         Method->setInvalidDecl();
       } else {
+        if (PrevMethod)
+          Context.setObjCMethodRedeclaration(PrevMethod, Method);
         InsMap[Method->getSelector()] = Method;
         /// The following allows us to typecheck messages to "id".
         AddInstanceMethodToGlobalPool(Method);
@@ -2186,6 +2188,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
         Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
         Method->setInvalidDecl();
       } else {
+        if (PrevMethod)
+          Context.setObjCMethodRedeclaration(PrevMethod, Method);
         ClsMap[Method->getSelector()] = Method;
         /// The following allows us to typecheck messages to "Class".
         AddFactoryMethodToGlobalPool(Method);
diff --git a/test/PCH/method-redecls.m b/test/PCH/method-redecls.m
new file mode 100644 (file)
index 0000000..14ce3ac
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t
+
+// Avoid infinite loop because of method redeclarations.
+
+@interface Foo
+-(void)meth;
+-(void)meth;
+-(void)meth;
+@end
+
+@implementation Foo
+-(void)meth { }
+@end