clang 18.0.0git
IncrementalParser.cpp
Go to the documentation of this file.
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
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
32namespace clang {
33
34class IncrementalASTConsumer final : public ASTConsumer {
35 Interpreter &Interp;
36 std::unique_ptr<ASTConsumer> Consumer;
37
38public:
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>(D);
50 TSD && TSD->isSemiMissing())
51 TSD->setStmt(Interp.SynthesizeExpr(cast<Expr>(TSD->getStmt())));
52
53 return Consumer->HandleTopLevelDecl(DGR);
54 }
55 void HandleTranslationUnit(ASTContext &Ctx) override final {
56 Consumer->HandleTranslationUnit(Ctx);
57 }
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 }
71 Consumer->HandleCXXImplicitFunctionInstantiation(D);
72 }
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(VarDecl *D) override final {
83 Consumer->CompleteExternalDeclaration(D);
84 }
85 void AssignInheritanceModel(CXXRecordDecl *RD) override final {
86 Consumer->AssignInheritanceModel(RD);
87 }
89 Consumer->HandleCXXStaticMemberVarInstantiation(D);
90 }
91 void HandleVTable(CXXRecordDecl *RD) override final {
92 Consumer->HandleVTable(RD);
93 }
95 return Consumer->GetASTMutationListener();
96 }
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///
117private:
118 bool IsTerminating = false;
119
120public:
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 std::errc::state_not_recoverable,
130 "Driver initialization failed. "
131 "Incremental mode for action %d is not supported",
133 return Act;
135 [[fallthrough]];
137 [[fallthrough]];
139 Act = CreateFrontendAction(CI);
140 break;
142 [[fallthrough]];
144 [[fallthrough]];
145 case frontend::EmitBC:
146 [[fallthrough]];
148 [[fallthrough]];
150 [[fallthrough]];
152 Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
153 break;
154 }
155 return Act;
156 }()) {}
157 FrontendAction *getWrapped() const { return WrappedAction.get(); }
159 return TU_Incremental;
160 }
161
162 void ExecuteAction() override {
164 assert(CI.hasPreprocessor() && "No PP!");
165
166 // Use a code completion consumer?
167 CodeCompleteConsumer *CompletionConsumer = nullptr;
169 CompletionConsumer = &CI.getCodeCompletionConsumer();
170
171 Preprocessor &PP = CI.getPreprocessor();
173
174 if (!CI.hasSema())
175 CI.createSema(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())
184 }
185
187 assert(!IsTerminating && "Already finalized!");
188 IsTerminating = true;
190 }
191};
192
194 FrontendAction *WrappedAct = Act->getWrapped();
195 if (!WrappedAct->hasIRSupport())
196 return nullptr;
197 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
198}
199
201
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>(*CI, LLVMCtx, Err);
209 if (Err)
210 return;
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();
216 P.reset(
217 new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
218 P->Initialize();
219
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();
225 }
226
227 if (CodeGenerator *CG = getCodeGen()) {
228 std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
229 CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
230 M->getContext());
231 PTU->TheModule = std::move(M);
232 assert(PTU->TheModule && "Failed to create initial PTU");
233 }
234}
235
237 P.reset();
238 Act->FinalizeAction();
239}
240
242IncrementalParser::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);
248
249 PTUs.emplace_back(PartialTranslationUnit());
250 PartialTranslationUnit &LastPTU = PTUs.back();
251 // Add a new PTU.
252 ASTContext &C = S.getASTContext();
253 C.addTranslationUnitDecl();
254 LastPTU.TUPart = C.getTranslationUnitDecl();
255
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.
261 P->ExitScope();
262 S.CurContext = nullptr;
263 // Start a new PTU.
264 P->EnterScope(Scope::DeclScope);
265 S.ActOnTranslationUnitScope(P->getCurScope());
266 }
267
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",
275 std::error_code());
276 }
277
278 DiagnosticsEngine &Diags = getCI()->getDiagnostics();
279 if (Diags.hasErrorOccurred()) {
280 PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
281 nullptr};
282 CleanUpPTU(MostRecentPTU);
283
284 Diags.Reset(/*soft=*/true);
285 Diags.getClient()->clear();
286 return llvm::make_error<llvm::StringError>("Parsing failed.",
287 std::error_code());
288 }
289
290 // Process any TopLevelDecls generated by #pragma weak.
291 for (Decl *D : S.WeakTopLevelDecls()) {
292 DeclGroupRef DGR(D);
294 }
295
296 LocalInstantiations.perform();
297 GlobalInstantiations.perform();
298
300
301 return LastPTU;
302}
303
305IncrementalParser::Parse(llvm::StringRef input) {
306 Preprocessor &PP = CI->getPreprocessor();
307 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
308
309 std::ostringstream SourceName;
310 SourceName << "input_line_" << InputCount++;
311
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,
317 SourceName.str()));
318 char *MBStart = const_cast<char *>(MB->getBufferStart());
319 memcpy(MBStart, input.data(), InputSize);
320 MBStart[InputSize] = '\n';
321
322 SourceManager &SM = CI->getSourceManager();
323
324 // FIXME: Create SourceLocation, which will allow clang to order the overload
325 // candidates for example
326 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
327
328 // Create FileID for the current buffer.
329 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
330 /*LoadedOffset=*/0, NewLoc);
331
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.",
336 std::error_code());
337
338 auto PTU = ParseOrWrapTopLevelDecl();
339 if (!PTU)
340 return PTU.takeError();
341
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.
347 Token Tok;
348 do {
349 PP.Lex(Tok);
350 } while (Tok.isNot(tok::annot_repl_input_end));
351 } else {
352 Token AssertTok;
353 PP.Lex(AssertTok);
354 assert(AssertTok.is(tok::annot_repl_input_end) &&
355 "Lexer must be EOF when starting incremental parse!");
356 }
357
358 if (std::unique_ptr<llvm::Module> M = GenModule())
359 PTU->TheModule = std::move(M);
360
361 return PTU;
362}
363
364std::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());
369 return M;
370 }
371 return nullptr;
372}
373
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) {
383 List.remove(D);
384 }
385 }
386 if (List.isNull())
387 Map->erase(I);
388 }
389 }
390}
391
394 assert(CG);
395 return CG->GetMangledName(GD);
396}
397} // end namespace clang
static char ID
Definition: Arena.cpp:183
#define SM(sm)
Definition: Cuda.cpp:80
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: ASTConsumer.h:66
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Definition: ASTConsumer.cpp:18
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
An abstract interface that should be implemented by listeners that want to be notified when an AST en...
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
Abstract interface for a consumer of code-completion information.
The primary public interface to the Clang code generator.
Definition: ModuleBuilder.h:48
llvm::StringRef GetMangledName(GlobalDecl GD)
Given a global declaration, return a mangled name for this declaration which has been added to this c...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
bool hasCodeCompletionConsumer() const
CodeCompleteConsumer & getCodeCompletionConsumer() const
void createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer)
Create the Sema object to be used for parsing.
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1368
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1368
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition: DeclBase.h:2628
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Abstract base class for actions which can be performed by the frontend.
virtual bool hasIRSupport() const
Does this action support use with IR files?
CompilerInstance & getCompilerInstance() const
frontend::ActionKind ProgramAction
The frontend action to perform.
Represents a function declaration or definition.
Definition: Decl.h:1957
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:56
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4768
bool shouldSkipFunctionBody(Decl *D) override final
This callback is called for each function if the Parser was initialized with SkipFunctionBodies set t...
void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final
HandleCXXStaticMemberVarInstantiation - Tell the consumer that this.
void AssignInheritanceModel(CXXRecordDecl *RD) override final
Callback invoked when an MSInheritanceAttr has been attached to a CXXRecordDecl.
ASTDeserializationListener * GetASTDeserializationListener() override final
If the consumer is interested in entities being deserialized from AST files, it should return a point...
IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr< ASTConsumer > C)
void HandleVTable(CXXRecordDecl *RD) override final
Callback involved at the end of a translation unit to notify the consumer that a vtable for the given...
void CompleteExternalDeclaration(VarDecl *D) override final
CompleteExternalDeclaration - Callback invoked at the end of a translation unit to notify the consume...
void HandleTagDeclDefinition(TagDecl *D) override final
HandleTagDeclDefinition - This callback is invoked each time a TagDecl (e.g.
void HandleInterestingDecl(DeclGroupRef D) override final
HandleInterestingDecl - Handle the specified interesting declaration.
void HandleImplicitImportDecl(ImportDecl *D) override final
Handle an ImportDecl that was implicitly created due to an inclusion directive.
ASTMutationListener * GetASTMutationListener() override final
If the consumer is interested in entities getting modified after their initial creation,...
bool HandleTopLevelDecl(DeclGroupRef DGR) override final
HandleTopLevelDecl - Handle the specified top-level declaration.
void PrintStats() override final
PrintStats - If desired, print any statistics.
static bool classof(const clang::ASTConsumer *)
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final
Invoked when a function is implicitly instantiated.
void HandleInlineFunctionDefinition(FunctionDecl *D) override final
This callback is invoked each time an inline (method or friend) function definition in a class is com...
void HandleTagDeclRequiredDefinition(const TagDecl *D) override final
This callback is invoked the first time each TagDecl is required to be complete.
void CompleteTentativeDefinition(VarDecl *D) override final
CompleteTentativeDefinition - Callback invoked at the end of a translation unit to notify the consume...
void HandleTranslationUnit(ASTContext &Ctx) override final
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final
Handle the specified top-level declaration that occurred inside and ObjC container.
A custom action enabling the incremental processing functionality.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
TranslationUnitKind getTranslationUnitKind() override
For AST-based actions, the kind of translation unit we're handling.
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, llvm::Error &Err)
FrontendAction * getWrapped() const
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
std::list< PartialTranslationUnit > PTUs
List containing every information about every incrementally parsed piece of code.
llvm::StringRef GetMangledName(GlobalDecl GD) const
Uses the CodeGenModule mangled name cache and avoids recomputing.
std::unique_ptr< IncrementalAction > Act
Long-lived, incremental parsing action.
virtual llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Input)
Parses incremental input by creating an in-memory file.
CompilerInstance * getCI()
std::unique_ptr< CompilerInstance > CI
Compiler instance performing the incremental compilation.
void CleanUpPTU(PartialTranslationUnit &PTU)
unsigned InputCount
Counts the number of direct user input lines that have been parsed.
std::unique_ptr< llvm::Module > GenModule()
std::unique_ptr< Parser > P
Parser.
ASTConsumer * Consumer
Consumer to process the produced top level decls. Owned by Act.
CodeGenerator * getCodeGen() const
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:76
This represents a decl that may have a name.
Definition: Decl.h:248
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:53
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:458
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
bool isIncrementalProcessingEnabled() const
Returns true if incremental processing is enabled.
void Lex(Token &Result)
Lex the next token for this preprocessor.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.
const LangOptions & getLangOpts() const
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
Definition: Redeclarable.h:216
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:60
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:357
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition: Sema.h:3199
Encodes a location in the source.
This class handles loading and caching of source files into memory.
An array of decls optimized for the common case of only containing one entry.
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3533
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition: Token.h:98
bool isNot(tok::TokenKind K) const
Definition: Token.h:99
The top declaration context.
Definition: Decl.h:83
Represents a variable declaration or definition.
Definition: Decl.h:916
A frontend action which simply wraps some other runtime-specified frontend action.
std::unique_ptr< FrontendAction > WrappedAction
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
@ PrintPreprocessedInput
-E mode.
@ ParseSyntaxOnly
Parse and perform semantic analysis.
@ EmitBC
Emit a .bc file.
@ PluginAction
Run a plugin action,.
@ EmitObj
Emit a .o file.
@ ASTPrint
Parse ASTs and print them.
@ ASTDump
Parse ASTs and dump them.
@ EmitAssembly
Emit a .s file.
@ EmitLLVMOnly
Generate LLVM IR, but do not emit anything.
std::unique_ptr< FrontendAction > CreateFrontendAction(CompilerInstance &CI)
Construct the FrontendAction of a compiler invocation based on the options specified for the compiler...
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:941
@ TU_Incremental
The translation unit is a is a complete translation unit that we might incrementally extend later.
Definition: LangOptions.h:954
@ List
New-expression has a C++11 list-initializer.
Definition: Format.h:5226
The class keeps track of various objects created as part of processing incremental inputs.