Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -154,6 +154,7 @@ "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: clang/include/clang/Serialization/ASTWriter.h =================================================================== --- clang/include/clang/Serialization/ASTWriter.h +++ clang/include/clang/Serialization/ASTWriter.h @@ -570,7 +570,8 @@ /// 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 @@ llvm::BitstreamWriter Stream; ASTWriter Writer; bool AllowASTWithErrors; + bool ShouldCacheASTInMemory; protected: ASTWriter &getWriter() { return Writer; } @@ -985,7 +987,8 @@ StringRef OutputFile, StringRef isysroot, std::shared_ptr Buffer, ArrayRef> 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: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -112,7 +112,7 @@ 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 @@ 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: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -4596,7 +4596,8 @@ 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 @@ 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: clang/lib/Serialization/GeneratePCH.cpp =================================================================== --- clang/lib/Serialization/GeneratePCH.cpp +++ clang/lib/Serialization/GeneratePCH.cpp @@ -24,12 +24,14 @@ const Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, StringRef isysroot, std::shared_ptr Buffer, ArrayRef> 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 @@ 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: clang/unittests/Frontend/FrontendActionTest.cpp =================================================================== --- clang/unittests/Frontend/FrontendActionTest.cpp +++ clang/unittests/Frontend/FrontendActionTest.cpp @@ -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 @@ 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(); + 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