1 //===--------- IncrementalParser.cpp - Incremental Compilation -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the class which performs incremental code compilation.
11 //===----------------------------------------------------------------------===//
13 #include "IncrementalParser.h"
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"
34 class IncrementalASTConsumer final
: public ASTConsumer
{
36 std::unique_ptr
<ASTConsumer
> Consumer
;
39 IncrementalASTConsumer(Interpreter
&InterpRef
, std::unique_ptr
<ASTConsumer
> C
)
40 : Interp(InterpRef
), Consumer(std::move(C
)) {}
42 bool HandleTopLevelDecl(DeclGroupRef DGR
) override final
{
49 if (auto *TSD
= llvm::dyn_cast
<TopLevelStmtDecl
>(D
);
50 TSD
&& TSD
->isSemiMissing())
51 TSD
->setStmt(Interp
.SynthesizeExpr(cast
<Expr
>(TSD
->getStmt())));
53 return Consumer
->HandleTopLevelDecl(DGR
);
55 void HandleTranslationUnit(ASTContext
&Ctx
) override final
{
56 Consumer
->HandleTranslationUnit(Ctx
);
58 void HandleInlineFunctionDefinition(FunctionDecl
*D
) override final
{
59 Consumer
->HandleInlineFunctionDefinition(D
);
61 void HandleInterestingDecl(DeclGroupRef D
) override final
{
62 Consumer
->HandleInterestingDecl(D
);
64 void HandleTagDeclDefinition(TagDecl
*D
) override final
{
65 Consumer
->HandleTagDeclDefinition(D
);
67 void HandleTagDeclRequiredDefinition(const TagDecl
*D
) override final
{
68 Consumer
->HandleTagDeclRequiredDefinition(D
);
70 void HandleCXXImplicitFunctionInstantiation(FunctionDecl
*D
) override final
{
71 Consumer
->HandleCXXImplicitFunctionInstantiation(D
);
73 void HandleTopLevelDeclInObjCContainer(DeclGroupRef D
) override final
{
74 Consumer
->HandleTopLevelDeclInObjCContainer(D
);
76 void HandleImplicitImportDecl(ImportDecl
*D
) override final
{
77 Consumer
->HandleImplicitImportDecl(D
);
79 void CompleteTentativeDefinition(VarDecl
*D
) override final
{
80 Consumer
->CompleteTentativeDefinition(D
);
82 void CompleteExternalDeclaration(VarDecl
*D
) override final
{
83 Consumer
->CompleteExternalDeclaration(D
);
85 void AssignInheritanceModel(CXXRecordDecl
*RD
) override final
{
86 Consumer
->AssignInheritanceModel(RD
);
88 void HandleCXXStaticMemberVarInstantiation(VarDecl
*D
) override final
{
89 Consumer
->HandleCXXStaticMemberVarInstantiation(D
);
91 void HandleVTable(CXXRecordDecl
*RD
) override final
{
92 Consumer
->HandleVTable(RD
);
94 ASTMutationListener
*GetASTMutationListener() override final
{
95 return Consumer
->GetASTMutationListener();
97 ASTDeserializationListener
*GetASTDeserializationListener() override final
{
98 return Consumer
->GetASTDeserializationListener();
100 void PrintStats() override final
{ Consumer
->PrintStats(); }
101 bool shouldSkipFunctionBody(Decl
*D
) override final
{
102 return Consumer
->shouldSkipFunctionBody(D
);
104 static bool classof(const clang::ASTConsumer
*) { return true; }
107 /// A custom action enabling the incremental processing functionality.
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.
113 /// \p IncrementalAction ensures it keep its underlying action's objects alive
114 /// as long as the \p IncrementalParser needs them.
116 class IncrementalAction
: public WrapperFrontendAction
{
118 bool IsTerminating
= false;
121 IncrementalAction(CompilerInstance
&CI
, llvm::LLVMContext
&LLVMCtx
,
123 : WrapperFrontendAction([&]() {
124 llvm::ErrorAsOutParameter
EAO(&Err
);
125 std::unique_ptr
<FrontendAction
> Act
;
126 switch (CI
.getFrontendOpts().ProgramAction
) {
128 Err
= llvm::createStringError(
129 std::errc::state_not_recoverable
,
130 "Driver initialization failed. "
131 "Incremental mode for action %d is not supported",
132 CI
.getFrontendOpts().ProgramAction
);
134 case frontend::ASTDump
:
136 case frontend::ASTPrint
:
138 case frontend::ParseSyntaxOnly
:
139 Act
= CreateFrontendAction(CI
);
141 case frontend::PluginAction
:
143 case frontend::EmitAssembly
:
145 case frontend::EmitBC
:
147 case frontend::EmitObj
:
149 case frontend::PrintPreprocessedInput
:
151 case frontend::EmitLLVMOnly
:
152 Act
.reset(new EmitLLVMOnlyAction(&LLVMCtx
));
157 FrontendAction
*getWrapped() const { return WrappedAction
.get(); }
158 TranslationUnitKind
getTranslationUnitKind() override
{
159 return TU_Incremental
;
162 void ExecuteAction() override
{
163 CompilerInstance
&CI
= getCompilerInstance();
164 assert(CI
.hasPreprocessor() && "No PP!");
166 // Use a code completion consumer?
167 CodeCompleteConsumer
*CompletionConsumer
= nullptr;
168 if (CI
.hasCodeCompletionConsumer())
169 CompletionConsumer
= &CI
.getCodeCompletionConsumer();
171 Preprocessor
&PP
= CI
.getPreprocessor();
172 PP
.EnterMainSourceFile();
175 CI
.createSema(getTranslationUnitKind(), CompletionConsumer
);
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();
186 void FinalizeAction() {
187 assert(!IsTerminating
&& "Already finalized!");
188 IsTerminating
= true;
193 CodeGenerator
*IncrementalParser::getCodeGen() const {
194 FrontendAction
*WrappedAct
= Act
->getWrapped();
195 if (!WrappedAct
->hasIRSupport())
197 return static_cast<CodeGenAction
*>(WrappedAct
)->getCodeGenerator();
200 IncrementalParser::IncrementalParser() {}
202 IncrementalParser::IncrementalParser(Interpreter
&Interp
,
203 std::unique_ptr
<CompilerInstance
> Instance
,
204 llvm::LLVMContext
&LLVMCtx
,
206 : CI(std::move(Instance
)) {
207 llvm::ErrorAsOutParameter
EAO(&Err
);
208 Act
= std::make_unique
<IncrementalAction
>(*CI
, LLVMCtx
, Err
);
211 CI
->ExecuteAction(*Act
);
212 std::unique_ptr
<ASTConsumer
> IncrConsumer
=
213 std::make_unique
<IncrementalASTConsumer
>(Interp
, CI
->takeASTConsumer());
214 CI
->setASTConsumer(std::move(IncrConsumer
));
215 Consumer
= &CI
->getASTConsumer();
217 new Parser(CI
->getPreprocessor(), CI
->getSema(), /*SkipBodies=*/false));
220 // An initial PTU is needed as CUDA includes some headers automatically
221 auto PTU
= ParseOrWrapTopLevelDecl();
222 if (auto E
= PTU
.takeError()) {
223 consumeError(std::move(E
)); // FIXME
224 return; // PTU.takeError();
227 if (CodeGenerator
*CG
= getCodeGen()) {
228 std::unique_ptr
<llvm::Module
> M(CG
->ReleaseModule());
229 CG
->StartModule("incr_module_" + std::to_string(PTUs
.size()),
231 PTU
->TheModule
= std::move(M
);
232 assert(PTU
->TheModule
&& "Failed to create initial PTU");
236 IncrementalParser::~IncrementalParser() {
238 Act
->FinalizeAction();
241 llvm::Expected
<PartialTranslationUnit
&>
242 IncrementalParser::ParseOrWrapTopLevelDecl() {
243 // Recover resources if we crash before exiting this method.
244 Sema
&S
= CI
->getSema();
245 llvm::CrashRecoveryContextCleanupRegistrar
<Sema
> CleanupSema(&S
);
246 Sema::GlobalEagerInstantiationScope
GlobalInstantiations(S
, /*Enabled=*/true);
247 Sema::LocalEagerInstantiationScope
LocalInstantiations(S
);
249 PTUs
.emplace_back(PartialTranslationUnit());
250 PartialTranslationUnit
&LastPTU
= PTUs
.back();
252 ASTContext
&C
= S
.getASTContext();
253 C
.addTranslationUnitDecl();
254 LastPTU
.TUPart
= C
.getTranslationUnitDecl();
256 // Skip previous eof due to last incremental input.
257 if (P
->getCurToken().is(tok::annot_repl_input_end
)) {
258 P
->ConsumeAnyToken();
259 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
260 // might want to do that around HandleEndOfTranslationUnit.
262 S
.CurContext
= nullptr;
264 P
->EnterScope(Scope::DeclScope
);
265 S
.ActOnTranslationUnitScope(P
->getCurScope());
268 Parser::DeclGroupPtrTy ADecl
;
269 Sema::ModuleImportState ImportState
;
270 for (bool AtEOF
= P
->ParseFirstTopLevelDecl(ADecl
, ImportState
); !AtEOF
;
271 AtEOF
= P
->ParseTopLevelDecl(ADecl
, ImportState
)) {
272 if (ADecl
&& !Consumer
->HandleTopLevelDecl(ADecl
.get()))
273 return llvm::make_error
<llvm::StringError
>("Parsing failed. "
274 "The consumer rejected a decl",
278 DiagnosticsEngine
&Diags
= getCI()->getDiagnostics();
279 if (Diags
.hasErrorOccurred()) {
280 PartialTranslationUnit MostRecentPTU
= {C
.getTranslationUnitDecl(),
282 CleanUpPTU(MostRecentPTU
);
284 Diags
.Reset(/*soft=*/true);
285 Diags
.getClient()->clear();
286 return llvm::make_error
<llvm::StringError
>("Parsing failed.",
290 // Process any TopLevelDecls generated by #pragma weak.
291 for (Decl
*D
: S
.WeakTopLevelDecls()) {
293 Consumer
->HandleTopLevelDecl(DGR
);
296 LocalInstantiations
.perform();
297 GlobalInstantiations
.perform();
299 Consumer
->HandleTranslationUnit(C
);
304 llvm::Expected
<PartialTranslationUnit
&>
305 IncrementalParser::Parse(llvm::StringRef input
) {
306 Preprocessor
&PP
= CI
->getPreprocessor();
307 assert(PP
.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
309 std::ostringstream SourceName
;
310 SourceName
<< "input_line_" << InputCount
++;
312 // Create an uninitialized memory buffer, copy code in and append "\n"
313 size_t InputSize
= input
.size(); // don't include trailing 0
314 // MemBuffer size should *not* include terminating zero
315 std::unique_ptr
<llvm::MemoryBuffer
> MB(
316 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize
+ 1,
318 char *MBStart
= const_cast<char *>(MB
->getBufferStart());
319 memcpy(MBStart
, input
.data(), InputSize
);
320 MBStart
[InputSize
] = '\n';
322 SourceManager
&SM
= CI
->getSourceManager();
324 // FIXME: Create SourceLocation, which will allow clang to order the overload
325 // candidates for example
326 SourceLocation NewLoc
= SM
.getLocForStartOfFile(SM
.getMainFileID());
328 // Create FileID for the current buffer.
329 FileID FID
= SM
.createFileID(std::move(MB
), SrcMgr::C_User
, /*LoadedID=*/0,
330 /*LoadedOffset=*/0, NewLoc
);
332 // NewLoc only used for diags.
333 if (PP
.EnterSourceFile(FID
, /*DirLookup=*/nullptr, NewLoc
))
334 return llvm::make_error
<llvm::StringError
>("Parsing failed. "
335 "Cannot enter source file.",
338 auto PTU
= ParseOrWrapTopLevelDecl();
340 return PTU
.takeError();
342 if (PP
.getLangOpts().DelayedTemplateParsing
) {
343 // Microsoft-specific:
344 // Late parsed templates can leave unswallowed "macro"-like tokens.
345 // They will seriously confuse the Parser when entering the next
346 // source file. So lex until we are EOF.
350 } while (Tok
.isNot(tok::annot_repl_input_end
));
354 assert(AssertTok
.is(tok::annot_repl_input_end
) &&
355 "Lexer must be EOF when starting incremental parse!");
358 if (std::unique_ptr
<llvm::Module
> M
= GenModule())
359 PTU
->TheModule
= std::move(M
);
364 std::unique_ptr
<llvm::Module
> IncrementalParser::GenModule() {
365 static unsigned ID
= 0;
366 if (CodeGenerator
*CG
= getCodeGen()) {
367 std::unique_ptr
<llvm::Module
> M(CG
->ReleaseModule());
368 CG
->StartModule("incr_module_" + std::to_string(ID
++), M
->getContext());
374 void IncrementalParser::CleanUpPTU(PartialTranslationUnit
&PTU
) {
375 TranslationUnitDecl
*MostRecentTU
= PTU
.TUPart
;
376 TranslationUnitDecl
*FirstTU
= MostRecentTU
->getFirstDecl();
377 if (StoredDeclsMap
*Map
= FirstTU
->getPrimaryContext()->getLookupPtr()) {
378 for (auto I
= Map
->begin(); I
!= Map
->end(); ++I
) {
379 StoredDeclsList
&List
= I
->second
;
380 DeclContextLookupResult R
= List
.getLookupResult();
381 for (NamedDecl
*D
: R
) {
382 if (D
->getTranslationUnitDecl() == MostRecentTU
) {
392 llvm::StringRef
IncrementalParser::GetMangledName(GlobalDecl GD
) const {
393 CodeGenerator
*CG
= getCodeGen();
395 return CG
->GetMangledName(GD
);
397 } // end namespace clang