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