diff options
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 20 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 121 | ||||
-rw-r--r-- | test/Modules/lookup.cpp | 12 |
3 files changed, 126 insertions, 27 deletions
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 25f73c07e2..a3fe75205a 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -552,6 +552,26 @@ public: /// \param UserData User data associated with the visitor object, which /// will be passed along to the visitor. void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData); + + /// \brief Visit each of the modules with a depth-first traversal. + /// + /// This routine visits each of the modules known to the module + /// manager using a depth-first search, starting with the first + /// loaded module. The traversal invokes the callback both before + /// traversing the children (preorder traversal) and after + /// traversing the children (postorder traversal). + /// + /// \param Visitor A visitor function that will be invoked with each + /// module and given a \c Preorder flag that indicates whether we're + /// visiting the module before or after visiting its children. The + /// visitor may return true at any time to abort the depth-first + /// visitation. + /// + /// \param UserData User data ssociated with the visitor object, + /// which will be passed along to the user. + void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData); }; } // end namespace serialization diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 8264a7421c..0a2992baa5 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4264,34 +4264,69 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { return ReadStmtFromStream(*Loc.F); } +namespace { + class FindExternalLexicalDeclsVisitor { + ASTReader &Reader; + const DeclContext *DC; + bool (*isKindWeWant)(Decl::Kind); + SmallVectorImpl<Decl*> &Decls; + bool PredefsVisited[NUM_PREDEF_DECL_IDS]; + + public: + FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls) + : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) + { + for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) + PredefsVisited[I] = false; + } + + static bool visit(Module &M, bool Preorder, void *UserData) { + if (Preorder) + return false; + + FindExternalLexicalDeclsVisitor *This + = static_cast<FindExternalLexicalDeclsVisitor *>(UserData); + + Module::DeclContextInfosMap::iterator Info + = M.DeclContextInfos.find(This->DC); + if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) + return false; + + // Load all of the declaration IDs + for (const KindDeclIDPair *ID = Info->second.LexicalDecls, + *IDE = ID + Info->second.NumLexicalDecls; + ID != IDE; ++ID) { + if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) + continue; + + // Don't add predefined declarations to the lexical context more + // than once. + if (ID->second < NUM_PREDEF_DECL_IDS) { + if (This->PredefsVisited[ID->second]) + continue; + + This->PredefsVisited[ID->second] = true; + } + + Decl *D = This->Reader.GetLocalDecl(M, ID->second); + assert(D && "Null decl in lexical decls"); + This->Decls.push_back(D); + } + + return false; + } + }; +} + ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), SmallVectorImpl<Decl*> &Decls) { // There might be lexical decls in multiple modules, for the TU at - // least. - // FIXME: We might want a faster way to zero - // FIXME: Going backwards through the chain does the right thing for - // chained PCH; for modules, it isn't clear what the right thing is. - for (ModuleReverseIterator M = ModuleMgr.rbegin(), MEnd = ModuleMgr.rend(); - M != MEnd; ++M) { - Module::DeclContextInfosMap::iterator Info - = (*M)->DeclContextInfos.find(DC); - if (Info == (*M)->DeclContextInfos.end() || !Info->second.LexicalDecls) - continue; - - // Load all of the declaration IDs - for (const KindDeclIDPair *ID = Info->second.LexicalDecls, - *IDE = ID + Info->second.NumLexicalDecls; - ID != IDE; ++ID) { - if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first)) - continue; - - Decl *D = GetLocalDecl(**M, ID->second); - assert(D && "Null decl in lexical decls"); - Decls.push_back(D); - } - } - + // least. Walk all of the modules in the order they were loaded. + FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); + ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor); ++NumLexicalDeclContextsRead; return ELR_Success; } @@ -5888,3 +5923,41 @@ void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData), } } } + +/// \brief Perform a depth-first visit of the current module. +static bool visitDepthFirst(Module &M, + bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData, + llvm::SmallPtrSet<Module *, 4> &Visited) { + // Preorder visitation + if (Visitor(M, /*Preorder=*/true, UserData)) + return true; + + // Visit children + for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(), + IMEnd = M.Imports.end(); + IM != IMEnd; ++IM) { + if (!Visited.insert(*IM)) + continue; + + if (visitDepthFirst(**IM, Visitor, UserData, Visited)) + return true; + } + + // Postorder visitation + return Visitor(M, /*Preorder=*/false, UserData); +} + +void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData) { + llvm::SmallPtrSet<Module *, 4> Visited; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (!Visited.insert(Chain[I])) + continue; + + if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) + return; + } +} diff --git a/test/Modules/lookup.cpp b/test/Modules/lookup.cpp index 4d8184f6ce..ca12a281af 100644 --- a/test/Modules/lookup.cpp +++ b/test/Modules/lookup.cpp @@ -9,6 +9,12 @@ void test(int i, float f) { ::f0(&f); } -// RUN: %clang_cc1 -emit-pch -o %t_lookup_left.h.pch %S/Inputs/lookup_left.hpp -// RUN: %clang_cc1 -emit-pch -o %t_lookup_right.h.pch %S/Inputs/lookup_right.hpp -// RUN: %clang_cc1 -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s +// RUN: %clang_cc1 -emit-pch -x c++ -o %t_lookup_left.h.pch %S/Inputs/lookup_left.hpp +// RUN: %clang_cc1 -emit-pch -x c++ -o %t_lookup_right.h.pch %S/Inputs/lookup_right.hpp +// RUN: %clang_cc1 -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s +// RUN: %clang_cc1 -ast-print -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch %s | FileCheck -check-prefix=CHECK-PRINT %s + +// CHECK-PRINT: int *f0(int *); +// CHECK-PRINT: float *f0(float *); +// CHECK-PRINT: void test(int i, float f) + |