]> granicus.if.org Git - clang/commitdiff
Modules: Add LangOptions::CacheGeneratedPCH
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 12 Mar 2019 18:38:04 +0000 (18:38 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 12 Mar 2019 18:38:04 +0000 (18:38 +0000)
Add an option to cache the generated PCH in the ModuleCache when
emitting it.  This protects clients that build PCHs and read them in the
same process, allowing them to avoid race conditions between parallel
jobs the same way that Clang's implicit module build system does.

rdar://problem/48740787

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@355950 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/LangOptions.def
include/clang/Serialization/ASTWriter.h
lib/Frontend/FrontendActions.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/GeneratePCH.cpp
unittests/Frontend/FrontendActionTest.cpp

index 7b2ab7a66fa6dd5e1c04cef079b4f2b674eabe62..8a35f4ed21d3e7770605dbd5f94f529f82572ce4 100644 (file)
@@ -154,6 +154,7 @@ BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 2, CMK_None,
                     "compiling a module interface")
 BENIGN_LANGOPT(CompilingPCH, 1, 0, "building a pch")
 BENIGN_LANGOPT(BuildingPCHWithObjectFile, 1, 0, "building a pch which has a corresponding object file")
+BENIGN_LANGOPT(CacheGeneratedPCH, 1, 0, "cache generated PCH files in memory")
 COMPATIBLE_LANGOPT(ModulesDeclUse    , 1, 0, "require declaration of module uses")
 BENIGN_LANGOPT(ModulesSearchAll  , 1, 1, "searching even non-imported modules to find unresolved references")
 COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "requiring declaration of module uses and all headers to be in modules")
index b0f722247006724aac05be382ebd7294aca609c4..3e287d9657f1ce1a7a9fb756bc125d793b0c38f3 100644 (file)
@@ -570,7 +570,8 @@ public:
   /// the module but currently is merely a random 32-bit number.
   ASTFileSignature WriteAST(Sema &SemaRef, const std::string &OutputFile,
                             Module *WritingModule, StringRef isysroot,
-                            bool hasErrors = false);
+                            bool hasErrors = false,
+                            bool ShouldCacheASTInMemory = false);
 
   /// Emit a token.
   void AddToken(const Token &Tok, RecordDataImpl &Record);
@@ -974,6 +975,7 @@ class PCHGenerator : public SemaConsumer {
   llvm::BitstreamWriter Stream;
   ASTWriter Writer;
   bool AllowASTWithErrors;
+  bool ShouldCacheASTInMemory;
 
 protected:
   ASTWriter &getWriter() { return Writer; }
@@ -985,7 +987,8 @@ public:
                StringRef OutputFile, StringRef isysroot,
                std::shared_ptr<PCHBuffer> Buffer,
                ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
-               bool AllowASTWithErrors = false, bool IncludeTimestamps = true);
+               bool AllowASTWithErrors = false, bool IncludeTimestamps = true,
+               bool ShouldCacheASTInMemory = false);
   ~PCHGenerator() override;
 
   void InitializeSema(Sema &S) override { SemaPtr = &S; }
index 5ad9a1cc036b71a17dbb69862be14f31d4a8194c..9cb2ab2d5ee2e3bfea7d3a9c3cf43fb57deb3385 100644 (file)
@@ -112,7 +112,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
       CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
       FrontendOpts.ModuleFileExtensions,
       CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
-      FrontendOpts.IncludeTimestamps));
+      FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH));
   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
       CI, InFile, OutputFile, std::move(OS), Buffer));
 
@@ -176,6 +176,8 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
       CI.getFrontendOpts().ModuleFileExtensions,
       /*AllowASTWithErrors=*/false,
       /*IncludeTimestamps=*/
+      +CI.getFrontendOpts().BuildingImplicitModule,
+      /*ShouldCacheASTInMemory=*/
       +CI.getFrontendOpts().BuildingImplicitModule));
   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
       CI, InFile, OutputFile, std::move(OS), Buffer));
index 85bc2818395b65c73b859f04ec2e4edde71f2645..933cc6b12c68095846dd390fe6c6217e465d2266 100644 (file)
@@ -4596,7 +4596,8 @@ time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const {
 ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
                                      const std::string &OutputFile,
                                      Module *WritingModule, StringRef isysroot,
-                                     bool hasErrors) {
+                                     bool hasErrors,
+                                     bool ShouldCacheASTInMemory) {
   WritingAST = true;
 
   ASTHasCompilerErrors = hasErrors;
@@ -4620,7 +4621,7 @@ ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
   this->BaseDirectory.clear();
 
   WritingAST = false;
-  if (SemaRef.Context.getLangOpts().ImplicitModules && WritingModule) {
+  if (ShouldCacheASTInMemory) {
     // Construct MemoryBuffer and update buffer manager.
     ModuleCache.addBuiltPCM(OutputFile,
                             llvm::MemoryBuffer::getMemBufferCopy(
index 7c2ef5a13a1955c212b90291c3e53404d168b4b6..6d98524636f8e5bb7dfd26e32142420fecaf2df7 100644 (file)
@@ -24,12 +24,14 @@ PCHGenerator::PCHGenerator(
     const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
     StringRef OutputFile, StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer,
     ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
-    bool AllowASTWithErrors, bool IncludeTimestamps)
+    bool AllowASTWithErrors, bool IncludeTimestamps,
+    bool ShouldCacheASTInMemory)
     : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()),
       SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data),
       Writer(Stream, this->Buffer->Data, ModuleCache, Extensions,
              IncludeTimestamps),
-      AllowASTWithErrors(AllowASTWithErrors) {
+      AllowASTWithErrors(AllowASTWithErrors),
+      ShouldCacheASTInMemory(ShouldCacheASTInMemory) {
   this->Buffer->IsComplete = false;
 }
 
@@ -61,7 +63,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
       Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot,
                       // For serialization we are lenient if the errors were
                       // only warn-as-error kind.
-                      PP.getDiagnostics().hasUncompilableErrorOccurred());
+                      PP.getDiagnostics().hasUncompilableErrorOccurred(),
+                      ShouldCacheASTInMemory);
 
   Buffer->IsComplete = true;
 }
index 0203fe4ce2bf66713a7f1449a7942a8dbf790b05..20356c6d833a1f7bf696ae915384ec1011a998ee 100644 (file)
@@ -6,18 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Frontend/FrontendAction.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Serialization/InMemoryModuleCache.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ToolOutputFile.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -253,4 +255,40 @@ TEST(ASTFrontendAction, ExternalSemaSource) {
   EXPECT_EQ("This is a note", TDC->Note.str().str());
 }
 
+TEST(GeneratePCHFrontendAction, CacheGeneratedPCH) {
+  // Create a temporary file for writing out the PCH that will be cleaned up.
+  int PCHFD;
+  llvm::SmallString<128> PCHFilename;
+  ASSERT_FALSE(
+      llvm::sys::fs::createTemporaryFile("test.h", "pch", PCHFD, PCHFilename));
+  llvm::ToolOutputFile PCHFile(PCHFilename, PCHFD);
+
+  for (bool ShouldCache : {false, true}) {
+    auto Invocation = std::make_shared<CompilerInvocation>();
+    Invocation->getLangOpts()->CacheGeneratedPCH = ShouldCache;
+    Invocation->getPreprocessorOpts().addRemappedFile(
+        "test.h",
+        MemoryBuffer::getMemBuffer("int foo(void) { return 1; }\n").release());
+    Invocation->getFrontendOpts().Inputs.push_back(
+        FrontendInputFile("test.h", InputKind::C));
+    Invocation->getFrontendOpts().OutputFile = StringRef(PCHFilename);
+    Invocation->getFrontendOpts().ProgramAction = frontend::GeneratePCH;
+    Invocation->getTargetOpts().Triple = "x86_64-apple-darwin19.0.0";
+    CompilerInstance Compiler;
+    Compiler.setInvocation(std::move(Invocation));
+    Compiler.createDiagnostics();
+
+    GeneratePCHAction TestAction;
+    ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
+
+    // Check whether the PCH was cached.
+    if (ShouldCache)
+      EXPECT_EQ(InMemoryModuleCache::Final,
+                Compiler.getModuleCache().getPCMState(PCHFilename));
+    else
+      EXPECT_EQ(InMemoryModuleCache::Unknown,
+                Compiler.getModuleCache().getPCMState(PCHFilename));
+  }
+}
+
 } // anonymous namespace