diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-04-24 21:10:55 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-04-24 21:10:55 +0000 |
commit | f0aaf7a59729a4ae0146e3464ee987745be95829 (patch) | |
tree | 713860e07637f8137d9a5210f6fd6a9e325afca7 /lib | |
parent | d019d96e1ea39cec32f1320b1f9f772aae28247e (diff) |
PCH support for the global method pool (= instance and factory method
pools, combined). The methods in the global method pool are lazily
loaded from an on-disk hash table when Sema looks into its version of
the hash tables.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69989 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 135 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 173 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 32 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 96 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 4 |
6 files changed, 419 insertions, 25 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 62d0ba4f9f..5a1e882067 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1085,6 +1085,114 @@ unsigned PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { //===----------------------------------------------------------------------===// namespace { +class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait { + PCHReader &Reader; + +public: + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + + typedef Selector external_key_type; + typedef external_key_type internal_key_type; + + explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + return R; + } + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); + } + + internal_key_type ReadKey(const unsigned char* d, unsigned n) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext().Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); + if (N == 0) + return SelTable.getNullarySelector(FirstII); + else if (N == 1) + return SelTable.getUnarySelector(FirstII); + + llvm::SmallVector<IdentifierInfo *, 16> Args; + Args.push_back(FirstII); + for (unsigned I = 1; I != N; ++I) + Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d))); + + return SelTable.getSelector(N, &Args[0]); + } + + data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { + using namespace clang::io; + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); + + data_type Result; + + // Load instance methods + ObjCMethodList *Prev = 0; + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.first.Method) { + // This is the first method, which is the easy case. + Result.first.Method = Method; + Prev = &Result.first; + continue; + } + + Prev->Next = new ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + // Load factory methods + Prev = 0; + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.second.Method) { + // This is the first method, which is the easy case. + Result.second.Method = Method; + Prev = &Result.second; + continue; + } + + Prev->Next = new ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + return Result; + } +}; + +} // end anonymous namespace + +/// \brief The on-disk hash table used for the global method pool. +typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait> + PCHMethodPoolLookupTable; + +namespace { class VISIBILITY_HIDDEN PCHIdentifierLookupTrait { PCHReader &Reader; @@ -1844,6 +1952,14 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset, } LocallyScopedExternalDecls.swap(Record); break; + + case pch::METHOD_POOL: + MethodPoolLookupTable + = PCHMethodPoolLookupTable::Create( + (const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + PCHMethodPoolLookupTrait(*this)); + break; } } Error("Premature end of bitstream"); @@ -2539,6 +2655,7 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) { return 0; unsigned Index = ID - 1; + assert(Index < DeclAlreadyLoaded.size() && "Declaration ID out of range"); if (DeclAlreadyLoaded[Index]) return reinterpret_cast<Decl *>(DeclOffsets[Index]); @@ -2679,7 +2796,8 @@ void PCHReader::PrintStats() { void PCHReader::InitializeSema(Sema &S) { SemaObj = &S; - + S.ExternalSource = this; + // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { @@ -2719,6 +2837,21 @@ IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) { return *Pos; } +std::pair<ObjCMethodList, ObjCMethodList> +PCHReader::ReadMethodPool(Selector Sel) { + if (!MethodPoolLookupTable) + return std::pair<ObjCMethodList, ObjCMethodList>(); + + // Try to find this selector within our on-disk hash table. + PCHMethodPoolLookupTable *PoolTable + = (PCHMethodPoolLookupTable*)MethodPoolLookupTable; + PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel); + if (Pos == PoolTable->end()) + return std::pair<ObjCMethodList, ObjCMethodList>();; + + return *Pos; +} + void PCHReader::SetIdentifierInfo(unsigned ID, const IdentifierInfo *II) { assert(ID && "Non-zero identifier ID required"); IdentifierData[ID - 1] = reinterpret_cast<uint64_t>(II); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index de4b9990b1..581ca051a5 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1774,6 +1774,176 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { } namespace { +// Trait used for the on-disk hash table used in the method pool. +class VISIBILITY_HIDDEN PCHMethodPoolTrait { + PCHWriter &Writer; + +public: + typedef Selector key_type; + typedef key_type key_type_ref; + + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + typedef const data_type& data_type_ref; + + explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + return R; + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel, + data_type_ref Methods) { + unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); + clang::io::Emit16(Out, KeyLen); + unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + clang::io::Emit16(Out, DataLen); + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) { + // FIXME: Keep track of the location of the key data (the + // selector), so we can fold the selector table's storage into + // this hash table. + unsigned N = Sel.getNumArgs(); + clang::io::Emit16(Out, N); + if (N == 0) + N = 1; + for (unsigned I = 0; I != N; ++I) + clang::io::Emit32(Out, + Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); + } + + void EmitData(llvm::raw_ostream& Out, key_type_ref, + data_type_ref Methods, unsigned) { + unsigned NumInstanceMethods = 0; + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + ++NumInstanceMethods; + + unsigned NumFactoryMethods = 0; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + ++NumFactoryMethods; + + clang::io::Emit16(Out, NumInstanceMethods); + clang::io::Emit16(Out, NumFactoryMethods); + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + clang::io::Emit16(Out, NumFactoryMethods); + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + } +}; +} // end anonymous namespace + +/// \brief Write the method pool into the PCH file. +/// +/// The method pool contains both instance and factory methods, stored +/// in an on-disk hash table indexed by the selector. +void PCHWriter::WriteMethodPool(Sema &SemaRef) { + using namespace llvm; + + // Create and write out the blob that contains the instance and + // factor method pools. + bool Empty = true; + { + OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator; + + // Create the on-disk hash table representation. Start by + // iterating through the instance method pool. + PCHMethodPoolTrait::key_type Key; + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Instance = SemaRef.InstanceMethodPool.begin(), + InstanceEnd = SemaRef.InstanceMethodPool.end(); + Instance != InstanceEnd; ++Instance) { + // Check whether there is a factory method with the same + // selector. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory + = SemaRef.FactoryMethodPool.find(Instance->first); + + if (Factory == SemaRef.FactoryMethodPool.end()) + Generator.insert(Instance->first, + std::make_pair(Instance->second, + ObjCMethodList())); + else + Generator.insert(Instance->first, + std::make_pair(Instance->second, Factory->second)); + + Empty = false; + } + + // Now iterate through the factory method pool, to pick up any + // selectors that weren't already in the instance method pool. + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Factory = SemaRef.FactoryMethodPool.begin(), + FactoryEnd = SemaRef.FactoryMethodPool.end(); + Factory != FactoryEnd; ++Factory) { + // Check whether there is an instance method with the same + // selector. If so, there is no work to do here. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance + = SemaRef.InstanceMethodPool.find(Factory->first); + + if (Instance == SemaRef.InstanceMethodPool.end()) + Generator.insert(Factory->first, + std::make_pair(ObjCMethodList(), Factory->second)); + + Empty = false; + } + + if (Empty) + return; + + // Create the on-disk hash table in a buffer. + llvm::SmallVector<char, 4096> MethodPool; + uint32_t BucketOffset; + { + PCHMethodPoolTrait Trait(*this); + llvm::raw_svector_ostream Out(MethodPool); + // Make sure that no bucket is at offset 0 + clang::io::Emit16(Out, 0); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the identifier table + RecordData Record; + Record.push_back(pch::METHOD_POOL); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, + &MethodPool.front(), + MethodPool.size()); + } +} + +namespace { class VISIBILITY_HIDDEN PCHIdentifierTableTrait { PCHWriter &Writer; Preprocessor &PP; @@ -1880,6 +2050,8 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { { PCHIdentifierTableTrait Trait(*this, PP); llvm::raw_svector_ostream Out(IdentifierTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit16(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } @@ -2113,6 +2285,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) { WritePreprocessor(PP); WriteTypesBlock(Context); WriteDeclsBlock(Context); + WriteMethodPool(SemaRef); WriteSelectorTable(); WriteIdentifierTable(PP); Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3702c89cf6..367c9f5756 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -163,8 +163,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit) : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), - SourceMgr(PP.getSourceManager()), CurContext(0), PreDeclaratorDC(0), + Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), + ExternalSource(0), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b3cb5e25fb..7426965a44 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -19,13 +19,13 @@ #include "CXXFieldCollector.h" #include "SemaOverload.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclObjC.h" #include "clang/Parse/Action.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" -#include "clang/AST/DeclObjC.h" #include <string> #include <vector> @@ -40,6 +40,7 @@ namespace clang { class Decl; class DeclContext; class DeclSpec; + class ExternalSemaSource; class NamedDecl; class Stmt; class Expr; @@ -128,6 +129,9 @@ public: Diagnostic &Diags; SourceManager &SourceMgr; + /// \brief Source of additional semantic information. + ExternalSemaSource *ExternalSource; + /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; @@ -243,27 +247,17 @@ public: /// unit. bool CompleteTranslationUnit; - /// ObjCMethodList - a linked list of methods with different signatures. - struct ObjCMethodList { - ObjCMethodDecl *Method; - ObjCMethodList *Next; - - ObjCMethodList() { - Method = 0; - Next = 0; - } - ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { - Method = M; - Next = C; - } - }; + typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool; + /// Instance/Factory Method Pools - allows efficient lookup when typechecking /// messages to "id". We need to maintain a list, since selectors can have /// differing signatures across classes. In Cocoa, this happens to be /// extremely uncommon (only 1% of selectors are "overloaded"). - llvm::DenseMap<Selector, ObjCMethodList> InstanceMethodPool; - llvm::DenseMap<Selector, ObjCMethodList> FactoryMethodPool; + MethodPool InstanceMethodPool; + MethodPool FactoryMethodPool; + MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance); + /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); public: @@ -1126,6 +1120,10 @@ public: /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R); + + /// LookupFactoryMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R); /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f4014d1f25..05e471b10d 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -1090,8 +1091,47 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, return true; } +/// \brief Read the contents of the instance and factory method pools +/// for a given selector from external storage. +/// +/// This routine should only be called once, when neither the instance +/// nor the factory method pool has an entry for this selector. +Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, + bool isInstance) { + assert(ExternalSource && "We need an external AST source"); + assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() && + "Selector data already loaded into the instance method pool"); + assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() && + "Selector data already loaded into the factory method pool"); + + // Read the method list from the external source. + std::pair<ObjCMethodList, ObjCMethodList> Methods + = ExternalSource->ReadMethodPool(Sel); + + if (isInstance) { + if (Methods.second.Method) + FactoryMethodPool[Sel] = Methods.second; + return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first; + } + + if (Methods.first.Method) + InstanceMethodPool[Sel] = Methods.first; + + return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first; +} + void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { - ObjCMethodList &Entry = InstanceMethodPool[Method->getSelector()]; + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = InstanceMethodPool.find(Method->getSelector()); + if (Pos == InstanceMethodPool.end()) { + if (ExternalSource && !FactoryMethodPool.count(Method->getSelector())) + Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true); + else + Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(), + ObjCMethodList())).first; + } + + ObjCMethodList &Entry = Pos->second; if (Entry.Method == 0) { // Haven't seen a method with this selector name yet - add it. Entry.Method = Method; @@ -1113,7 +1153,16 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { // FIXME: Finish implementing -Wno-strict-selector-match. ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R) { - ObjCMethodList &MethList = InstanceMethodPool[Sel]; + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = InstanceMethodPool.find(Sel); + if (Pos == InstanceMethodPool.end() && !FactoryMethodPool.count(Sel)) { + if (ExternalSource) + Pos = ReadMethodPool(Sel, /*isInstance=*/true); + else + return 0; + } + + ObjCMethodList &MethList = Pos->second; bool issueWarning = false; if (MethList.Method && MethList.Next) { @@ -1134,7 +1183,17 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, } void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { - ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()]; + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = FactoryMethodPool.find(Method->getSelector()); + if (Pos == FactoryMethodPool.end()) { + if (ExternalSource && !InstanceMethodPool.count(Method->getSelector())) + Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false); + else + Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(), + ObjCMethodList())).first; + } + + ObjCMethodList &FirstMethod = Pos->second; if (!FirstMethod.Method) { // Haven't seen a method with this selector name yet - add it. FirstMethod.Method = Method; @@ -1156,6 +1215,37 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { } } +ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, + SourceRange R) { + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = FactoryMethodPool.find(Sel); + if (Pos == FactoryMethodPool.end()) { + if (ExternalSource && !InstanceMethodPool.count(Sel)) + Pos = ReadMethodPool(Sel, /*isInstance=*/false); + else + return 0; + } + + ObjCMethodList &MethList = Pos->second; + bool issueWarning = false; + + if (MethList.Method && MethList.Next) { + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + // This checks if the methods differ by size & alignment. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) + issueWarning = true; + } + if (issueWarning && (MethList.Method && MethList.Next)) { + Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; + Diag(MethList.Method->getLocStart(), diag::note_using_decl) + << MethList.Method->getSourceRange(); + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + << Next->Method->getSourceRange(); + } + return MethList.Method; +} + /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods /// have the property type and issue diagnostics if they don't. /// Also synthesize a getter/setter method if none exist (and update the diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d48ba4470c..f2cd00195f 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -497,7 +497,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( Sel, SourceRange(lbrac,rbrac)); if (!Method) - Method = FactoryMethodPool[Sel].Method; + Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac)); if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true; @@ -523,7 +523,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!isSelfExpr(RExpr)) { - Method = FactoryMethodPool[Sel].Method; + Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); if (!Method) { Method = LookupInstanceMethodInGlobalPool( Sel, SourceRange(lbrac,rbrac)); |