From: Argyrios Kyrtzidis Date: Fri, 14 Oct 2011 06:48:06 +0000 (+0000) Subject: Keep track of objc method redeclarations in the same interface. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b40034c2e580ab3b08de9dfb738d8e5d8ef79136;p=clang Keep track of objc method redeclarations in the same interface. 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 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 09defdb31e..05311ff0bf 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -150,6 +150,10 @@ class ASTContext : public llvm::RefCountedBase { /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap ObjCImpls; + + /// \brief Mapping from ObjCMethod to its duplicate declaration in the same + /// interface. + llvm::DenseMap ObjCMethodRedecls; /// \brief Mapping from __block VarDecls to their copy initialization expr. llvm::DenseMap 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_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); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 48fbbe0c2b..7c1332ab10 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -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(Ctx.getObjCMethodRedeclaration(this)); + if (Redecl) + return Redecl; + Decl *CtxD = cast(getDeclContext()); if (ObjCInterfaceDecl *IFD = dyn_cast(CtxD)) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 82b5b17fa4..bdf492bbc1 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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 index 0000000000..14ce3acdfd --- /dev/null +++ b/test/PCH/method-redecls.m @@ -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