Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -1225,59 +1225,174 @@ /// single result (with no stable storage) or a collection of results (with /// stable storage provided by the lookup table). class DeclContextLookupResult { - using ResultTy = ArrayRef; + friend class StoredDeclsList; + struct ListNode; + /// When in collection form, this is what the Data pointer points to. + using Decls = llvm::PointerUnion; + class ListNode { + friend class StoredDeclsList; + NamedDecl *D = nullptr; + Decls Rest = nullptr; + public: + ListNode(NamedDecl *ND) : D(ND) {} + bool empty() const { + assert((D || Rest.isNull()) && "D must be not nullptr if Rest is set."); + return !D && Rest.isNull(); + } - ResultTy Result; + template + class ListNodeIterator { + friend class ListNode; + friend class DeclContextLookupResult; + using ConstIterator = ListNodeIterator; + public: + using difference_type = ptrdiff_t; + using value_type = + typename std::conditional::type; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; + private: + Decls Ptr = nullptr; + ListNodeIterator(Decls Node) : Ptr(Node) { } + bool isNamedDecl() const { return Ptr.dyn_cast(); } + public: + ListNodeIterator() = default; + // Converting ctor from non-const iterators to const iterators. SFINAE'd + // out for const iterator destinations so it doesn't end up as a user + // defined copy constructor. + template > + ListNodeIterator(const ListNodeIterator &I) : Ptr(I.Ptr) {} + + reference operator*() const { + assert(Ptr && "dereferencing end() iterator"); + // FIXME: Remove the const_casts... + if (isNamedDecl()) + return *(const_cast(Ptr.getAddrOfPtr1())); + return Ptr.get()->D; + } + pointer operator->() const { + assert(Ptr && "dereferencing end() iterator"); + return isNamedDecl() ? Ptr.getAddrOfPtr1() : &Ptr.get()->D; + } + bool operator==(const ConstIterator &X) const { return Ptr == X.Ptr; } + bool operator!=(const ConstIterator &X) const { return Ptr != X.Ptr; } + inline ListNodeIterator& operator++() { // ++It + assert(!Ptr.isNull() && "Advancing empty iterator"); + assert((Ptr.dyn_cast() || Ptr.dyn_cast()) && + "Advancing empty iterator"); + + Ptr = !isNamedDecl() ? Ptr.get()->Rest : nullptr; + return *this; + } + ListNodeIterator operator++(int) { // It++ + ListNodeIterator temp = *this; + ++(*this); + return temp; + } + }; + using iterator = ListNodeIterator; + using const_iterator = ListNodeIterator; + + iterator begin() { return empty() ? end() : iterator(this); } + iterator end() { return iterator(); } + + // const_iterator begin() { return empty() ? end() : const_iterator(this); } + // const_iterator end() const { return const_iterator(); } + + void push_back(NamedDecl *ND) { + assert(D && "No need to call push_back"); + ListNode *Node = new ListNode(ND); + + ListNode *Prev = this; + while(Prev->Rest) + Prev = Prev->Rest.get(); + + Prev->Rest = Node; + } - // If there is only one lookup result, it would be invalidated by - // reallocations of the name table, so store it separately. - NamedDecl *Single = nullptr; + template + void erase_if(Pred pred) { + ListNode *Prev = this; + if (D && Rest.isNull()) { + if (!pred(D)) + D = nullptr; + return; + } + + while(Prev && !pred(Prev->Rest.get()->D)) + Prev = Prev->Rest.get(); + + assert(Prev && "list does not contain decl"); + ListNode *ToDelete = Prev->Rest.get(); + Prev->Rest = ToDelete->Rest; + delete ToDelete; + } + + void erase(NamedDecl *ND) { + erase_if([ND](NamedDecl *D){ return D == ND; }); + } + }; - static NamedDecl *const SingleElementDummyList; + Decls Result = nullptr; public: DeclContextLookupResult() = default; - DeclContextLookupResult(ArrayRef Result) - : Result(Result) {} - DeclContextLookupResult(NamedDecl *Single) - : Result(SingleElementDummyList), Single(Single) {} - - class iterator; - - using IteratorBase = - llvm::iterator_adaptor_base; - - class iterator : public IteratorBase { - value_type SingleElement; - - public: - explicit iterator(pointer Pos, value_type Single = nullptr) - : IteratorBase(Pos), SingleElement(Single) {} - - reference operator*() const { - return SingleElement ? SingleElement : IteratorBase::operator*(); - } - }; + DeclContextLookupResult(Decls Result) : Result(Result) {} + using iterator = ListNode::ListNodeIterator; + // FIXME: Add a proper const iterator + //using const_iterator = ListNode::ListNodeIterator; using const_iterator = iterator; - using pointer = iterator::pointer; using reference = iterator::reference; - iterator begin() const { return iterator(Result.begin(), Single); } - iterator end() const { return iterator(Result.end(), Single); } + iterator begin() { + if (empty()) + return end(); + return iterator(Result); + } + iterator end() { return iterator(); } + const_iterator begin() const { + return const_cast(this)->begin(); + } + const_iterator end() const { return iterator(); } + + bool empty() const { + if (Result.isNull()) + return true; + // Might have been prepared to be filled later (see setHasExternalDecls). + if (Result.dyn_cast() || !Result.get()->empty()) + return false; + return true; + } + bool isSingleResult() const { + return !empty() && Result.dyn_cast(); + } + bool equals(const DeclContextLookupResult &RHS) const { + if (empty() && RHS.empty()) + return true; + if (empty() == RHS.empty()) + return true; + if (isSingleResult() == RHS.isSingleResult()) + return true; - bool empty() const { return Result.empty(); } - pointer data() const { return Single ? &Single : Result.data(); } - size_t size() const { return Single ? 1 : Result.size(); } - reference front() const { return Single ? Single : Result.front(); } - reference back() const { return Single ? Single : Result.back(); } - reference operator[](size_t N) const { return Single ? Single : Result[N]; } + //FIXME: We should probably copy, sort and compare one by one. + DeclContextLookupResult X = *this; + DeclContextLookupResult Y = RHS; + return std::distance(X.begin(), X.end()) == + std::distance(Y.begin(), Y.end()); + } + reference front() const { return *begin(); } // FIXME: Remove this from the interface DeclContextLookupResult slice(size_t N) const { - DeclContextLookupResult Sliced = Result.slice(N); - Sliced.Single = Single; + assert(N <= (size_t)std::distance(begin(), end())); + auto I = begin(); + while(N--) + ++I; + + DeclContextLookupResult Sliced(I.Ptr); return Sliced; } }; Index: clang/include/clang/AST/DeclContextInternals.h =================================================================== --- clang/include/clang/AST/DeclContextInternals.h +++ clang/include/clang/AST/DeclContextInternals.h @@ -21,7 +21,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/SmallVector.h" #include #include @@ -32,51 +31,52 @@ /// An array of decls optimized for the common case of only containing /// one entry. struct StoredDeclsList { - /// When in vector form, this is what the Data pointer points to. - using DeclsTy = SmallVector; + using DeclsTy = DeclContextLookupResult::ListNode; + using Decls = DeclContextLookupResult::Decls; /// A collection of declarations, with a flag to indicate if we have /// further external declarations. - using DeclsAndHasExternalTy = llvm::PointerIntPair; + using DeclsAndHasExternalTy = llvm::PointerIntPair; /// The stored data, which will be either a pointer to a NamedDecl, /// or a pointer to a vector with a flag to indicate if there are further /// external declarations. - llvm::PointerUnion Data; - + DeclsAndHasExternalTy Data; public: StoredDeclsList() = default; StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) { - RHS.Data = (NamedDecl *)nullptr; + RHS.Data.setPointer(nullptr); + RHS.Data.setInt(0); } ~StoredDeclsList() { // If this is a vector-form, free the vector. if (DeclsTy *Vector = getAsVector()) - delete Vector; + Vector->~DeclsTy(); } StoredDeclsList &operator=(StoredDeclsList &&RHS) { if (DeclsTy *Vector = getAsVector()) delete Vector; Data = RHS.Data; - RHS.Data = (NamedDecl *)nullptr; + RHS.Data.setPointer(nullptr); + RHS.Data.setInt(0); return *this; } - bool isNull() const { return Data.isNull(); } + bool isNull() const { return Data.getPointer().isNull(); } NamedDecl *getAsDecl() const { - return Data.dyn_cast(); + return getAsVectorAndHasExternal().getPointer().dyn_cast(); } DeclsAndHasExternalTy getAsVectorAndHasExternal() const { - return Data.dyn_cast(); + return Data; } DeclsTy *getAsVector() const { - return getAsVectorAndHasExternal().getPointer(); + return getAsVectorAndHasExternal().getPointer().dyn_cast(); } bool hasExternalDecls() const { @@ -87,19 +87,20 @@ if (DeclsTy *Vec = getAsVector()) Data = DeclsAndHasExternalTy(Vec, true); else { - DeclsTy *VT = new DeclsTy(); - if (NamedDecl *OldD = getAsDecl()) - VT->push_back(OldD); - Data = DeclsAndHasExternalTy(VT, true); + if (NamedDecl *OldD = getAsDecl()) { + DeclsTy *VT = new DeclsTy(OldD); + Data = DeclsAndHasExternalTy(VT, true); + } + Data.setInt(1); } } void setOnlyValue(NamedDecl *ND) { assert(!getAsVector() && "Not inline"); - Data = ND; + Data.setPointer(ND); // Make sure that Data is a plain NamedDecl* so we can use its address // at getLookupResult. - assert(*(NamedDecl **)&Data == ND && + assert(*(NamedDecl **)Data.getPointer().getAddrOfPtr1() == ND && "PointerUnion mangles the NamedDecl pointer!"); } @@ -108,14 +109,13 @@ if (NamedDecl *Singleton = getAsDecl()) { assert(Singleton == D && "list is different singleton"); (void)Singleton; - Data = (NamedDecl *)nullptr; + Data.setPointer(nullptr); + Data.setInt(0); return; } DeclsTy &Vec = *getAsVector(); - DeclsTy::iterator I = llvm::find(Vec, D); - assert(I != Vec.end() && "list does not contain decl"); - Vec.erase(I); + Vec.erase(D); assert(llvm::find(Vec, D) == Vec.end() && "list still contains decl"); } @@ -130,33 +130,20 @@ *this = StoredDeclsList(); } else { DeclsTy &Vec = *getAsVector(); - Vec.erase(std::remove_if(Vec.begin(), Vec.end(), - [](Decl *D) { return D->isFromASTFile(); }), - Vec.end()); + Vec.erase_if([](NamedDecl *ND){ return ND->isFromASTFile(); }); + // Don't have any external decls any more. - Data = DeclsAndHasExternalTy(&Vec, false); + if (Vec.empty()) + Data = DeclsAndHasExternalTy((DeclsTy *) nullptr, false); + else + Data = DeclsAndHasExternalTy(&Vec, false); } } /// getLookupResult - Return an array of all the decls that this list /// represents. DeclContext::lookup_result getLookupResult() { - if (isNull()) - return DeclContext::lookup_result(); - - // If we have a single NamedDecl, return it. - if (NamedDecl *ND = getAsDecl()) { - assert(!isNull() && "Empty list isn't allowed"); - - // Data is a raw pointer to a NamedDecl*, return it. - return DeclContext::lookup_result(ND); - } - - assert(getAsVector() && "Must have a vector at this point"); - DeclsTy &Vector = *getAsVector(); - - // Otherwise, we have a range result. - return DeclContext::lookup_result(Vector); + return DeclContext::lookup_result(Data.getPointer()); } /// HandleRedeclaration - If this is a redeclaration of an existing decl, @@ -192,70 +179,32 @@ // If this is the second decl added to the list, convert this to vector // form. if (NamedDecl *OldD = getAsDecl()) { - DeclsTy *VT = new DeclsTy(); - VT->push_back(OldD); + DeclsTy *VT = new DeclsTy(OldD); Data = DeclsAndHasExternalTy(VT, false); } DeclsTy &Vec = *getAsVector(); - - // Using directives end up in a special entry which contains only - // other using directives, so all this logic is wasted for them. - // But avoiding the logic wastes time in the far-more-common case - // that we're *not* adding a new using directive. - - // Tag declarations always go at the end of the list so that an - // iterator which points at the first tag will start a span of - // decls that only contains tags. - if (D->hasTagIdentifierNamespace()) - Vec.push_back(D); - - // Resolved using declarations go at the front of the list so that - // they won't show up in other lookup results. Unresolved using - // declarations (which are always in IDNS_Using | IDNS_Ordinary) - // follow that so that the using declarations will be contiguous. - else if (D->getIdentifierNamespace() & Decl::IDNS_Using) { - DeclsTy::iterator I = Vec.begin(); - if (D->getIdentifierNamespace() != Decl::IDNS_Using) { - while (I != Vec.end() && - (*I)->getIdentifierNamespace() == Decl::IDNS_Using) - ++I; - } - Vec.insert(I, D); - - // All other declarations go at the end of the list, but before any - // tag declarations. But we can be clever about tag declarations - // because there can only ever be one in a scope. - } else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()) { - NamedDecl *TagD = Vec.back(); - Vec.back() = D; - Vec.push_back(TagD); - } else - Vec.push_back(D); + Vec.push_back(D); } }; class StoredDeclsMap : public llvm::SmallDenseMap { -public: - static void DestroyAll(StoredDeclsMap *Map, bool Dependent); - -private: friend class ASTContext; // walks the chain deleting these friend class DeclContext; llvm::PointerIntPair Previous; +public: + static void DestroyAll(StoredDeclsMap *Map, bool Dependent); }; class DependentStoredDeclsMap : public StoredDeclsMap { -public: - DependentStoredDeclsMap() = default; - -private: friend class DeclContext; // iterates over diagnostics friend class DependentDiagnostic; DependentDiagnostic *FirstDiagnostic = nullptr; +public: + DependentStoredDeclsMap() = default; }; } // namespace clang Index: clang/lib/ARCMigrate/ObjCMT.cpp =================================================================== --- clang/lib/ARCMigrate/ObjCMT.cpp +++ clang/lib/ARCMigrate/ObjCMT.cpp @@ -613,7 +613,7 @@ continue; HasAtleastOneRequiredProperty = true; DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName()); - if (R.size() == 0) { + if (R.empty()) { // Relax the rule and look into class's implementation for a synthesize // or dynamic declaration. Class is implementing a property coming from // another protocol. This still makes the target protocol as conforming. @@ -622,7 +622,7 @@ Property->getQueryKind())) return false; } - else if (ObjCPropertyDecl *ClassProperty = dyn_cast(R[0])) { + else if (auto *ClassProperty = dyn_cast(R.front())) { if ((ClassProperty->getPropertyAttributes() != Property->getPropertyAttributes()) || !Ctx.hasSameType(ClassProperty->getType(), Property->getType())) @@ -645,12 +645,12 @@ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) continue; DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName()); - if (R.size() == 0) + if (R.empty()) return false; bool match = false; HasAtleastOneRequiredMethod = true; - for (unsigned I = 0, N = R.size(); I != N; ++I) - if (ObjCMethodDecl *ImpMD = dyn_cast(R[0])) + for (auto I = R.begin(), E = R.end(); I != E; ++I) + if (ObjCMethodDecl *ImpMD = dyn_cast(*I)) if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { match = true; break; Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1609,8 +1609,7 @@ // Suppress inline namespace if it doesn't make the result ambiguous. if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope && - Ctx->lookup(NameInScope).size() == - Ctx->getParent()->lookup(NameInScope).size()) + Ctx->lookup(NameInScope).equals(Ctx->getParent()->lookup(NameInScope))) continue; // Skip non-named contexts such as linkage specifications and ExportDecls. Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -37,6 +37,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -1545,7 +1546,8 @@ assert(Pos != Map->end() && "no lookup entry for decl"); // Remove the decl only if it is contained. StoredDeclsList::DeclsTy *Vec = Pos->second.getAsVector(); - if ((Vec && is_contained(*Vec, ND)) || Pos->second.getAsDecl() == ND) + if ((Vec && llvm::is_contained(*Vec, ND)) || + Pos->second.getAsDecl() == ND) Pos->second.remove(ND); } } while (DC->isTransparentContext() && (DC = DC->getParent())); @@ -1663,8 +1665,6 @@ } } -NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr; - DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) const { assert(getDeclKind() != Decl::LinkageSpec && @@ -1940,7 +1940,10 @@ // In this case, we never try to replace an existing declaration; we'll // handle that when we finalize the list of declarations for this name. DeclNameEntries.setHasExternalDecls(); - DeclNameEntries.AddSubsequentDecl(D); + if (DeclNameEntries.isNull()) + DeclNameEntries.setOnlyValue(D); + else + DeclNameEntries.AddSubsequentDecl(D); return; } Index: clang/lib/AST/ExternalASTMerger.cpp =================================================================== --- clang/lib/AST/ExternalASTMerger.cpp +++ clang/lib/AST/ExternalASTMerger.cpp @@ -64,9 +64,14 @@ Source SourceName = *SourceNameOrErr; DeclContext::lookup_result SearchResult = SourceParentDC.get()->lookup(SourceName.get()); - size_t SearchResultSize = SearchResult.size(); - if (SearchResultSize == 0 || SearchResultSize > 1) { - // There are two cases here. First, we might not find the name. + if (SearchResult.isSingleResult()) { + NamedDecl *SearchResultDecl = SearchResult.front(); + if (isa(SearchResultDecl) && + SearchResultDecl->getKind() == DC->getDeclKind()) + return cast(SearchResultDecl)->getPrimaryContext(); + return nullptr; // This type of lookup is unsupported + } else { + // There are two cases here. First, we might not find the name. // We might also find multiple copies, in which case we have no // guarantee that the one we wanted is the one we pick. (E.g., // if we have two specializations of the same template it is @@ -76,12 +81,6 @@ // explicitly recorded, so we trigger that recording by returning // nothing (rather than a possibly-inaccurate guess) here. return nullptr; - } else { - NamedDecl *SearchResultDecl = SearchResult[0]; - if (isa(SearchResultDecl) && - SearchResultDecl->getKind() == DC->getDeclKind()) - return cast(SearchResultDecl)->getPrimaryContext(); - return nullptr; // This type of lookup is unsupported } } Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -1229,8 +1229,7 @@ // Only suppress an inline namespace if the name has the same lookup // results in the enclosing namespace. if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope && - DC->getParent()->lookup(NameInScope).size() == - DC->lookup(NameInScope).size()) + DC->getParent()->lookup(NameInScope).equals(DC->lookup(NameInScope))) return AppendScope(DC->getParent(), OS, NameInScope); AppendScope(DC->getParent(), OS, NS->getDeclName()); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -4107,13 +4107,9 @@ IdentifierInfo *MemberOrBase) { if (SS.getScopeRep() || TemplateTypeTy) return nullptr; - DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (Result.empty()) - return nullptr; - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front()))) - return Member; + for (auto *D : ClassDecl->lookup(MemberOrBase)) + if (isa(D) || isa(D)) + return cast(D); return nullptr; } Index: clang/lib/Sema/SemaObjCProperty.cpp =================================================================== --- clang/lib/Sema/SemaObjCProperty.cpp +++ clang/lib/Sema/SemaObjCProperty.cpp @@ -112,9 +112,8 @@ return; // Look for a property with the same name. - DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName()); - for (unsigned I = 0, N = R.size(); I != N; ++I) { - if (ObjCPropertyDecl *ProtoProp = dyn_cast(R[I])) { + for (auto *R : Proto->lookup(Prop->getDeclName())) { + if (ObjCPropertyDecl *ProtoProp = dyn_cast(R)) { S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true); return; } @@ -233,9 +232,8 @@ bool FoundInSuper = false; ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { - DeclContext::lookup_result R = Super->lookup(Res->getDeclName()); - for (unsigned I = 0, N = R.size(); I != N; ++I) { - if (ObjCPropertyDecl *SuperProp = dyn_cast(R[I])) { + for (auto *R : Super->lookup(Res->getDeclName())) { + if (ObjCPropertyDecl *SuperProp = dyn_cast(R)) { DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); FoundInSuper = true; break; @@ -1150,7 +1148,7 @@ for (auto *Ext : IDecl->known_extensions()) { DeclContext::lookup_result R = Ext->lookup(property->getDeclName()); if (!R.empty()) - if (ObjCPropertyDecl *ExtProp = dyn_cast(R[0])) { + if (auto *ExtProp = dyn_cast(R.front())) { PIkind = ExtProp->getPropertyAttributesAsWritten(); if (PIkind & ObjCPropertyAttribute::kind_readwrite) { ReadWriteProperty = true; Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3414,7 +3414,13 @@ Instantiation->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - FieldDecl *Pattern = cast(Lookup.front()); + FieldDecl *Pattern = nullptr; + for (auto *R : Lookup) + if (isa(R)) { + Pattern = cast(R); + break; + } + assert(Pattern); InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern, TemplateArgs); } Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -837,7 +837,7 @@ llvm::Optional operator()(StringRef Name) { IdentifierInfo &II = ACtx.Idents.get(Name); auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); - if (LookupRes.size() == 0) + if (LookupRes.empty()) return None; // Prioritze typedef declarations. @@ -989,7 +989,7 @@ return false; IdentifierInfo &II = ACtx.Idents.get(Name); auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); - if (LookupRes.size() == 0) + if (LookupRes.empty()) return false; for (Decl *D : LookupRes) { if (auto *FD = dyn_cast(D)) { Index: clang/tools/libclang/CXType.cpp =================================================================== --- clang/tools/libclang/CXType.cpp +++ clang/tools/libclang/CXType.cpp @@ -1030,7 +1030,7 @@ // and we would return InvalidFieldName instead of Incomplete. // But this erroneous results does protects again a hidden assertion failure // in the RecordLayoutBuilder - if (Res.size() != 1) + if (!Res.isSingleResult()) return CXTypeLayoutError_InvalidFieldName; if (const FieldDecl *FD = dyn_cast(Res.front())) return Ctx.getFieldOffset(FD); Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -2491,9 +2491,9 @@ auto FromName = FromD->getDeclName(); auto *Class = FirstDeclMatcher().match(FromTU, ClassPattern); auto LookupRes = Class->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 0u); + ASSERT_TRUE(LookupRes.empty()); LookupRes = FromTU->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 1u); + ASSERT_TRUE(LookupRes.isSingleResult()); } auto *ToD = cast(Import(FromD, Lang_CXX03)); @@ -2502,9 +2502,9 @@ TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); auto *Class = FirstDeclMatcher().match(ToTU, ClassPattern); auto LookupRes = Class->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 0u); + EXPECT_TRUE(LookupRes.empty()); LookupRes = ToTU->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 1u); + EXPECT_TRUE(LookupRes.isSingleResult()); EXPECT_EQ(DeclCounter().match(ToTU, FunctionPattern), 1u); auto *To0 = FirstDeclMatcher().match(ToTU, FunctionPattern); @@ -2538,9 +2538,9 @@ auto *FromClass = FirstDeclMatcher().match(FromTU, ClassPattern); auto LookupRes = FromClass->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 0u); + ASSERT_TRUE(LookupRes.empty()); LookupRes = FromTU->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 1u); + ASSERT_TRUE(LookupRes.isSingleResult()); auto *ToFriend = cast(Import(FromFriend, Lang_CXX03)); auto ToName = ToFriend->getDeclName(); @@ -2548,10 +2548,10 @@ TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); auto *ToClass = FirstDeclMatcher().match(ToTU, ClassPattern); LookupRes = ToClass->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 0u); + EXPECT_TRUE(LookupRes.empty()); LookupRes = ToTU->noload_lookup(ToName); // Test is disabled because this result is 2. - EXPECT_EQ(LookupRes.size(), 1u); + EXPECT_TRUE(LookupRes.isSingleResult()); ASSERT_EQ(DeclCounter().match(ToTU, FunctionPattern), 2u); ToFriend = FirstDeclMatcher().match(ToTU, FunctionPattern); @@ -2582,9 +2582,9 @@ auto *FromClass = FirstDeclMatcher().match(FromTU, ClassPattern); auto LookupRes = FromClass->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 0u); + ASSERT_TRUE(LookupRes.empty()); LookupRes = FromTU->noload_lookup(FromName); - ASSERT_EQ(LookupRes.size(), 1u); + ASSERT_TRUE(LookupRes.isSingleResult()); auto *ToNormal = cast(Import(FromNormal, Lang_CXX03)); auto ToName = ToNormal->getDeclName(); @@ -2592,9 +2592,9 @@ auto *ToClass = FirstDeclMatcher().match(ToTU, ClassPattern); LookupRes = ToClass->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 0u); + EXPECT_TRUE(LookupRes.empty()); LookupRes = ToTU->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 1u); + EXPECT_TRUE(LookupRes.isSingleResult()); EXPECT_EQ(DeclCounter().match(ToTU, FunctionPattern), 2u); ToNormal = FirstDeclMatcher().match(ToTU, FunctionPattern); @@ -2624,9 +2624,9 @@ ASSERT_FALSE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); ASSERT_TRUE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); auto LookupRes = FromNormalTU->noload_lookup(FromNormalName); - ASSERT_EQ(LookupRes.size(), 1u); + ASSERT_TRUE(LookupRes.isSingleResult()); LookupRes = FromFriendTU->noload_lookup(FromFriendName); - ASSERT_EQ(LookupRes.size(), 1u); + ASSERT_TRUE(LookupRes.isSingleResult()); auto *ToNormalF = cast(Import(FromNormalF, Lang_CXX03)); TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); @@ -2634,12 +2634,12 @@ EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); EXPECT_FALSE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); LookupRes = ToTU->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 1u); + EXPECT_TRUE(LookupRes.isSingleResult()); EXPECT_EQ(DeclCounter().match(ToTU, Pattern), 1u); auto *ToFriendF = cast(Import(FromFriendF, Lang_CXX03)); LookupRes = ToTU->noload_lookup(ToName); - EXPECT_EQ(LookupRes.size(), 1u); + EXPECT_TRUE(LookupRes.isSingleResult()); EXPECT_EQ(DeclCounter().match(ToTU, Pattern), 2u); EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); @@ -3965,7 +3965,8 @@ // one we are going to delete from the DC later. L.setHasExternalDecls(); ASSERT_TRUE(L.getAsVector()); - ASSERT_EQ(1u, L.getAsVector()->size()); + auto Results = L.getAsVector(); + ASSERT_EQ(1u, std::distance(Results->begin(), Results->end())); // This asserts in the old implementation. DC->removeDecl(A0);