From: Douglas Gregor Date: Sat, 15 Oct 2011 00:10:27 +0000 (+0000) Subject: Teach the ASTImporter to perform DeclContext lookups in a way that X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b75a3451bcae1301875282e73a13934c90b6574c;p=clang Teach the ASTImporter to perform DeclContext lookups in a way that avoids loading data from an external source, since those lookups were causing some "interesting" recursion in LLDB. This code is not efficient. I plan to remedy this inefficiency in a follow-up commit. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142023 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 25a103a767..9f29411768 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1262,6 +1262,15 @@ public: lookup_result lookup(DeclarationName Name); lookup_const_result lookup(DeclarationName Name) const; + /// \brief A simplistic name lookup mechanism that performs name lookup + /// into this declaration context without consulting the external source. + /// + /// This function should almost never be used, because it subverts the + /// usual relationship between a DeclContext and the external source. + /// See the ASTImporter for the (few, but important) use cases. + void localUncachedLookup(DeclarationName Name, + llvm::SmallVectorImpl &Results); + /// @brief Makes a declaration visible within this context. /// /// This routine makes the declaration D visible to name lookup diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 3db75bacbf..af66b04c3a 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2048,19 +2048,19 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { MergeWithNamespace = cast(DC)->getAnonymousNamespace(); } else { SmallVector ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; - if (NamespaceDecl *FoundNS = dyn_cast(*Lookup.first)) { + if (NamespaceDecl *FoundNS = dyn_cast(FoundDecls[I])) { MergeWithNamespace = FoundNS; ConflictingDecls.clear(); break; } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2109,19 +2109,19 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; if (TypedefNameDecl *FoundTypedef = - dyn_cast(*Lookup.first)) { + dyn_cast(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), FoundTypedef->getUnderlyingType())) return Importer.Imported(D, FoundTypedef); } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2189,13 +2189,13 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // We may already have an enum of the same name; try to find and match it. if (!DC->isFunctionOrMethod() && SearchName) { SmallVector ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(SearchName); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(SearchName, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (TypedefNameDecl *Typedef = dyn_cast(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs()) Found = Tag->getDecl(); @@ -2206,7 +2206,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { return Importer.Imported(D, FoundEnum); } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2275,13 +2275,13 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { RecordDecl *AdoptDecl = 0; if (!DC->isFunctionOrMethod() && SearchName) { SmallVector ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(SearchName); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(SearchName, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (TypedefNameDecl *Typedef = dyn_cast(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs()) Found = Tag->getDecl(); @@ -2304,7 +2304,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2360,13 +2360,13 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { if (!LexicalDC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2406,13 +2406,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (!LexicalDC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - if (FunctionDecl *FoundFunction = dyn_cast(*Lookup.first)) { + if (FunctionDecl *FoundFunction = dyn_cast(FoundDecls[I])) { if (isExternalLinkage(FoundFunction->getLinkage()) && isExternalLinkage(D->getLinkage())) { if (Importer.IsStructurallyEquivalent(D->getType(), @@ -2437,7 +2437,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2567,10 +2567,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { return 0; // Determine whether we've already imported this field. - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (FieldDecl *FoundField = dyn_cast(*Lookup.first)) { + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (FieldDecl *FoundField = dyn_cast(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); @@ -2618,11 +2618,11 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { return 0; // Determine whether we've already imported this field. - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField - = dyn_cast(*Lookup.first)) { + = dyn_cast(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); @@ -2674,10 +2674,10 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { return 0; // Determine whether we've already imported this ivar - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (ObjCIvarDecl *FoundIvar = dyn_cast(*Lookup.first)) { + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (ObjCIvarDecl *FoundIvar = dyn_cast(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { Importer.Imported(D, FoundIvar); @@ -2729,13 +2729,13 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { VarDecl *MergeWithVar = 0; SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - if (VarDecl *FoundVar = dyn_cast(*Lookup.first)) { + if (VarDecl *FoundVar = dyn_cast(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. if (isExternalLinkage(FoundVar->getLinkage()) && isExternalLinkage(D->getLinkage())) { @@ -2774,7 +2774,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (MergeWithVar) { @@ -2900,10 +2900,10 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (ObjCMethodDecl *FoundMethod = dyn_cast(*Lookup.first)) { + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (ObjCMethodDecl *FoundMethod = dyn_cast(FoundDecls[I])) { if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) continue; @@ -3093,13 +3093,13 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { return 0; ObjCProtocolDecl *MergeWithProtocol = 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) continue; - if ((MergeWithProtocol = dyn_cast(*Lookup.first))) + if ((MergeWithProtocol = dyn_cast(FoundDecls[I]))) break; } @@ -3154,13 +3154,13 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { return 0; ObjCInterfaceDecl *MergeWithIface = 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - if ((MergeWithIface = dyn_cast(*Lookup.first))) + if ((MergeWithIface = dyn_cast(FoundDecls[I]))) break; } @@ -3385,11 +3385,11 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return 0; // Check whether we have already imported this property. - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCPropertyDecl *FoundProp - = dyn_cast(*Lookup.first)) { + = dyn_cast(FoundDecls[I])) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { @@ -3690,13 +3690,13 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // We may already have a template of the same name; try to find and match it. if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + llvm::SmallVector FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (ClassTemplateDecl *FoundTemplate = dyn_cast(Found)) { if (IsStructuralMatch(D, FoundTemplate)) { @@ -3709,7 +3709,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 844a39361b..321e40b438 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -1081,6 +1081,38 @@ DeclContext::lookup(DeclarationName Name) const { return const_cast(this)->lookup(Name); } +void DeclContext::localUncachedLookup(DeclarationName Name, + llvm::SmallVectorImpl &Results) { + Results.clear(); + + // If there's no external storage, just perform a normal lookup and copy + // the results. + if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage()) { + lookup_result LookupResults = lookup(Name); + Results.insert(Results.end(), LookupResults.first, LookupResults.second); + return; + } + + // If we have a lookup table, check there first. Maybe we'll get lucky. + if (LookupPtr) { + StoredDeclsMap::iterator Pos = LookupPtr->find(Name); + if (Pos != LookupPtr->end()) { + Results.insert(Results.end(), + Pos->second.getLookupResult().first, + Pos->second.getLookupResult().second); + return; + } + } + + // Slow case: grovel through the declarations in our chain looking for + // matches. + for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { + if (NamedDecl *ND = dyn_cast(D)) + if (ND->getDeclName() == Name) + Results.push_back(ND); + } +} + DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; // Skip through transparent contexts.