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/Frontend/FrontendDiagnostic.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), OutputFile(OutputFile), isysroot(isysroot.str()), 33 SemaPtr(nullptr), 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 void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { 60 // Don't create a PCH if there were fatal failures during module loading. 61 if (PP.getModuleLoader().HadFatalFailure) 62 return; 63 64 bool hasErrors = PP.getDiagnostics().hasErrorOccurred(); 65 if (hasErrors && !AllowASTWithErrors) 66 return; 67 68 Module *Module = getEmittingModule(Ctx); 69 70 // Errors that do not prevent the PCH from being written should not cause the 71 // overall compilation to fail either. 72 if (AllowASTWithErrors) 73 PP.getDiagnostics().getClient()->clear(); 74 75 // Emit the PCH file to the Buffer. 76 assert(SemaPtr && "No Sema?"); 77 Buffer->Signature = Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, 78 ShouldCacheASTInMemory); 79 80 Buffer->IsComplete = true; 81 } 82 83 ASTMutationListener *PCHGenerator::GetASTMutationListener() { 84 return &Writer; 85 } 86 87 ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { 88 return &Writer; 89 } 90 91 void PCHGenerator::anchor() {} 92 93 CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP, 94 InMemoryModuleCache &ModuleCache, 95 StringRef OutputFile, 96 bool GeneratingReducedBMI) 97 : PCHGenerator( 98 PP, ModuleCache, OutputFile, llvm::StringRef(), 99 std::make_shared<PCHBuffer>(), 100 /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(), 101 /*AllowASTWithErrors*/ false, /*IncludeTimestamps=*/false, 102 /*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false, 103 GeneratingReducedBMI) {} 104 105 Module *CXX20ModulesGenerator::getEmittingModule(ASTContext &Ctx) { 106 Module *M = Ctx.getCurrentNamedModule(); 107 assert(M && M->isNamedModuleUnit() && 108 "CXX20ModulesGenerator should only be used with C++20 Named modules."); 109 return M; 110 } 111 112 void CXX20ModulesGenerator::HandleTranslationUnit(ASTContext &Ctx) { 113 // FIMXE: We'd better to wrap such options to a new class ASTWriterOptions 114 // since this is not about searching header really. 115 HeaderSearchOptions &HSOpts = 116 getPreprocessor().getHeaderSearchInfo().getHeaderSearchOpts(); 117 HSOpts.ModulesSkipDiagnosticOptions = true; 118 HSOpts.ModulesSkipHeaderSearchPaths = true; 119 120 PCHGenerator::HandleTranslationUnit(Ctx); 121 122 if (!isComplete()) 123 return; 124 125 std::error_code EC; 126 auto OS = std::make_unique<llvm::raw_fd_ostream>(getOutputFile(), EC); 127 if (EC) { 128 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 129 << getOutputFile() << EC.message() << "\n"; 130 return; 131 } 132 133 *OS << getBufferPtr()->Data; 134 OS->flush(); 135 } 136 137 void CXX20ModulesGenerator::anchor() {} 138 139 void ReducedBMIGenerator::anchor() {} 140