From: Douglas Gregor Date: Tue, 3 Aug 2010 19:06:41 +0000 (+0000) Subject: When using a precompiled preamble, keep track of the top-level X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb8837b88c18631c69ac75f64ab1853762063180;p=clang When using a precompiled preamble, keep track of the top-level declarations that we saw when creating the precompiled preamble, and provide those declarations in addition to the declarations parsed in the main source file when traversing top-level declarations. This makes the use of precompiled preambles a pure optimization, rather than changing the semantics of the parsed translation unit. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110131 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index ad622c55e6..58f2b38707 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -14,12 +14,13 @@ #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H #define LLVM_CLANG_FRONTEND_ASTUNIT_H +#include "clang/Index/ASTLocation.h" +#include "clang/Frontend/PCHBitCodes.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" -#include "clang/Basic/FileManager.h" -#include "clang/Index/ASTLocation.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/System/Path.h" @@ -168,7 +169,11 @@ private: /// \brief The group of timers associated with this translation unit. llvm::OwningPtr TimerGroup; - + + /// \brief A list of the PCH ID numbers for each of the top-level + /// declarations parsed within the precompiled preamble. + std::vector TopLevelDeclsInPreamble; + /// \brief The timers we've created from the various parses, reparses, etc. /// involved in this translation unit. std::vector Timers; @@ -185,7 +190,8 @@ private: ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer); llvm::MemoryBuffer *BuildPrecompiledPreamble(); - + void RealizeTopLevelDeclsFromPreamble(); + public: class ConcurrencyCheck { volatile ASTUnit &Self; @@ -236,16 +242,48 @@ public: bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + /// \brief Retrieve the maximum PCH level of declarations that a + /// traversal of the translation unit should consider. + unsigned getMaxPCHLevel() const; + void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } ASTLocation getLastASTLocation() const { return LastLoc; } - std::vector &getTopLevelDecls() { + typedef std::vector::iterator top_level_iterator; + + top_level_iterator top_level_begin() { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); - return TopLevelDecls; + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.begin(); } - const std::vector &getTopLevelDecls() const { + + top_level_iterator top_level_end() { assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); - return TopLevelDecls; + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.end(); + } + + std::size_t top_level_size() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.size() + TopLevelDecls.size(); + } + + bool top_level_empty() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty(); + } + + /// \brief Add a new top-level declaration. + void addTopLevelDecl(Decl *D) { + TopLevelDecls.push_back(D); + } + + /// \brief Add a new top-level declaration, identified by its ID in + /// the precompiled preamble. + void addTopLevelDeclFromPreamble(pch::DeclID D) { + TopLevelDeclsInPreamble.push_back(D); } /// \brief Retrieve the mapping from File IDs to the preprocessed entities diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 3403c6e2d1..3ba5691ebc 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -448,6 +448,10 @@ class PCHGenerator : public SemaConsumer { llvm::BitstreamWriter Stream; PCHWriter Writer; +protected: + PCHWriter &getWriter() { return Writer; } + const PCHWriter &getWriter() const { return Writer; } + public: PCHGenerator(const Preprocessor &PP, bool Chaining, const char *isysroot, llvm::raw_ostream *Out); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index bd60296ca8..c37610afc3 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -309,7 +309,7 @@ public: // fundamental problem in the parser right now. if (isa(D)) continue; - Unit.getTopLevelDecls().push_back(D); + Unit.addTopLevelDecl(D); } } }; @@ -331,6 +331,7 @@ public: class PrecompilePreambleConsumer : public PCHGenerator { ASTUnit &Unit; + std::vector TopLevelDecls; public: PrecompilePreambleConsumer(ASTUnit &Unit, @@ -338,7 +339,7 @@ public: const char *isysroot, llvm::raw_ostream *Out) : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { } - void HandleTopLevelDecl(DeclGroupRef D) { + virtual void HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { Decl *D = *it; // FIXME: Currently ObjC method declarations are incorrectly being @@ -347,7 +348,20 @@ public: // fundamental problem in the parser right now. if (isa(D)) continue; - Unit.getTopLevelDecls().push_back(D); + TopLevelDecls.push_back(D); + } + } + + virtual void HandleTranslationUnit(ASTContext &Ctx) { + PCHGenerator::HandleTranslationUnit(Ctx); + if (!Unit.getDiagnostics().hasErrorOccurred()) { + // Translate the top-level declarations we captured during + // parsing into declaration IDs in the precompiled + // preamble. This will allow us to deserialize those top-level + // declarations when requested. + for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I) + Unit.addTopLevelDeclFromPreamble( + getWriter().getDeclID(TopLevelDecls[I])); } } }; @@ -855,7 +869,9 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { // Clear out old caches and data. StoredDiagnostics.clear(); - + TopLevelDecls.clear(); + TopLevelDeclsInPreamble.clear(); + // Capture any diagnostics that would otherwise be dropped. CaptureDroppedDiagnostics Capture(CaptureDiagnostics, getDiagnostics(), @@ -867,7 +883,6 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { // Create the source manager. Clang.setSourceManager(new SourceManager(getDiagnostics())); - // FIXME: Eventually, we'll have to track top-level declarations here, too. llvm::OwningPtr Act; Act.reset(new PrecompilePreambleAction(*this)); if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, @@ -889,7 +904,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { Clang.takeDiagnosticClient(); Clang.takeInvocation(); - if (Diagnostics->getNumErrors() > 0) { + if (Diagnostics->hasErrorOccurred()) { // There were errors parsing the preamble, so no precompiled header was // generated. Forget that we even tried. // FIXME: Should we leave a note for ourselves to try again? @@ -899,7 +914,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { delete NewPreamble.first; if (PreambleTimer) PreambleTimer->stopTimer(); - + TopLevelDeclsInPreamble.clear(); return 0; } @@ -935,6 +950,31 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { FrontendOpts.Inputs[0].second); } +void ASTUnit::RealizeTopLevelDeclsFromPreamble() { + std::vector Resolved; + Resolved.reserve(TopLevelDeclsInPreamble.size()); + ExternalASTSource &Source = *getASTContext().getExternalSource(); + for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) { + // Resolve the declaration ID to an actual declaration, possibly + // deserializing the declaration in the process. + Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]); + if (D) + Resolved.push_back(D); + } + TopLevelDeclsInPreamble.clear(); + TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); +} + +unsigned ASTUnit::getMaxPCHLevel() const { + if (!getOnlyLocalDecls()) + return Decl::MaxPCHLevel; + + unsigned Result = 0; + if (isMainFileAST() || SavedMainFileBuffer) + ++Result; + return Result; +} + ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, llvm::IntrusiveRefCntPtr Diags, bool OnlyLocalDecls, diff --git a/test/Index/preamble.c b/test/Index/preamble.c index e1a64c2fbe..7e75bf9b89 100644 --- a/test/Index/preamble.c +++ b/test/Index/preamble.c @@ -5,6 +5,16 @@ int wibble(int); // RUN: %clang -x c-header -o %t.pch %S/Inputs/prefix.h // RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s // RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt +// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:12 - 6:2] +// CHECK: :0:0: UnexposedStmt= Extent=[1:23 - 6:2] +// CHECK: :0:0: UnexposedStmt= Extent=[2:3 - 2:16] +// CHECK: :0:0: UnexposedStmt= Extent=[3:3 - 3:15] +// CHECK: preamble.h:4:3: UnexposedExpr= Extent=[4:3 - 4:13] +// CHECK: preamble.h:4:3: DeclRefExpr=ptr:2:8 Extent=[4:3 - 4:6] +// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13] +// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13] +// CHECK: :0:0: UnexposedStmt= Extent=[5:3 - 5:11] +// CHECK: preamble.h:5:10: UnexposedExpr= Extent=[5:10 - 5:11] // CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16] // CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16] // CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *' diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 1b3c6a2c73..b90740f8b0 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -478,10 +478,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { ASTUnit *CXXUnit = getCursorASTUnit(Cursor); if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && RegionOfInterest.isInvalid()) { - const std::vector &TLDs = CXXUnit->getTopLevelDecls(); - for (std::vector::const_iterator it = TLDs.begin(), - ie = TLDs.end(); it != ie; ++it) { - if (Visit(MakeCXCursor(*it, CXXUnit), true)) + for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), + TLEnd = CXXUnit->top_level_end(); + TL != TLEnd; ++TL) { + if (Visit(MakeCXCursor(*TL, CXXUnit), true)) return true; } } else if (VisitDeclContext( @@ -1636,18 +1636,8 @@ unsigned clang_visitChildren(CXCursor parent, CXClientData client_data) { ASTUnit *CXXUnit = getCursorASTUnit(parent); - unsigned PCHLevel = Decl::MaxPCHLevel; - - // Set the PCHLevel to filter out unwanted decls if requested. - if (CXXUnit->getOnlyLocalDecls()) { - PCHLevel = 0; - - // If the main input was an AST, bump the level. - if (CXXUnit->isMainFileAST()) - ++PCHLevel; - } - - CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel); + CursorVisitor CursorVis(CXXUnit, visitor, client_data, + CXXUnit->getMaxPCHLevel()); return CursorVis.VisitChildren(parent); }