Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -592,6 +592,9 @@ std::unique_ptr InterpContext; std::unique_ptr ParentMapCtx; + /// Keeps track of the deallocated DeclListNodes for future reuse. + DeclListNode *ListNodeFreeList = nullptr; + public: IdentifierTable &Idents; SelectorTable &Selectors; @@ -643,6 +646,22 @@ } void Deallocate(void *Ptr) const {} + /// Allocates a \c DeclListNode or returns one from the \c ListNodeFreeList + /// pool. + DeclListNode *AllocateDecListNode(clang::NamedDecl *ND) { + if (DeclListNode *Alloc = ListNodeFreeList) { + ListNodeFreeList = Alloc->Rest.dyn_cast(); + return Alloc; + } + return new (*this) DeclListNode(ND); + } + /// Deallcates a \c DeclListNode by returning it to the \c ListNodeFreeList + /// pool. + void DeallocateDecListNode(DeclListNode *N) { + N->Rest = ListNodeFreeList; + ListNodeFreeList = N; + } + /// Return the total amount of physical memory allocated for representing /// AST nodes and type information. size_t getASTAllocatedMemory() const { Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -579,6 +579,16 @@ AnonOrFirstNamespaceAndInline.setInt(Inline); } + /// Returns true if the inline qualifier for \c Name is redundant. + bool isRedundantInlineQualifierFor(DeclarationName Name) const { + if (!isInline()) + return false; + auto X = lookup(Name); + auto Y = getParent()->lookup(Name); + return std::distance(X.begin(), X.end()) == + std::distance(Y.begin(), Y.end()); + } + /// Get the original (first) namespace declaration. NamespaceDecl *getOriginalNamespace(); Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -1221,65 +1221,126 @@ void print(raw_ostream &OS) const override; }; -/// The results of name lookup within a DeclContext. This is either a -/// single result (with no stable storage) or a collection of results (with -/// stable storage provided by the lookup table). -class DeclContextLookupResult { - using ResultTy = ArrayRef; - - ResultTy Result; +/// A list storing NamedDecls in the lookup tables. +class DeclListNode { + friend class ASTContext; // allocate, decallocate nodes. + friend class StoredDeclsList; +public: + using Decls = llvm::PointerUnion; +private: + NamedDecl *D = nullptr; + Decls Rest = nullptr; + DeclListNode(NamedDecl *ND) : D(ND) {} + class DeclListIterator { + friend class DeclContextLookupResult; + + Decls Ptr; + DeclListIterator(Decls Node) : Ptr(Node) { } + public: + using difference_type = ptrdiff_t; + using value_type = NamedDecl*; + using pointer = value_type; + using reference = value_type; + using iterator_category = std::forward_iterator_tag; - // If there is only one lookup result, it would be invalidated by - // reallocations of the name table, so store it separately. - NamedDecl *Single = nullptr; + DeclListIterator() = default; - static NamedDecl *const SingleElementDummyList; + reference operator*() const { + assert(Ptr && "dereferencing end() iterator"); + if (DeclListNode *CurNode = Ptr.dyn_cast()) { + if (NamedDecl *ND = CurNode->Rest.dyn_cast()) + return ND; + else + return CurNode->D; + } + return Ptr.get(); + } + pointer operator->() const { return operator*(); } + bool operator==(const DeclListIterator &X) const { return Ptr == X.Ptr; } + bool operator!=(const DeclListIterator &X) const { return Ptr != X.Ptr; } + inline DeclListIterator& operator++() { // ++It + assert(!Ptr.isNull() && "Advancing empty iterator"); + assert((Ptr.dyn_cast() || Ptr.dyn_cast()) && + "Advancing empty iterator"); + + if (DeclListNode *CurNode = Ptr.dyn_cast()) { + if (CurNode->Rest.is()) + Ptr = CurNode->D; + else + Ptr = CurNode->Rest; + } else { + Ptr = nullptr; + } + return *this; + } + DeclListIterator operator++(int) { // It++ + DeclListIterator temp = *this; + ++(*this); + return temp; + } + }; public: - DeclContextLookupResult() = default; - DeclContextLookupResult(ArrayRef Result) - : Result(Result) {} - DeclContextLookupResult(NamedDecl *Single) - : Result(SingleElementDummyList), Single(Single) {} + using iterator = DeclListIterator; - class iterator; + // iterator begin() { return iterator(this); } + // iterator end() { return iterator(); } +}; - using IteratorBase = - llvm::iterator_adaptor_base; +/// The results of name lookup within a DeclContext. This is either a +/// single result (with no stable storage) or a collection of results (with +/// stable storage provided by the lookup table). +class DeclContextLookupResult { + friend class StoredDeclsList; - class iterator : public IteratorBase { - value_type SingleElement; + using Decls = DeclListNode::Decls; - public: - explicit iterator(pointer Pos, value_type Single = nullptr) - : IteratorBase(Pos), SingleElement(Single) {} + /// When in collection form, this is what the Data pointer points to. + DeclListNode::Decls Result = nullptr; - reference operator*() const { - return SingleElement ? SingleElement : IteratorBase::operator*(); - } - }; +public: + DeclContextLookupResult() = default; + DeclContextLookupResult(Decls Result) : Result(Result) {} + using iterator = DeclListNode::iterator; 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 { 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]; } + bool empty() const { return Result.isNull(); } + bool isSingleResult() const { + return !empty() && Result.dyn_cast(); + } + 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; } + + template T *find_first() const { + for (auto *D : *this) + if (T* Decl = dyn_cast(D)) + return Decl; + + return nullptr; + } }; /// DeclContext - This is used only as base class of specific decl types that Index: clang/include/clang/AST/DeclContextInternals.h =================================================================== --- clang/include/clang/AST/DeclContextInternals.h +++ clang/include/clang/AST/DeclContextInternals.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H #define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -21,7 +22,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/SmallVector.h" #include #include @@ -31,93 +31,162 @@ /// 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; +class StoredDeclsList { + using DeclsTy = DeclListNode; + using Decls = DeclListNode::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; + + void setOnlyValue(NamedDecl *ND) { + assert(!getAsVector() && "Not inline"); + Data.setPointer(ND); + Data.setInt(0); + // Make sure that Data is a plain NamedDecl* so we can use its address + // at getLookupResult. + assert(*(NamedDecl **)Data.getPointer().getAddrOfPtr1() == ND && + "PointerUnion mangles the NamedDecl pointer!"); + } + + void push_front(NamedDecl *ND) { + assert(!isNull() && "No need to call push_front"); + + ASTContext &C = getASTContext(); + DeclsTy *Node = C.AllocateDecListNode(ND); + + // If this is the second decl added optimize the use by setting the + // pointer to the next to point to OldD. This way we save an extra + // allocation. + if (NamedDecl *OldD = getAsDecl()) { + // FIXME: Enable both asserts... + //assert(OldD != ND && "list already contains decl"); + Node->Rest = OldD; + Data.setPointer(Node); + return; + } + + // assert(llvm::find(*getAsVector(), ND) == std::end(*getAsVector()) && + // "list still contains decl"); + Node->Rest = Data.getPointer(); + Data.setPointer(Node); + } + + template + void erase_if(Pred pred) { + DeclsTy *Prev = getAsVector(); + assert(Prev && "Not in list mode!"); + + ASTContext &C = getASTContext(); + DeclsTy *Next = Prev; + while(Next->Rest.dyn_cast()) { + if (pred(Next->D)) { + Prev->Rest = Next->Rest; + // FIXME: Move after assigning from Next.Rest + //C.DeallocateDecListNode(Next); + } + + Next = Next->Rest.get(); + if (Next->Rest.dyn_cast()) + Prev = Next; + } + + // The last element's Rest points to a NamedDecl to save space. + NamedDecl *ND = Next->Rest.get(); + if (Prev == Next) { + if (pred(ND)) { + Data.setPointer(Next->D); + C.DeallocateDecListNode(Next); + } else if (pred(Next->D)) { + Data.setPointer(ND); + C.DeallocateDecListNode(Next); + } + } else { + if (pred(ND)) { + Prev->Rest = Next->D; + C.DeallocateDecListNode(Next); + } else if (pred(Next->D)) { + Prev->Rest = ND; + C.DeallocateDecListNode(Next); + } + } + } + + void erase(NamedDecl *ND) { + erase_if([ND](NamedDecl *D){ return D == ND; }); + } 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; + if (DeclsTy *Vector = getAsVector()) { + ASTContext &C = getASTContext(); + C.DeallocateDecListNode(Vector); + } } StoredDeclsList &operator=(StoredDeclsList &&RHS) { - if (DeclsTy *Vector = getAsVector()) - delete Vector; + if (DeclsTy *Vector = getAsVector()) { + ASTContext &C = getASTContext(); + C.DeallocateDecListNode(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(); + ASTContext &getASTContext() { + if (NamedDecl *ND = getAsDecl()) + return ND->getASTContext(); + auto &Vec = *getAsVector(); + return Vec.D->getASTContext(); } DeclsAndHasExternalTy getAsVectorAndHasExternal() const { - return Data.dyn_cast(); + return Data; + } + + NamedDecl *getAsDecl() const { + return getAsVectorAndHasExternal().getPointer().dyn_cast(); } DeclsTy *getAsVector() const { - return getAsVectorAndHasExternal().getPointer(); + return getAsVectorAndHasExternal().getPointer().dyn_cast(); } + bool hasExternalDecls() const { return getAsVectorAndHasExternal().getInt(); } void setHasExternalDecls() { - 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); - } - } - - void setOnlyValue(NamedDecl *ND) { - assert(!getAsVector() && "Not inline"); - Data = ND; - // Make sure that Data is a plain NamedDecl* so we can use its address - // at getLookupResult. - assert(*(NamedDecl **)&Data == ND && - "PointerUnion mangles the NamedDecl pointer!"); + Data.setInt(1); } void remove(NamedDecl *D) { assert(!isNull() && "removing from empty list"); if (NamedDecl *Singleton = getAsDecl()) { - assert(Singleton == D && "list is different singleton"); - (void)Singleton; - Data = (NamedDecl *)nullptr; + if (Singleton == D) + Data.setPointer(nullptr); return; } - DeclsTy &Vec = *getAsVector(); - DeclsTy::iterator I = llvm::find(Vec, D); - assert(I != Vec.end() && "list does not contain decl"); - Vec.erase(I); - - assert(llvm::find(Vec, D) == Vec.end() && "list still contains decl"); + erase(D); } /// Remove any declarations which were imported from an external @@ -129,34 +198,14 @@ if (Singleton->isFromASTFile()) *this = StoredDeclsList(); } else { - DeclsTy &Vec = *getAsVector(); - Vec.erase(std::remove_if(Vec.begin(), Vec.end(), - [](Decl *D) { return D->isFromASTFile(); }), - Vec.end()); - // Don't have any external decls any more. - Data = DeclsAndHasExternalTy(&Vec, false); + erase_if([](NamedDecl *ND){ return ND->isFromASTFile(); }); } } /// 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, @@ -172,90 +221,57 @@ // Determine if this declaration is actually a redeclaration. DeclsTy &Vec = *getAsVector(); - for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); - OD != ODEnd; ++OD) { - NamedDecl *OldD = *OD; - if (D->declarationReplaces(OldD, IsKnownNewer)) { - *OD = D; + while (DeclsTy *Next = Vec.Rest.dyn_cast()) { + if (D->declarationReplaces(Vec.D, IsKnownNewer)) { + Vec.D = D; return true; } + Vec = *Next; + } + + // Handle the two element case. + if (D->declarationReplaces(Vec.Rest.get(), IsKnownNewer)) { + Vec.Rest = D; + return true; + } + + if (D->declarationReplaces(Vec.D, IsKnownNewer)) { + Vec.D = D; + return true; } return false; } - /// AddSubsequentDecl - This is called on the second and later decl when it is - /// not a redeclaration to merge it into the appropriate place in our list. - void AddSubsequentDecl(NamedDecl *D) { - assert(!isNull() && "don't AddSubsequentDecl when we have no decls"); - - // 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); - Data = DeclsAndHasExternalTy(VT, false); + /// AddDecl - Called to add declarations when it is not a redeclaration to + /// merge it into the appropriate place in our list. + void AddDecl(NamedDecl *D) { + if (isNull()) { + setOnlyValue(D); + return; } - 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); + push_front(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()) + cast(Ctx)->isRedundantInlineQualifierFor(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 @@ -1420,15 +1420,12 @@ if (I == Skip[SkipPos]) ++SkipPos; else - List.AddSubsequentDecl(Decls[I]); + List.AddDecl(Decls[I]); } } else { // Convert the array to a StoredDeclsList. for (auto *D : Decls) { - if (List.isNull()) - List.setOnlyValue(D); - else - List.AddSubsequentDecl(D); + List.AddDecl(D); } } @@ -1543,10 +1540,7 @@ if (Map) { StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); 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) - Pos->second.remove(ND); + Pos->second.remove(ND); } } while (DC->isTransparentContext() && (DC = DC->getParent())); } @@ -1663,8 +1657,6 @@ } } -NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr; - DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) const { assert(getDeclKind() != Decl::LinkageSpec && @@ -1940,12 +1932,12 @@ // 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); + DeclNameEntries.AddDecl(D); return; } if (DeclNameEntries.isNull()) { - DeclNameEntries.setOnlyValue(D); + DeclNameEntries.AddDecl(D); return; } @@ -1956,7 +1948,7 @@ } // Put this declaration into the appropriate slot. - DeclNameEntries.AddSubsequentDecl(D); + DeclNameEntries.AddDecl(D); } UsingDirectiveDecl *DeclContext::udir_iterator::operator*() const { Index: clang/lib/AST/ExternalASTMerger.cpp =================================================================== --- clang/lib/AST/ExternalASTMerger.cpp +++ clang/lib/AST/ExternalASTMerger.cpp @@ -64,24 +64,24 @@ 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. - // 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 - // very hard to determine which is the one you want.) - // - // The Origins map fixes this problem by allowing the origin to be - // explicitly recorded, so we trigger that recording by returning - // nothing (rather than a possibly-inaccurate guess) here. - return nullptr; - } else { - NamedDecl *SearchResultDecl = SearchResult[0]; + + // 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 + // very hard to determine which is the one you want.) + // + // The Origins map fixes this problem by allowing the origin to be + // explicitly recorded, so we trigger that recording by returning + // nothing (rather than a possibly-inaccurate guess) here. + 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 { + return nullptr; } } 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()) + NS->isRedundantInlineQualifierFor(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; @@ -1149,14 +1147,13 @@ // redeclared 'readwrite', then no warning is to be issued. for (auto *Ext : IDecl->known_extensions()) { DeclContext::lookup_result R = Ext->lookup(property->getDeclName()); - if (!R.empty()) - if (ObjCPropertyDecl *ExtProp = dyn_cast(R[0])) { - PIkind = ExtProp->getPropertyAttributesAsWritten(); - if (PIkind & ObjCPropertyAttribute::kind_readwrite) { - ReadWriteProperty = true; - break; - } + if (auto *ExtProp = R.find_first()) { + PIkind = ExtProp->getPropertyAttributesAsWritten(); + if (PIkind & ObjCPropertyAttribute::kind_readwrite) { + ReadWriteProperty = true; + break; } + } } if (!ReadWriteProperty) { Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3414,7 +3414,8 @@ Instantiation->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - FieldDecl *Pattern = cast(Lookup.front()); + FieldDecl *Pattern = Lookup.find_first(); + 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);