154 lines · cpp
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-exception6//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 24namespace clang {25IncrementalAction::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 std::errc::state_not_recoverable,36 "Driver initialization failed. "37 "Incremental mode for action %d is not supported",38 Instance.getFrontendOpts().ProgramAction);39 return Act;40 case frontend::ASTDump:41 case frontend::ASTPrint:42 case frontend::ParseSyntaxOnly:43 Act = CreateFrontendAction(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(new EmitLLVMOnlyAction(&LLVMCtx));52 break;53 }54 return Act;55 }()),56 Interp(I), CI(Instance), Consumer(std::move(Consumer)) {}57 58std::unique_ptr<ASTConsumer>59IncrementalAction::CreateASTConsumer(CompilerInstance & /*CI*/,60 StringRef InFile) {61 std::unique_ptr<ASTConsumer> C =62 WrapperFrontendAction::CreateASTConsumer(this->CI, InFile);63 64 if (Consumer) {65 std::vector<std::unique_ptr<ASTConsumer>> Cs;66 Cs.push_back(std::move(Consumer));67 Cs.push_back(std::move(C));68 return std::make_unique<MultiplexConsumer>(std::move(Cs));69 }70 71 return std::make_unique<InProcessPrintingASTConsumer>(std::move(C), Interp);72}73 74void IncrementalAction::ExecuteAction() {75 WrapperFrontendAction::ExecuteAction();76 getCompilerInstance().getSema().CurContext = nullptr;77}78 79void IncrementalAction::EndSourceFile() {80 if (IsTerminating && getWrapped())81 WrapperFrontendAction::EndSourceFile();82}83 84void IncrementalAction::FinalizeAction() {85 assert(!IsTerminating && "Already finalized!");86 IsTerminating = true;87 EndSourceFile();88}89 90void IncrementalAction::CacheCodeGenModule() {91 CachedInCodeGenModule = GenModule();92}93 94llvm::Module *IncrementalAction::getCachedCodeGenModule() const {95 return CachedInCodeGenModule.get();96}97 98std::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 many102 // cases for convenience various CodeGen parts have a reference to the103 // llvm::Module (TheModule or Module) which does not change when a new104 // module is pushed. However, the execution engine wants to take ownership105 // of the module which does not map well to CodeGen's design. To work this106 // around we created an empty module to make CodeGen happy. We should make107 // 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("incr_module_" + std::to_string(ID++), M->getContext());118 return M;119 }120 return nullptr;121}122 123CodeGenerator *IncrementalAction::getCodeGen() const {124 FrontendAction *WrappedAct = getWrapped();125 if (!WrappedAct || !WrappedAct->hasIRSupport())126 return nullptr;127 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();128}129 130InProcessPrintingASTConsumer::InProcessPrintingASTConsumer(131 std::unique_ptr<ASTConsumer> C, Interpreter &I)132 : MultiplexConsumer(std::move(C)), Interp(I) {}133 134bool InProcessPrintingASTConsumer::HandleTopLevelDecl(DeclGroupRef DGR) {135 if (DGR.isNull())136 return true;137 138 for (Decl *D : DGR)139 if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))140 if (TLSD && TLSD->isSemiMissing()) {141 auto ExprOrErr = Interp.convertExprToValue(cast<Expr>(TLSD->getStmt()));142 if (llvm::Error E = ExprOrErr.takeError()) {143 llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),144 "Value printing failed: ");145 return false; // abort parsing146 }147 TLSD->setStmt(*ExprOrErr);148 }149 150 return MultiplexConsumer::HandleTopLevelDecl(DGR);151}152 153} // namespace clang154