1 //===--- GeneratePCH.cpp - Sema Consumer for PCH Generation -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the PCHGenerator, which as a SemaConsumer that generates 10 // a PCH file. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/AST/ASTContext.h" 15 #include "clang/Basic/DiagnosticFrontend.h" 16 #include "clang/Lex/HeaderSearch.h" 17 #include "clang/Lex/HeaderSearchOptions.h" 18 #include "clang/Lex/Preprocessor.h" 19 #include "clang/Sema/SemaConsumer.h" 20 #include "clang/Serialization/ASTWriter.h" 21 #include "llvm/Bitstream/BitstreamWriter.h" 22 23 using namespace clang; 24 25 PCHGenerator::PCHGenerator( 26 Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, 27 StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer, 28 ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, 29 bool AllowASTWithErrors, bool IncludeTimestamps, 30 bool BuildingImplicitModule, bool ShouldCacheASTInMemory, 31 bool GeneratingReducedBMI) 32 : PP(PP), Subject(&PP), OutputFile(OutputFile), isysroot(isysroot.str()), 33 Buffer(std::move(Buffer)), Stream(this->Buffer->Data), 34 Writer(Stream, this->Buffer->Data, ModuleCache, Extensions, 35 IncludeTimestamps, BuildingImplicitModule, GeneratingReducedBMI), 36 AllowASTWithErrors(AllowASTWithErrors), 37 ShouldCacheASTInMemory(ShouldCacheASTInMemory) { 38 this->Buffer->IsComplete = false; 39 } 40 41 PCHGenerator::~PCHGenerator() { 42 } 43 44 Module *PCHGenerator::getEmittingModule(ASTContext &) { 45 Module *M = nullptr; 46 47 if (PP.getLangOpts().isCompilingModule()) { 48 M = PP.getHeaderSearchInfo().lookupModule(PP.getLangOpts().CurrentModule, 49 SourceLocation(), 50 /*AllowSearch*/ false); 51 if (!M) 52 assert(PP.getDiagnostics().hasErrorOccurred() && 53 "emitting module but current module doesn't exist"); 54 } 55 56 return M; 57 } 58 59 DiagnosticsEngine &PCHGenerator::getDiagnostics() const { 60 return PP.getDiagnostics(); 61 } 62 63 void PCHGenerator::InitializeSema(Sema &S) { 64 if (!PP.getHeaderSearchInfo() 65 .getHeaderSearchOpts() 66 .ModulesSerializeOnlyPreprocessor) 67 Subject = &S; 68 } 69 70 void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { 71 // Don't create a PCH if there were fatal failures during module loading. 72 if (PP.getModuleLoader().HadFatalFailure) 73 return; 74 75 bool hasErrors = PP.getDiagnostics().hasErrorOccurred(); 76 if (hasErrors && !AllowASTWithErrors) 77 return; 78 79 Module *Module = getEmittingModule(Ctx); 80 81 // Errors that do not prevent the PCH from being written should not cause the 82 // overall compilation to fail either. 83 if (AllowASTWithErrors) 84 PP.getDiagnostics().getClient()->clear(); 85 86 Buffer->Signature = Writer.WriteAST(Subject, OutputFile, Module, isysroot, 87 ShouldCacheASTInMemory); 88 89 Buffer->IsComplete = true; 90 } 91 92 ASTMutationListener *PCHGenerator::GetASTMutationListener() { 93 return &Writer; 94 } 95 96 ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { 97 return &Writer; 98 } 99 100 void PCHGenerator::anchor() {} 101 102 CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP, 103 InMemoryModuleCache &ModuleCache, 104 StringRef OutputFile, 105 bool GeneratingReducedBMI, 106 bool AllowASTWithErrors) 107 : PCHGenerator( 108 PP, ModuleCache, OutputFile, llvm::StringRef(), 109 std::make_shared<PCHBuffer>(), 110 /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(), 111 AllowASTWithErrors, /*IncludeTimestamps=*/false, 112 /*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false, 113 GeneratingReducedBMI) {} 114 115 Module *CXX20ModulesGenerator::getEmittingModule(ASTContext &Ctx) { 116 Module *M = Ctx.getCurrentNamedModule(); 117 assert(M && M->isNamedModuleUnit() && 118 "CXX20ModulesGenerator should only be used with C++20 Named modules."); 119 return M; 120 } 121 122 void CXX20ModulesGenerator::HandleTranslationUnit(ASTContext &Ctx) { 123 // FIMXE: We'd better to wrap such options to a new class ASTWriterOptions 124 // since this is not about searching header really. 125 HeaderSearchOptions &HSOpts = 126 getPreprocessor().getHeaderSearchInfo().getHeaderSearchOpts(); 127 HSOpts.ModulesSkipDiagnosticOptions = true; 128 HSOpts.ModulesSkipHeaderSearchPaths = true; 129 130 PCHGenerator::HandleTranslationUnit(Ctx); 131 132 if (!isComplete()) 133 return; 134 135 std::error_code EC; 136 auto OS = std::make_unique<llvm::raw_fd_ostream>(getOutputFile(), EC); 137 if (EC) { 138 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 139 << getOutputFile() << EC.message() << "\n"; 140 return; 141 } 142 143 *OS << getBufferPtr()->Data; 144 OS->flush(); 145 } 146 147 void CXX20ModulesGenerator::anchor() {} 148 149 void ReducedBMIGenerator::anchor() {} 150