summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-10-14 06:48:06 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-10-14 06:48:06 +0000
commitb40034c2e580ab3b08de9dfb738d8e5d8ef79136 (patch)
tree7135179f3044eb13380b0fec707f8b25fc56bd38
parent905c45f15a25598620d19160c139c6b785aeea89 (diff)
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
-rw-r--r--include/clang/AST/ASTContext.h19
-rw-r--r--lib/AST/DeclObjC.cpp6
-rw-r--r--lib/Sema/SemaDeclObjC.cpp4
-rw-r--r--test/PCH/method-redecls.m13
4 files changed, 41 insertions, 1 deletions
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<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);
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<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this));
+ if (Redecl)
+ return Redecl;
+
Decl *CtxD = cast<Decl>(getDeclContext());
if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(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