From 1d715ac14bf440664fb0d1425ea882274f994f57 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 3 Aug 2010 08:14:03 +0000 Subject: [PATCH] Reshuffle the PCH generator action and consumer, so that we can re-use it while generating precompiled preambles. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110108 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/ASTConsumers.h | 8 ---- include/clang/Frontend/FrontendActions.h | 11 +++++ include/clang/Frontend/PCHWriter.h | 23 ++++++++++ lib/Frontend/ASTUnit.cpp | 55 ++++++++++++++++++++++-- lib/Frontend/FrontendActions.cpp | 36 +++++++++++----- lib/Frontend/GeneratePCH.cpp | 27 ------------ 6 files changed, 111 insertions(+), 49 deletions(-) diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 0747290358..cca243d6cd 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -57,14 +57,6 @@ ASTConsumer *CreateASTViewer(); // to stderr; this is intended for debugging. ASTConsumer *CreateDeclContextPrinter(); -// PCH generator: generates a precompiled header file; this file can be used -// later with the PCHReader (clang -cc1 option -include-pch) to speed up compile -// times. -ASTConsumer *CreatePCHGenerator(const Preprocessor &PP, - llvm::raw_ostream *OS, - bool Chaining, - const char *isysroot = 0); - // Inheritance viewer: for C++ code, creates a graph of the inheritance // tree for the given class and displays it with "dotty". ASTConsumer *CreateInheritanceViewer(const std::string& clsname); diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index efa8e91cab..7b8063ce54 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -74,6 +74,17 @@ protected: virtual bool usesCompleteTranslationUnit() { return false; } virtual bool hasASTFileSupport() const { return false; } + +public: + /// \brief Compute the AST consumer arguments that will be used to + /// create the PCHGenerator instance returned by CreateASTConsumer. + /// + /// \returns true if an error occurred, false otherwise. + static bool ComputeASTConsumerArguments(CompilerInstance &CI, + llvm::StringRef InFile, + std::string &Sysroot, + llvm::raw_ostream *&OS, + bool &Chaining); }; class InheritanceViewAction : public ASTFrontendAction { diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index c143cefccf..92c7085bc6 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -20,10 +20,13 @@ #include "clang/AST/TemplateBase.h" #include "clang/Frontend/PCHBitCodes.h" #include "clang/Frontend/PCHDeserializationListener.h" +#include "clang/Sema/SemaConsumer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Bitcode/BitstreamWriter.h" #include #include +#include namespace llvm { class APFloat; @@ -427,6 +430,26 @@ public: void DeclRead(pch::DeclID ID, const Decl *D); }; +/// \brief AST and semantic-analysis consumer that generates a +/// precompiled header from the parsed source code. +class PCHGenerator : public SemaConsumer { + const Preprocessor &PP; + const char *isysroot; + llvm::raw_ostream *Out; + Sema *SemaPtr; + MemorizeStatCalls *StatCalls; // owned by the FileManager + std::vector Buffer; + llvm::BitstreamWriter Stream; + PCHWriter Writer; + +public: + PCHGenerator(const Preprocessor &PP, bool Chaining, + const char *isysroot, llvm::raw_ostream *Out); + virtual void InitializeSema(Sema &S) { SemaPtr = &S; } + virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual PCHDeserializationListener *GetPCHDeserializationListener(); +}; + } // end namespace clang #endif diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index b36a338c19..bd60296ca8 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/PCHWriter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" @@ -25,6 +25,7 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/PCHReader.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetOptions.h" @@ -328,6 +329,54 @@ public: virtual bool hasCodeCompletionSupport() const { return false; } }; +class PrecompilePreambleConsumer : public PCHGenerator { + ASTUnit &Unit; + +public: + PrecompilePreambleConsumer(ASTUnit &Unit, + const Preprocessor &PP, bool Chaining, + const char *isysroot, llvm::raw_ostream *Out) + : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { } + + 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 + // reported as top-level declarations, even though their DeclContext + // is the containing ObjC @interface/@implementation. This is a + // fundamental problem in the parser right now. + if (isa(D)) + continue; + Unit.getTopLevelDecls().push_back(D); + } + } +}; + +class PrecompilePreambleAction : public ASTFrontendAction { + ASTUnit &Unit; + +public: + explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {} + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + std::string Sysroot; + llvm::raw_ostream *OS = 0; + bool Chaining; + if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + OS, Chaining)) + return 0; + + const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? + Sysroot.c_str() : 0; + return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining, + isysroot, OS); + } + + virtual bool hasCodeCompletionSupport() const { return false; } + virtual bool hasASTFileSupport() const { return false; } +}; + } /// Parse the source file into a translation unit using the given compiler @@ -819,8 +868,8 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() { Clang.setSourceManager(new SourceManager(getDiagnostics())); // FIXME: Eventually, we'll have to track top-level declarations here, too. - llvm::OwningPtr Act; - Act.reset(new GeneratePCHAction); + llvm::OwningPtr Act; + Act.reset(new PrecompilePreambleAction(*this)); if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, Clang.getFrontendOpts().Inputs[0].first)) { Clang.takeDiagnosticClient(); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index b0f85f1ad6..08639b6590 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -17,6 +17,7 @@ #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/PCHWriter.h" #include "clang/Frontend/Utils.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/MemoryBuffer.h" @@ -70,22 +71,35 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; - if (CI.getFrontendOpts().RelocatablePCH && - Sysroot.empty()) { - CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + std::string Sysroot; + llvm::raw_ostream *OS = 0; + bool Chaining; + if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining)) return 0; + + const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? + Sysroot.c_str() : 0; + return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS); +} + +bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, + llvm::StringRef InFile, + std::string &Sysroot, + llvm::raw_ostream *&OS, + bool &Chaining) { + Sysroot = CI.getHeaderSearchOpts().Sysroot; + if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { + CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + return true; } - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + OS = CI.createDefaultOutputFile(true, InFile); if (!OS) - return 0; + return true; - bool Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && - !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; - return CreatePCHGenerator(CI.getPreprocessor(), OS, Chaining, isysroot); + Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && + !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); + return false; } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index 561a68a6ef..33f5ef56ae 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -25,26 +25,6 @@ using namespace clang; -namespace { - class PCHGenerator : public SemaConsumer { - const Preprocessor &PP; - const char *isysroot; - llvm::raw_ostream *Out; - Sema *SemaPtr; - MemorizeStatCalls *StatCalls; // owned by the FileManager - std::vector Buffer; - llvm::BitstreamWriter Stream; - PCHWriter Writer; - - public: - PCHGenerator(const Preprocessor &PP, bool Chaining, - const char *isysroot, llvm::raw_ostream *Out); - virtual void InitializeSema(Sema &S) { SemaPtr = &S; } - virtual void HandleTranslationUnit(ASTContext &Ctx); - virtual PCHDeserializationListener *GetPCHDeserializationListener(); - }; -} - PCHGenerator::PCHGenerator(const Preprocessor &PP, bool Chaining, const char *isysroot, @@ -82,10 +62,3 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { PCHDeserializationListener *PCHGenerator::GetPCHDeserializationListener() { return &Writer; } - -ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP, - llvm::raw_ostream *OS, - bool Chaining, - const char *isysroot) { - return new PCHGenerator(PP, Chaining, isysroot, OS); -} -- 2.40.0