xref: /freebsd/contrib/llvm-project/clang/lib/Serialization/GeneratePCH.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- GeneratePCH.cpp - Sema Consumer for PCH Generation -----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines the PCHGenerator, which as a SemaConsumer that generates
100b57cec5SDimitry Andric //  a PCH file.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
15*0fca6ea1SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
160b57cec5SDimitry Andric #include "clang/Lex/HeaderSearch.h"
17*0fca6ea1SDimitry Andric #include "clang/Lex/HeaderSearchOptions.h"
180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
190b57cec5SDimitry Andric #include "clang/Sema/SemaConsumer.h"
200b57cec5SDimitry Andric #include "clang/Serialization/ASTWriter.h"
210b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace clang;
240b57cec5SDimitry Andric 
PCHGenerator(Preprocessor & PP,InMemoryModuleCache & ModuleCache,StringRef OutputFile,StringRef isysroot,std::shared_ptr<PCHBuffer> Buffer,ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,bool AllowASTWithErrors,bool IncludeTimestamps,bool BuildingImplicitModule,bool ShouldCacheASTInMemory,bool GeneratingReducedBMI)250b57cec5SDimitry Andric PCHGenerator::PCHGenerator(
26*0fca6ea1SDimitry Andric     Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile,
27*0fca6ea1SDimitry Andric     StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer,
280b57cec5SDimitry Andric     ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
290b57cec5SDimitry Andric     bool AllowASTWithErrors, bool IncludeTimestamps,
30*0fca6ea1SDimitry Andric     bool BuildingImplicitModule, bool ShouldCacheASTInMemory,
31*0fca6ea1SDimitry Andric     bool GeneratingReducedBMI)
320b57cec5SDimitry Andric     : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()),
330b57cec5SDimitry Andric       SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data),
340b57cec5SDimitry Andric       Writer(Stream, this->Buffer->Data, ModuleCache, Extensions,
35*0fca6ea1SDimitry Andric              IncludeTimestamps, BuildingImplicitModule, GeneratingReducedBMI),
360b57cec5SDimitry Andric       AllowASTWithErrors(AllowASTWithErrors),
370b57cec5SDimitry Andric       ShouldCacheASTInMemory(ShouldCacheASTInMemory) {
380b57cec5SDimitry Andric   this->Buffer->IsComplete = false;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
~PCHGenerator()410b57cec5SDimitry Andric PCHGenerator::~PCHGenerator() {
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
getEmittingModule(ASTContext &)44*0fca6ea1SDimitry Andric Module *PCHGenerator::getEmittingModule(ASTContext &) {
45*0fca6ea1SDimitry Andric   Module *M = nullptr;
46*0fca6ea1SDimitry Andric 
47*0fca6ea1SDimitry Andric   if (PP.getLangOpts().isCompilingModule()) {
48*0fca6ea1SDimitry Andric     M = PP.getHeaderSearchInfo().lookupModule(PP.getLangOpts().CurrentModule,
49*0fca6ea1SDimitry Andric                                               SourceLocation(),
50*0fca6ea1SDimitry Andric                                               /*AllowSearch*/ false);
51*0fca6ea1SDimitry Andric     if (!M)
52*0fca6ea1SDimitry Andric       assert(PP.getDiagnostics().hasErrorOccurred() &&
53*0fca6ea1SDimitry Andric              "emitting module but current module doesn't exist");
54*0fca6ea1SDimitry Andric   }
55*0fca6ea1SDimitry Andric 
56*0fca6ea1SDimitry Andric   return M;
57*0fca6ea1SDimitry Andric }
58*0fca6ea1SDimitry Andric 
HandleTranslationUnit(ASTContext & Ctx)590b57cec5SDimitry Andric void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
600b57cec5SDimitry Andric   // Don't create a PCH if there were fatal failures during module loading.
610b57cec5SDimitry Andric   if (PP.getModuleLoader().HadFatalFailure)
620b57cec5SDimitry Andric     return;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   bool hasErrors = PP.getDiagnostics().hasErrorOccurred();
650b57cec5SDimitry Andric   if (hasErrors && !AllowASTWithErrors)
660b57cec5SDimitry Andric     return;
670b57cec5SDimitry Andric 
68*0fca6ea1SDimitry Andric   Module *Module = getEmittingModule(Ctx);
690b57cec5SDimitry Andric 
705ffd83dbSDimitry Andric   // Errors that do not prevent the PCH from being written should not cause the
715ffd83dbSDimitry Andric   // overall compilation to fail either.
725ffd83dbSDimitry Andric   if (AllowASTWithErrors)
735ffd83dbSDimitry Andric     PP.getDiagnostics().getClient()->clear();
745ffd83dbSDimitry Andric 
750b57cec5SDimitry Andric   // Emit the PCH file to the Buffer.
760b57cec5SDimitry Andric   assert(SemaPtr && "No Sema?");
775f757f3fSDimitry Andric   Buffer->Signature = Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot,
780b57cec5SDimitry Andric                                       ShouldCacheASTInMemory);
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   Buffer->IsComplete = true;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
GetASTMutationListener()830b57cec5SDimitry Andric ASTMutationListener *PCHGenerator::GetASTMutationListener() {
840b57cec5SDimitry Andric   return &Writer;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
GetASTDeserializationListener()870b57cec5SDimitry Andric ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
880b57cec5SDimitry Andric   return &Writer;
890b57cec5SDimitry Andric }
90*0fca6ea1SDimitry Andric 
anchor()91*0fca6ea1SDimitry Andric void PCHGenerator::anchor() {}
92*0fca6ea1SDimitry Andric 
CXX20ModulesGenerator(Preprocessor & PP,InMemoryModuleCache & ModuleCache,StringRef OutputFile,bool GeneratingReducedBMI)93*0fca6ea1SDimitry Andric CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP,
94*0fca6ea1SDimitry Andric                                              InMemoryModuleCache &ModuleCache,
95*0fca6ea1SDimitry Andric                                              StringRef OutputFile,
96*0fca6ea1SDimitry Andric                                              bool GeneratingReducedBMI)
97*0fca6ea1SDimitry Andric     : PCHGenerator(
98*0fca6ea1SDimitry Andric           PP, ModuleCache, OutputFile, llvm::StringRef(),
99*0fca6ea1SDimitry Andric           std::make_shared<PCHBuffer>(),
100*0fca6ea1SDimitry Andric           /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
101*0fca6ea1SDimitry Andric           /*AllowASTWithErrors*/ false, /*IncludeTimestamps=*/false,
102*0fca6ea1SDimitry Andric           /*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false,
103*0fca6ea1SDimitry Andric           GeneratingReducedBMI) {}
104*0fca6ea1SDimitry Andric 
getEmittingModule(ASTContext & Ctx)105*0fca6ea1SDimitry Andric Module *CXX20ModulesGenerator::getEmittingModule(ASTContext &Ctx) {
106*0fca6ea1SDimitry Andric   Module *M = Ctx.getCurrentNamedModule();
107*0fca6ea1SDimitry Andric   assert(M && M->isNamedModuleUnit() &&
108*0fca6ea1SDimitry Andric          "CXX20ModulesGenerator should only be used with C++20 Named modules.");
109*0fca6ea1SDimitry Andric   return M;
110*0fca6ea1SDimitry Andric }
111*0fca6ea1SDimitry Andric 
HandleTranslationUnit(ASTContext & Ctx)112*0fca6ea1SDimitry Andric void CXX20ModulesGenerator::HandleTranslationUnit(ASTContext &Ctx) {
113*0fca6ea1SDimitry Andric   // FIMXE: We'd better to wrap such options to a new class ASTWriterOptions
114*0fca6ea1SDimitry Andric   // since this is not about searching header really.
115*0fca6ea1SDimitry Andric   HeaderSearchOptions &HSOpts =
116*0fca6ea1SDimitry Andric       getPreprocessor().getHeaderSearchInfo().getHeaderSearchOpts();
117*0fca6ea1SDimitry Andric   HSOpts.ModulesSkipDiagnosticOptions = true;
118*0fca6ea1SDimitry Andric   HSOpts.ModulesSkipHeaderSearchPaths = true;
119*0fca6ea1SDimitry Andric 
120*0fca6ea1SDimitry Andric   PCHGenerator::HandleTranslationUnit(Ctx);
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric   if (!isComplete())
123*0fca6ea1SDimitry Andric     return;
124*0fca6ea1SDimitry Andric 
125*0fca6ea1SDimitry Andric   std::error_code EC;
126*0fca6ea1SDimitry Andric   auto OS = std::make_unique<llvm::raw_fd_ostream>(getOutputFile(), EC);
127*0fca6ea1SDimitry Andric   if (EC) {
128*0fca6ea1SDimitry Andric     getDiagnostics().Report(diag::err_fe_unable_to_open_output)
129*0fca6ea1SDimitry Andric         << getOutputFile() << EC.message() << "\n";
130*0fca6ea1SDimitry Andric     return;
131*0fca6ea1SDimitry Andric   }
132*0fca6ea1SDimitry Andric 
133*0fca6ea1SDimitry Andric   *OS << getBufferPtr()->Data;
134*0fca6ea1SDimitry Andric   OS->flush();
135*0fca6ea1SDimitry Andric }
136*0fca6ea1SDimitry Andric 
anchor()137*0fca6ea1SDimitry Andric void CXX20ModulesGenerator::anchor() {}
138*0fca6ea1SDimitry Andric 
anchor()139*0fca6ea1SDimitry Andric void ReducedBMIGenerator::anchor() {}
140