1 | //===--------- IncrementalParser.cpp - Incremental Compilation -----------===// |
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 implements the class which performs incremental code compilation. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "IncrementalParser.h" |
14 | |
15 | #include "clang/AST/DeclContextInternals.h" |
16 | #include "clang/CodeGen/BackendUtil.h" |
17 | #include "clang/CodeGen/CodeGenAction.h" |
18 | #include "clang/CodeGen/ModuleBuilder.h" |
19 | #include "clang/Frontend/CompilerInstance.h" |
20 | #include "clang/Frontend/FrontendAction.h" |
21 | #include "clang/FrontendTool/Utils.h" |
22 | #include "clang/Interpreter/Interpreter.h" |
23 | #include "clang/Parse/Parser.h" |
24 | #include "clang/Sema/Sema.h" |
25 | #include "llvm/Option/ArgList.h" |
26 | #include "llvm/Support/CrashRecoveryContext.h" |
27 | #include "llvm/Support/Error.h" |
28 | #include "llvm/Support/Timer.h" |
29 | |
30 | #include <sstream> |
31 | |
32 | namespace clang { |
33 | |
34 | class IncrementalASTConsumer final : public ASTConsumer { |
35 | Interpreter &Interp; |
36 | std::unique_ptr<ASTConsumer> Consumer; |
37 | |
38 | public: |
39 | IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr<ASTConsumer> C) |
40 | : Interp(InterpRef), Consumer(std::move(C)) {} |
41 | |
42 | bool HandleTopLevelDecl(DeclGroupRef DGR) override final { |
43 | if (DGR.isNull()) |
44 | return true; |
45 | if (!Consumer) |
46 | return true; |
47 | |
48 | for (Decl *D : DGR) |
49 | if (auto *TSD = llvm::dyn_cast<TopLevelStmtDecl>(Val: D); |
50 | TSD && TSD->isSemiMissing()) |
51 | TSD->setStmt(Interp.SynthesizeExpr(E: cast<Expr>(Val: TSD->getStmt()))); |
52 | |
53 | return Consumer->HandleTopLevelDecl(D: DGR); |
54 | } |
55 | void HandleTranslationUnit(ASTContext &Ctx) override final { |
56 | Consumer->HandleTranslationUnit(Ctx); |
57 | } |
58 | void HandleInlineFunctionDefinition(FunctionDecl *D) override final { |
59 | Consumer->HandleInlineFunctionDefinition(D); |
60 | } |
61 | void HandleInterestingDecl(DeclGroupRef D) override final { |
62 | Consumer->HandleInterestingDecl(D); |
63 | } |
64 | void HandleTagDeclDefinition(TagDecl *D) override final { |
65 | Consumer->HandleTagDeclDefinition(D); |
66 | } |
67 | void HandleTagDeclRequiredDefinition(const TagDecl *D) override final { |
68 | Consumer->HandleTagDeclRequiredDefinition(D); |
69 | } |
70 | void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final { |
71 | Consumer->HandleCXXImplicitFunctionInstantiation(D); |
72 | } |
73 | void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final { |
74 | Consumer->HandleTopLevelDeclInObjCContainer(D); |
75 | } |
76 | void HandleImplicitImportDecl(ImportDecl *D) override final { |
77 | Consumer->HandleImplicitImportDecl(D); |
78 | } |
79 | void CompleteTentativeDefinition(VarDecl *D) override final { |
80 | Consumer->CompleteTentativeDefinition(D); |
81 | } |
82 | void CompleteExternalDeclaration(DeclaratorDecl *D) override final { |
83 | Consumer->CompleteExternalDeclaration(D); |
84 | } |
85 | void AssignInheritanceModel(CXXRecordDecl *RD) override final { |
86 | Consumer->AssignInheritanceModel(RD); |
87 | } |
88 | void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final { |
89 | Consumer->HandleCXXStaticMemberVarInstantiation(D); |
90 | } |
91 | void HandleVTable(CXXRecordDecl *RD) override final { |
92 | Consumer->HandleVTable(RD); |
93 | } |
94 | ASTMutationListener *GetASTMutationListener() override final { |
95 | return Consumer->GetASTMutationListener(); |
96 | } |
97 | ASTDeserializationListener *GetASTDeserializationListener() override final { |
98 | return Consumer->GetASTDeserializationListener(); |
99 | } |
100 | void PrintStats() override final { Consumer->PrintStats(); } |
101 | bool shouldSkipFunctionBody(Decl *D) override final { |
102 | return Consumer->shouldSkipFunctionBody(D); |
103 | } |
104 | static bool classof(const clang::ASTConsumer *) { return true; } |
105 | }; |
106 | |
107 | /// A custom action enabling the incremental processing functionality. |
108 | /// |
109 | /// The usual \p FrontendAction expects one call to ExecuteAction and once it |
110 | /// sees a call to \p EndSourceFile it deletes some of the important objects |
111 | /// such as \p Preprocessor and \p Sema assuming no further input will come. |
112 | /// |
113 | /// \p IncrementalAction ensures it keep its underlying action's objects alive |
114 | /// as long as the \p IncrementalParser needs them. |
115 | /// |
116 | class IncrementalAction : public WrapperFrontendAction { |
117 | private: |
118 | bool IsTerminating = false; |
119 | |
120 | public: |
121 | IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, |
122 | llvm::Error &Err) |
123 | : WrapperFrontendAction([&]() { |
124 | llvm::ErrorAsOutParameter EAO(&Err); |
125 | std::unique_ptr<FrontendAction> Act; |
126 | switch (CI.getFrontendOpts().ProgramAction) { |
127 | default: |
128 | Err = llvm::createStringError( |
129 | EC: std::errc::state_not_recoverable, |
130 | Fmt: "Driver initialization failed. " |
131 | "Incremental mode for action %d is not supported" , |
132 | Vals: CI.getFrontendOpts().ProgramAction); |
133 | return Act; |
134 | case frontend::ASTDump: |
135 | [[fallthrough]]; |
136 | case frontend::ASTPrint: |
137 | [[fallthrough]]; |
138 | case frontend::ParseSyntaxOnly: |
139 | Act = CreateFrontendAction(CI); |
140 | break; |
141 | case frontend::PluginAction: |
142 | [[fallthrough]]; |
143 | case frontend::EmitAssembly: |
144 | [[fallthrough]]; |
145 | case frontend::EmitBC: |
146 | [[fallthrough]]; |
147 | case frontend::EmitObj: |
148 | [[fallthrough]]; |
149 | case frontend::PrintPreprocessedInput: |
150 | [[fallthrough]]; |
151 | case frontend::EmitLLVMOnly: |
152 | Act.reset(p: new EmitLLVMOnlyAction(&LLVMCtx)); |
153 | break; |
154 | } |
155 | return Act; |
156 | }()) {} |
157 | FrontendAction *getWrapped() const { return WrappedAction.get(); } |
158 | TranslationUnitKind getTranslationUnitKind() override { |
159 | return TU_Incremental; |
160 | } |
161 | |
162 | void ExecuteAction() override { |
163 | CompilerInstance &CI = getCompilerInstance(); |
164 | assert(CI.hasPreprocessor() && "No PP!" ); |
165 | |
166 | // Use a code completion consumer? |
167 | CodeCompleteConsumer *CompletionConsumer = nullptr; |
168 | if (CI.hasCodeCompletionConsumer()) |
169 | CompletionConsumer = &CI.getCodeCompletionConsumer(); |
170 | |
171 | Preprocessor &PP = CI.getPreprocessor(); |
172 | PP.EnterMainSourceFile(); |
173 | |
174 | if (!CI.hasSema()) |
175 | CI.createSema(TUKind: getTranslationUnitKind(), CompletionConsumer); |
176 | } |
177 | |
178 | // Do not terminate after processing the input. This allows us to keep various |
179 | // clang objects alive and to incrementally grow the current TU. |
180 | void EndSourceFile() override { |
181 | // The WrappedAction can be nullptr if we issued an error in the ctor. |
182 | if (IsTerminating && getWrapped()) |
183 | WrapperFrontendAction::EndSourceFile(); |
184 | } |
185 | |
186 | void FinalizeAction() { |
187 | assert(!IsTerminating && "Already finalized!" ); |
188 | IsTerminating = true; |
189 | EndSourceFile(); |
190 | } |
191 | }; |
192 | |
193 | CodeGenerator *IncrementalParser::getCodeGen() const { |
194 | FrontendAction *WrappedAct = Act->getWrapped(); |
195 | if (!WrappedAct->hasIRSupport()) |
196 | return nullptr; |
197 | return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); |
198 | } |
199 | |
200 | IncrementalParser::IncrementalParser() {} |
201 | |
202 | IncrementalParser::IncrementalParser(Interpreter &Interp, |
203 | std::unique_ptr<CompilerInstance> Instance, |
204 | llvm::LLVMContext &LLVMCtx, |
205 | llvm::Error &Err) |
206 | : CI(std::move(Instance)) { |
207 | llvm::ErrorAsOutParameter EAO(&Err); |
208 | Act = std::make_unique<IncrementalAction>(args&: *CI, args&: LLVMCtx, args&: Err); |
209 | if (Err) |
210 | return; |
211 | CI->ExecuteAction(Act&: *Act); |
212 | |
213 | if (getCodeGen()) |
214 | CachedInCodeGenModule = GenModule(); |
215 | |
216 | std::unique_ptr<ASTConsumer> IncrConsumer = |
217 | std::make_unique<IncrementalASTConsumer>(args&: Interp, args: CI->takeASTConsumer()); |
218 | CI->setASTConsumer(std::move(IncrConsumer)); |
219 | Consumer = &CI->getASTConsumer(); |
220 | P.reset( |
221 | p: new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); |
222 | P->Initialize(); |
223 | |
224 | // An initial PTU is needed as CUDA includes some headers automatically |
225 | auto PTU = ParseOrWrapTopLevelDecl(); |
226 | if (auto E = PTU.takeError()) { |
227 | consumeError(Err: std::move(E)); // FIXME |
228 | return; // PTU.takeError(); |
229 | } |
230 | |
231 | if (getCodeGen()) { |
232 | PTU->TheModule = GenModule(); |
233 | assert(PTU->TheModule && "Failed to create initial PTU" ); |
234 | } |
235 | } |
236 | |
237 | IncrementalParser::~IncrementalParser() { |
238 | P.reset(); |
239 | Act->FinalizeAction(); |
240 | } |
241 | |
242 | llvm::Expected<PartialTranslationUnit &> |
243 | IncrementalParser::ParseOrWrapTopLevelDecl() { |
244 | // Recover resources if we crash before exiting this method. |
245 | Sema &S = CI->getSema(); |
246 | llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); |
247 | Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); |
248 | Sema::LocalEagerInstantiationScope LocalInstantiations(S); |
249 | |
250 | PTUs.emplace_back(args: PartialTranslationUnit()); |
251 | PartialTranslationUnit &LastPTU = PTUs.back(); |
252 | // Add a new PTU. |
253 | ASTContext &C = S.getASTContext(); |
254 | C.addTranslationUnitDecl(); |
255 | LastPTU.TUPart = C.getTranslationUnitDecl(); |
256 | |
257 | // Skip previous eof due to last incremental input. |
258 | if (P->getCurToken().is(K: tok::annot_repl_input_end)) { |
259 | P->ConsumeAnyToken(); |
260 | // FIXME: Clang does not call ExitScope on finalizing the regular TU, we |
261 | // might want to do that around HandleEndOfTranslationUnit. |
262 | P->ExitScope(); |
263 | S.CurContext = nullptr; |
264 | // Start a new PTU. |
265 | P->EnterScope(ScopeFlags: Scope::DeclScope); |
266 | S.ActOnTranslationUnitScope(S: P->getCurScope()); |
267 | } |
268 | |
269 | Parser::DeclGroupPtrTy ADecl; |
270 | Sema::ModuleImportState ImportState; |
271 | for (bool AtEOF = P->ParseFirstTopLevelDecl(Result&: ADecl, ImportState); !AtEOF; |
272 | AtEOF = P->ParseTopLevelDecl(Result&: ADecl, ImportState)) { |
273 | if (ADecl && !Consumer->HandleTopLevelDecl(D: ADecl.get())) |
274 | return llvm::make_error<llvm::StringError>(Args: "Parsing failed. " |
275 | "The consumer rejected a decl" , |
276 | Args: std::error_code()); |
277 | } |
278 | |
279 | DiagnosticsEngine &Diags = getCI()->getDiagnostics(); |
280 | if (Diags.hasErrorOccurred()) { |
281 | PartialTranslationUnit MostRecentPTU = {.TUPart: C.getTranslationUnitDecl(), |
282 | .TheModule: nullptr}; |
283 | CleanUpPTU(PTU&: MostRecentPTU); |
284 | |
285 | Diags.Reset(/*soft=*/true); |
286 | Diags.getClient()->clear(); |
287 | return llvm::make_error<llvm::StringError>(Args: "Parsing failed." , |
288 | Args: std::error_code()); |
289 | } |
290 | |
291 | // Process any TopLevelDecls generated by #pragma weak. |
292 | for (Decl *D : S.WeakTopLevelDecls()) { |
293 | DeclGroupRef DGR(D); |
294 | Consumer->HandleTopLevelDecl(D: DGR); |
295 | } |
296 | |
297 | LocalInstantiations.perform(); |
298 | GlobalInstantiations.perform(); |
299 | |
300 | Consumer->HandleTranslationUnit(Ctx&: C); |
301 | |
302 | return LastPTU; |
303 | } |
304 | |
305 | llvm::Expected<PartialTranslationUnit &> |
306 | IncrementalParser::Parse(llvm::StringRef input) { |
307 | Preprocessor &PP = CI->getPreprocessor(); |
308 | assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?" ); |
309 | |
310 | std::ostringstream SourceName; |
311 | SourceName << "input_line_" << InputCount++; |
312 | |
313 | // Create an uninitialized memory buffer, copy code in and append "\n" |
314 | size_t InputSize = input.size(); // don't include trailing 0 |
315 | // MemBuffer size should *not* include terminating zero |
316 | std::unique_ptr<llvm::MemoryBuffer> MB( |
317 | llvm::WritableMemoryBuffer::getNewUninitMemBuffer(Size: InputSize + 1, |
318 | BufferName: SourceName.str())); |
319 | char *MBStart = const_cast<char *>(MB->getBufferStart()); |
320 | memcpy(dest: MBStart, src: input.data(), n: InputSize); |
321 | MBStart[InputSize] = '\n'; |
322 | |
323 | SourceManager &SM = CI->getSourceManager(); |
324 | |
325 | // FIXME: Create SourceLocation, which will allow clang to order the overload |
326 | // candidates for example |
327 | SourceLocation NewLoc = SM.getLocForStartOfFile(FID: SM.getMainFileID()); |
328 | |
329 | // Create FileID for the current buffer. |
330 | FileID FID = SM.createFileID(Buffer: std::move(MB), FileCharacter: SrcMgr::C_User, /*LoadedID=*/0, |
331 | /*LoadedOffset=*/0, IncludeLoc: NewLoc); |
332 | |
333 | // NewLoc only used for diags. |
334 | if (PP.EnterSourceFile(FID, /*DirLookup=*/Dir: nullptr, Loc: NewLoc)) |
335 | return llvm::make_error<llvm::StringError>(Args: "Parsing failed. " |
336 | "Cannot enter source file." , |
337 | Args: std::error_code()); |
338 | |
339 | auto PTU = ParseOrWrapTopLevelDecl(); |
340 | if (!PTU) |
341 | return PTU.takeError(); |
342 | |
343 | if (PP.getLangOpts().DelayedTemplateParsing) { |
344 | // Microsoft-specific: |
345 | // Late parsed templates can leave unswallowed "macro"-like tokens. |
346 | // They will seriously confuse the Parser when entering the next |
347 | // source file. So lex until we are EOF. |
348 | Token Tok; |
349 | do { |
350 | PP.Lex(Result&: Tok); |
351 | } while (Tok.isNot(K: tok::annot_repl_input_end)); |
352 | } else { |
353 | Token AssertTok; |
354 | PP.Lex(Result&: AssertTok); |
355 | assert(AssertTok.is(tok::annot_repl_input_end) && |
356 | "Lexer must be EOF when starting incremental parse!" ); |
357 | } |
358 | |
359 | if (std::unique_ptr<llvm::Module> M = GenModule()) |
360 | PTU->TheModule = std::move(M); |
361 | |
362 | return PTU; |
363 | } |
364 | |
365 | std::unique_ptr<llvm::Module> IncrementalParser::GenModule() { |
366 | static unsigned ID = 0; |
367 | if (CodeGenerator *CG = getCodeGen()) { |
368 | // Clang's CodeGen is designed to work with a single llvm::Module. In many |
369 | // cases for convenience various CodeGen parts have a reference to the |
370 | // llvm::Module (TheModule or Module) which does not change when a new |
371 | // module is pushed. However, the execution engine wants to take ownership |
372 | // of the module which does not map well to CodeGen's design. To work this |
373 | // around we created an empty module to make CodeGen happy. We should make |
374 | // sure it always stays empty. |
375 | assert((!CachedInCodeGenModule || |
376 | (CachedInCodeGenModule->empty() && |
377 | CachedInCodeGenModule->global_empty() && |
378 | CachedInCodeGenModule->alias_empty() && |
379 | CachedInCodeGenModule->ifunc_empty())) && |
380 | "CodeGen wrote to a readonly module" ); |
381 | std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); |
382 | CG->StartModule(ModuleName: "incr_module_" + std::to_string(val: ID++), C&: M->getContext()); |
383 | return M; |
384 | } |
385 | return nullptr; |
386 | } |
387 | |
388 | void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { |
389 | TranslationUnitDecl *MostRecentTU = PTU.TUPart; |
390 | if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) { |
391 | for (auto &&[Key, List] : *Map) { |
392 | DeclContextLookupResult R = List.getLookupResult(); |
393 | std::vector<NamedDecl *> NamedDeclsToRemove; |
394 | bool RemoveAll = true; |
395 | for (NamedDecl *D : R) { |
396 | if (D->getTranslationUnitDecl() == MostRecentTU) |
397 | NamedDeclsToRemove.push_back(x: D); |
398 | else |
399 | RemoveAll = false; |
400 | } |
401 | if (LLVM_LIKELY(RemoveAll)) { |
402 | Map->erase(Val: Key); |
403 | } else { |
404 | for (NamedDecl *D : NamedDeclsToRemove) |
405 | List.remove(D); |
406 | } |
407 | } |
408 | } |
409 | |
410 | // FIXME: We should de-allocate MostRecentTU |
411 | for (Decl *D : MostRecentTU->decls()) { |
412 | auto *ND = dyn_cast<NamedDecl>(Val: D); |
413 | if (!ND) |
414 | continue; |
415 | // Check if we need to clean up the IdResolver chain. |
416 | if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC && |
417 | !D->getLangOpts().CPlusPlus) |
418 | getCI()->getSema().IdResolver.RemoveDecl(D: ND); |
419 | } |
420 | } |
421 | |
422 | llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { |
423 | CodeGenerator *CG = getCodeGen(); |
424 | assert(CG); |
425 | return CG->GetMangledName(GD); |
426 | } |
427 | } // end namespace clang |
428 | |