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 &CI,
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 (CI.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
+ CI.getFrontendOpts ().ProgramAction );
39
+ return Act;
40
+ case frontend::ASTDump:
41
+ case frontend::ASTPrint:
42
+ case frontend::ParseSyntaxOnly:
43
+ Act = CreateFrontendAction (CI);
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(CI), Consumer(std::move(Consumer)) {}
57
+
58
+ std::unique_ptr<ASTConsumer>
59
+ IncrementalAction::CreateASTConsumer (CompilerInstance &CI, StringRef InFile) {
60
+ std::unique_ptr<ASTConsumer> C =
61
+ WrapperFrontendAction::CreateASTConsumer (CI, InFile);
62
+
63
+ if (Consumer) {
64
+ std::vector<std::unique_ptr<ASTConsumer>> Cs;
65
+ Cs.push_back (std::move (Consumer));
66
+ Cs.push_back (std::move (C));
67
+ return std::make_unique<MultiplexConsumer>(std::move (Cs));
68
+ }
69
+
70
+ return std::make_unique<InProcessPrintingASTConsumer>(std::move (C), Interp);
71
+ }
72
+
73
+ void IncrementalAction::ExecuteAction () {
74
+ WrapperFrontendAction::ExecuteAction ();
75
+ getCompilerInstance ().getSema ().CurContext = nullptr ;
76
+ }
77
+
78
+ void IncrementalAction::EndSourceFile () {
79
+ if (IsTerminating && getWrapped ())
80
+ WrapperFrontendAction::EndSourceFile ();
81
+ }
82
+
83
+ void IncrementalAction::FinalizeAction () {
84
+ assert (!IsTerminating && " Already finalized!" );
85
+ IsTerminating = true ;
86
+ EndSourceFile ();
87
+ }
88
+
89
+ void IncrementalAction::CacheCodeGenModule () {
90
+ CachedInCodeGenModule = GenModule ();
91
+ }
92
+
93
+ llvm::Module *IncrementalAction::getCachedCodeGenModule () const {
94
+ return CachedInCodeGenModule.get ();
95
+ }
96
+
97
+ std::unique_ptr<llvm::Module> IncrementalAction::GenModule () {
98
+ static unsigned ID = 0 ;
99
+ if (CodeGenerator *CG = getCodeGen ()) {
100
+ // Clang's CodeGen is designed to work with a single llvm::Module. In many
101
+ // cases for convenience various CodeGen parts have a reference to the
102
+ // llvm::Module (TheModule or Module) which does not change when a new
103
+ // module is pushed. However, the execution engine wants to take ownership
104
+ // of the module which does not map well to CodeGen's design. To work this
105
+ // around we created an empty module to make CodeGen happy. We should make
106
+ // sure it always stays empty.
107
+ assert (((!CachedInCodeGenModule ||
108
+ !CI.getPreprocessorOpts ().Includes .empty ()) ||
109
+ (CachedInCodeGenModule->empty () &&
110
+ CachedInCodeGenModule->global_empty () &&
111
+ CachedInCodeGenModule->alias_empty () &&
112
+ CachedInCodeGenModule->ifunc_empty ())) &&
113
+ " CodeGen wrote to a readonly module" );
114
+ std::unique_ptr<llvm::Module> M (CG->ReleaseModule ());
115
+ CG->StartModule (" incr_module_" + std::to_string (ID++), M->getContext ());
116
+ return M;
117
+ }
118
+ return nullptr ;
119
+ }
120
+
121
+ CodeGenerator *IncrementalAction::getCodeGen () const {
122
+ FrontendAction *WrappedAct = getWrapped ();
123
+ if (!WrappedAct || !WrappedAct->hasIRSupport ())
124
+ return nullptr ;
125
+ return static_cast <CodeGenAction *>(WrappedAct)->getCodeGenerator ();
126
+ }
127
+
128
+ InProcessPrintingASTConsumer::InProcessPrintingASTConsumer (
129
+ std::unique_ptr<ASTConsumer> C, Interpreter &I)
130
+ : MultiplexConsumer(std::move(C)), Interp(I) {}
131
+
132
+ bool InProcessPrintingASTConsumer::HandleTopLevelDecl (DeclGroupRef DGR) {
133
+ if (DGR.isNull ())
134
+ return true ;
135
+
136
+ for (Decl *D : DGR)
137
+ if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
138
+ if (TLSD && TLSD->isSemiMissing ()) {
139
+ auto ExprOrErr = Interp.convertExprToValue (cast<Expr>(TLSD->getStmt ()));
140
+ if (llvm::Error E = ExprOrErr.takeError ()) {
141
+ llvm::logAllUnhandledErrors (std::move (E), llvm::errs (),
142
+ " Value printing failed: " );
143
+ return false ; // abort parsing
144
+ }
145
+ TLSD->setStmt (*ExprOrErr);
146
+ }
147
+
148
+ return MultiplexConsumer::HandleTopLevelDecl (DGR);
149
+ }
150
+
151
+ } // namespace clang
0 commit comments