| 1 | //===--- IncrementalAction.h - Incremental Frontend Action -*- 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 | #include "IncrementalAction.h" |
| 10 | |
| 11 | #include "clang/AST/ASTConsumer.h" |
| 12 | #include "clang/CodeGen/CodeGenAction.h" |
| 13 | #include "clang/CodeGen/ModuleBuilder.h" |
| 14 | #include "clang/Frontend/CompilerInstance.h" |
| 15 | #include "clang/Frontend/FrontendOptions.h" |
| 16 | #include "clang/FrontendTool/Utils.h" |
| 17 | #include "clang/Interpreter/Interpreter.h" |
| 18 | #include "clang/Lex/PreprocessorOptions.h" |
| 19 | #include "clang/Sema/Sema.h" |
| 20 | #include "llvm/IR/Module.h" |
| 21 | #include "llvm/Support/Error.h" |
| 22 | #include "llvm/Support/ErrorHandling.h" |
| 23 | |
| 24 | namespace clang { |
| 25 | IncrementalAction::IncrementalAction(CompilerInstance &Instance, |
| 26 | llvm::LLVMContext &LLVMCtx, |
| 27 | llvm::Error &Err, Interpreter &I, |
| 28 | std::unique_ptr<ASTConsumer> Consumer) |
| 29 | : WrapperFrontendAction([&]() { |
| 30 | llvm::ErrorAsOutParameter EAO(&Err); |
| 31 | std::unique_ptr<FrontendAction> Act; |
| 32 | switch (Instance.getFrontendOpts().ProgramAction) { |
| 33 | default: |
| 34 | Err = llvm::createStringError( |
| 35 | EC: std::errc::state_not_recoverable, |
| 36 | Fmt: "Driver initialization failed. " |
| 37 | "Incremental mode for action %d is not supported" , |
| 38 | Vals: Instance.getFrontendOpts().ProgramAction); |
| 39 | return Act; |
| 40 | case frontend::ASTDump: |
| 41 | case frontend::ASTPrint: |
| 42 | case frontend::ParseSyntaxOnly: |
| 43 | Act = CreateFrontendAction(CI&: Instance); |
| 44 | break; |
| 45 | case frontend::PluginAction: |
| 46 | case frontend::EmitAssembly: |
| 47 | case frontend::EmitBC: |
| 48 | case frontend::EmitObj: |
| 49 | case frontend::PrintPreprocessedInput: |
| 50 | case frontend::EmitLLVMOnly: |
| 51 | Act.reset(p: new EmitLLVMOnlyAction(&LLVMCtx)); |
| 52 | break; |
| 53 | } |
| 54 | return Act; |
| 55 | }()), |
| 56 | Interp(I), CI(Instance), Consumer(std::move(Consumer)) {} |
| 57 | |
| 58 | std::unique_ptr<ASTConsumer> |
| 59 | IncrementalAction::CreateASTConsumer(CompilerInstance & /*CI*/, |
| 60 | StringRef InFile) { |
| 61 | std::unique_ptr<ASTConsumer> C = |
| 62 | WrapperFrontendAction::CreateASTConsumer(CI&: this->CI, InFile); |
| 63 | |
| 64 | if (Consumer) { |
| 65 | std::vector<std::unique_ptr<ASTConsumer>> Cs; |
| 66 | Cs.push_back(x: std::move(Consumer)); |
| 67 | Cs.push_back(x: std::move(C)); |
| 68 | return std::make_unique<MultiplexConsumer>(args: std::move(Cs)); |
| 69 | } |
| 70 | |
| 71 | return std::make_unique<InProcessPrintingASTConsumer>(args: std::move(C), args&: Interp); |
| 72 | } |
| 73 | |
| 74 | void IncrementalAction::ExecuteAction() { |
| 75 | WrapperFrontendAction::ExecuteAction(); |
| 76 | getCompilerInstance().getSema().CurContext = nullptr; |
| 77 | } |
| 78 | |
| 79 | void IncrementalAction::EndSourceFile() { |
| 80 | if (IsTerminating && getWrapped()) |
| 81 | WrapperFrontendAction::EndSourceFile(); |
| 82 | } |
| 83 | |
| 84 | void IncrementalAction::FinalizeAction() { |
| 85 | assert(!IsTerminating && "Already finalized!" ); |
| 86 | IsTerminating = true; |
| 87 | EndSourceFile(); |
| 88 | } |
| 89 | |
| 90 | void IncrementalAction::CacheCodeGenModule() { |
| 91 | CachedInCodeGenModule = GenModule(); |
| 92 | } |
| 93 | |
| 94 | llvm::Module *IncrementalAction::getCachedCodeGenModule() const { |
| 95 | return CachedInCodeGenModule.get(); |
| 96 | } |
| 97 | |
| 98 | std::unique_ptr<llvm::Module> IncrementalAction::GenModule() { |
| 99 | static unsigned ID = 0; |
| 100 | if (CodeGenerator *CG = getCodeGen()) { |
| 101 | // Clang's CodeGen is designed to work with a single llvm::Module. In many |
| 102 | // cases for convenience various CodeGen parts have a reference to the |
| 103 | // llvm::Module (TheModule or Module) which does not change when a new |
| 104 | // module is pushed. However, the execution engine wants to take ownership |
| 105 | // of the module which does not map well to CodeGen's design. To work this |
| 106 | // around we created an empty module to make CodeGen happy. We should make |
| 107 | // sure it always stays empty. |
| 108 | assert(((!CachedInCodeGenModule || |
| 109 | !CI.getPreprocessorOpts().Includes.empty() || |
| 110 | !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) || |
| 111 | (CachedInCodeGenModule->empty() && |
| 112 | CachedInCodeGenModule->global_empty() && |
| 113 | CachedInCodeGenModule->alias_empty() && |
| 114 | CachedInCodeGenModule->ifunc_empty())) && |
| 115 | "CodeGen wrote to a readonly module" ); |
| 116 | std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); |
| 117 | CG->StartModule(ModuleName: "incr_module_" + std::to_string(val: ID++), C&: M->getContext()); |
| 118 | return M; |
| 119 | } |
| 120 | return nullptr; |
| 121 | } |
| 122 | |
| 123 | CodeGenerator *IncrementalAction::getCodeGen() const { |
| 124 | FrontendAction *WrappedAct = getWrapped(); |
| 125 | if (!WrappedAct || !WrappedAct->hasIRSupport()) |
| 126 | return nullptr; |
| 127 | return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); |
| 128 | } |
| 129 | |
| 130 | InProcessPrintingASTConsumer::InProcessPrintingASTConsumer( |
| 131 | std::unique_ptr<ASTConsumer> C, Interpreter &I) |
| 132 | : MultiplexConsumer(std::move(C)), Interp(I) {} |
| 133 | |
| 134 | bool InProcessPrintingASTConsumer::HandleTopLevelDecl(DeclGroupRef DGR) { |
| 135 | if (DGR.isNull()) |
| 136 | return true; |
| 137 | |
| 138 | CompilerInstance *CI = Interp.getCompilerInstance(); |
| 139 | DiagnosticsEngine &Diags = CI->getDiagnostics(); |
| 140 | if (Diags.hasErrorOccurred()) |
| 141 | return true; |
| 142 | |
| 143 | for (Decl *D : DGR) |
| 144 | if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(Val: D)) |
| 145 | if (TLSD && TLSD->isSemiMissing()) { |
| 146 | auto ExprOrErr = Interp.convertExprToValue(E: cast<Expr>(Val: TLSD->getStmt())); |
| 147 | if (llvm::Error E = ExprOrErr.takeError()) { |
| 148 | llvm::logAllUnhandledErrors(E: std::move(E), OS&: llvm::errs(), |
| 149 | ErrorBanner: "Value printing failed: " ); |
| 150 | return false; // abort parsing |
| 151 | } |
| 152 | TLSD->setStmt(*ExprOrErr); |
| 153 | } |
| 154 | |
| 155 | return MultiplexConsumer::HandleTopLevelDecl(D: DGR); |
| 156 | } |
| 157 | |
| 158 | } // namespace clang |
| 159 | |