diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1419,7 +1419,12 @@ const llvm::MapVector & getMismatchingDeleteExpressions() const; - typedef std::pair GlobalMethods; + struct GlobalMethods { + ObjCMethodList InstanceMethods; + ObjCMethodList FactoryMethods; + llvm::DenseSet AddedInstanceMethods; + llvm::DenseSet AddedFactoryMethods; + }; typedef llvm::DenseMap GlobalMethodPool; /// Method Pool - allows efficient lookup when typechecking messages to "id". @@ -4490,7 +4495,9 @@ void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// Add the given method to the list of globally-known methods. - void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); + void addMethodToGlobalList(ObjCMethodList *List, + llvm::DenseSet *AddedMethods, + ObjCMethodDecl *Method); /// Returns default addr space for method qualifiers. LangAS getDefaultCXXMethodAddrSpace() const; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -7693,7 +7693,7 @@ for (Sema::GlobalMethodPool::iterator M = SemaRef.MethodPool.begin(), MEnd = SemaRef.MethodPool.end(); M != MEnd; ++M) { - for (ObjCMethodList *MethList = &M->second.second; + for (ObjCMethodList *MethList = &M->second.FactoryMethods; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; @@ -7865,7 +7865,7 @@ for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { - for (ObjCMethodList *MethList = &M->second.first; + for (ObjCMethodList *MethList = &M->second.InstanceMethods; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; @@ -9266,8 +9266,9 @@ for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { - for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first - : &M->second.second; + for (ObjCMethodList *MethList = IsInstanceMethod + ? &M->second.InstanceMethods + : &M->second.FactoryMethods; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3301,7 +3301,12 @@ } void Sema::addMethodToGlobalList(ObjCMethodList *List, + llvm::DenseSet *AddedMethods, ObjCMethodDecl *Method) { + // Don't include duplicate methods + if (!AddedMethods->insert(Method).second) + return; + // Record at the head of the list whether there were 0, 1, or >= 2 methods // inside categories. if (ObjCCategoryDecl *CD = @@ -3432,8 +3437,11 @@ Method->setDefined(impl); - ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; - addMethodToGlobalList(&Entry, Method); + ObjCMethodList &Entry = + instance ? Pos->second.InstanceMethods : Pos->second.FactoryMethods; + auto &AddedMethods = instance ? Pos->second.AddedInstanceMethods + : Pos->second.AddedFactoryMethods; + addMethodToGlobalList(&Entry, &AddedMethods, Method); } /// Determines if this is an "acceptable" loose mismatch in the global @@ -3505,8 +3513,8 @@ return false; // Gather the non-hidden methods. - ObjCMethodList &MethList = InstanceFirst ? Pos->second.first : - Pos->second.second; + ObjCMethodList &MethList = + InstanceFirst ? Pos->second.InstanceMethods : Pos->second.FactoryMethods; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) { if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) @@ -3521,8 +3529,8 @@ return false; // Gather the other kind. - ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second : - Pos->second.first; + ObjCMethodList &MethList2 = + InstanceFirst ? Pos->second.FactoryMethods : Pos->second.InstanceMethods; for (ObjCMethodList *M = &MethList2; M; M = M->getNext()) if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) { if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) @@ -3552,8 +3560,9 @@ // caller. if (Pos == MethodPool.end()) return true; - ObjCMethodList &MethList = - BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second; + ObjCMethodList &MethList = BestMethod->isInstanceMethod() + ? Pos->second.InstanceMethods + : Pos->second.FactoryMethods; return MethList.hasMoreThanOneDecl(); } @@ -3568,7 +3577,8 @@ return nullptr; // Gather the non-hidden methods. - ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + ObjCMethodList &MethList = + instance ? Pos->second.InstanceMethods : Pos->second.FactoryMethods; SmallVector Methods; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) @@ -3637,14 +3647,14 @@ return nullptr; GlobalMethods &Methods = Pos->second; - for (const ObjCMethodList *Method = &Methods.first; Method; + for (const ObjCMethodList *Method = &Methods.InstanceMethods; Method; Method = Method->getNext()) if (Method->getMethod() && (Method->getMethod()->isDefined() || Method->getMethod()->isPropertyAccessor())) return Method->getMethod(); - for (const ObjCMethodList *Method = &Methods.second; Method; + for (const ObjCMethodList *Method = &Methods.FactoryMethods; Method; Method = Method->getNext()) if (Method->getMethod() && (Method->getMethod()->isDefined() || @@ -3711,7 +3721,7 @@ for (GlobalMethodPool::iterator b = MethodPool.begin(), e = MethodPool.end(); b != e; b++) { // instance methods - for (ObjCMethodList *M = &b->second.first; M; M=M->getNext()) + for (ObjCMethodList *M = &b->second.InstanceMethods; M; M = M->getNext()) if (M->getMethod() && (M->getMethod()->getSelector().getNumArgs() == NumArgs) && (M->getMethod()->getSelector() != Sel)) { @@ -3723,7 +3733,7 @@ Methods.push_back(M->getMethod()); } // class methods - for (ObjCMethodList *M = &b->second.second; M; M=M->getNext()) + for (ObjCMethodList *M = &b->second.FactoryMethods; M; M = M->getNext()) if (M->getMethod() && (M->getMethod()->getSelector().getNumArgs() == NumArgs) && (M->getMethod()->getSelector() != Sel)) { @@ -4281,8 +4291,9 @@ if (it == S.MethodPool.end()) return; } - const ObjCMethodList &list = - method->isInstanceMethod() ? it->second.first : it->second.second; + const ObjCMethodList &list = method->isInstanceMethod() + ? it->second.InstanceMethods + : it->second.FactoryMethods; if (!list.getMethod()) return; const ObjCContainerDecl *container @@ -4450,8 +4461,9 @@ GlobalMethodPool::iterator It = MethodPool.find(ObjCMethod->getSelector()); if (It != MethodPool.end()) { - ObjCMethodList &List = - ObjCMethod->isInstanceMethod()? It->second.first: It->second.second; + ObjCMethodList &List = ObjCMethod->isInstanceMethod() + ? It->second.InstanceMethods + : It->second.FactoryMethods; unsigned CategCount = List.getBits(); if (CategCount > 0) { // If the method is in a category we'll do lookup if there were at diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1215,13 +1215,13 @@ for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), e = S.MethodPool.end(); b != e; b++) { // first, instance methods - ObjCMethodList &InstMethList = b->second.first; + ObjCMethodList &InstMethList = b->second.InstanceMethods; if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc, Method, InstMethList)) Warned = true; // second, class methods - ObjCMethodList &ClsMethList = b->second.second; + ObjCMethodList &ClsMethList = b->second.FactoryMethods; if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc, Method, ClsMethList) || Warned) return; @@ -1262,9 +1262,9 @@ return nullptr; ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList( - S, Sel, Iter->second.first, onlyDirect, anyDirect); + S, Sel, Iter->second.InstanceMethods, onlyDirect, anyDirect); ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList( - S, Sel, Iter->second.second, onlyDirect, anyDirect); + S, Sel, Iter->second.FactoryMethods, onlyDirect, anyDirect); return DirectInstance ? DirectInstance : DirectClass; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4006,8 +4006,9 @@ return; // Retrieve the appropriate method list. - ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first - : Known->second.second; + ObjCMethodList &Start = Method->isInstanceMethod() + ? Known->second.InstanceMethods + : Known->second.FactoryMethods; bool Found = false; for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { @@ -8180,9 +8181,10 @@ /// Add the given set of methods to the method list. static void addMethodsToPool(Sema &S, ArrayRef Methods, - ObjCMethodList &List) { - for (unsigned I = 0, N = Methods.size(); I != N; ++I) { - S.addMethodToGlobalList(&List, Methods[I]); + ObjCMethodList &List, + llvm::DenseSet &AddedMethods) { + for (auto *M : Methods) { + S.addMethodToGlobalList(&List, &AddedMethods, M); } } @@ -8211,16 +8213,20 @@ Sema::GlobalMethodPool::iterator Pos = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; - Pos->second.first.setBits(Visitor.getInstanceBits()); - Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl()); - Pos->second.second.setBits(Visitor.getFactoryBits()); - Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl()); + Pos->second.InstanceMethods.setBits(Visitor.getInstanceBits()); + Pos->second.InstanceMethods.setHasMoreThanOneDecl( + Visitor.instanceHasMoreThanOneDecl()); + Pos->second.FactoryMethods.setBits(Visitor.getFactoryBits()); + Pos->second.FactoryMethods.setHasMoreThanOneDecl( + Visitor.factoryHasMoreThanOneDecl()); // Add methods to the global pool *after* setting hasMoreThanOneDecl, since // when building a module we keep every method individually and may need to // update hasMoreThanOneDecl as we add the methods. - addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); - addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); + addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.InstanceMethods, + Pos->second.AddedInstanceMethods); + addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.FactoryMethods, + Pos->second.AddedFactoryMethods); } void ASTReader::updateOutOfDateSelector(Selector Sel) { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3122,8 +3122,8 @@ ObjCMethodList() }; if (F != SemaRef.MethodPool.end()) { - Data.Instance = F->second.first; - Data.Factory = F->second.second; + Data.Instance = F->second.InstanceMethods; + Data.Factory = F->second.FactoryMethods; } // Only write this selector if it's not in an existing AST or something // changed.