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/CodeGen/BackendUtil.h" 16#include "clang/CodeGen/CodeGenAction.h" 17#include "clang/CodeGen/ModuleBuilder.h" 18#include "clang/Frontend/CompilerInstance.h" 19#include "clang/Frontend/FrontendAction.h" 20#include "clang/FrontendTool/Utils.h" 21#include "clang/Parse/Parser.h" 22#include "clang/Sema/Sema.h" 23 24#include "llvm/Option/ArgList.h" 25#include "llvm/Support/CrashRecoveryContext.h" 26#include "llvm/Support/Error.h" 27#include "llvm/Support/Timer.h" 28 29#include <sstream> 30 31namespace clang { 32 33/// A custom action enabling the incremental processing functionality. 34/// 35/// The usual \p FrontendAction expects one call to ExecuteAction and once it 36/// sees a call to \p EndSourceFile it deletes some of the important objects 37/// such as \p Preprocessor and \p Sema assuming no further input will come. 38/// 39/// \p IncrementalAction ensures it keep its underlying action's objects alive 40/// as long as the \p IncrementalParser needs them. 41/// 42class IncrementalAction : public WrapperFrontendAction { 43private: 44 bool IsTerminating = false; 45 46public: 47 IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, 48 llvm::Error &Err) 49 : WrapperFrontendAction([&]() { 50 llvm::ErrorAsOutParameter EAO(&Err); 51 std::unique_ptr<FrontendAction> Act; 52 switch (CI.getFrontendOpts().ProgramAction) { 53 default: 54 Err = llvm::createStringError( 55 std::errc::state_not_recoverable, 56 "Driver initialization failed. " 57 "Incremental mode for action %d is not supported", 58 CI.getFrontendOpts().ProgramAction); 59 return Act; 60 case frontend::ASTDump: 61 LLVM_FALLTHROUGH; 62 case frontend::ASTPrint: 63 LLVM_FALLTHROUGH; 64 case frontend::ParseSyntaxOnly: 65 Act = CreateFrontendAction(CI); 66 break; 67 case frontend::EmitAssembly: 68 LLVM_FALLTHROUGH; 69 case frontend::EmitObj: 70 LLVM_FALLTHROUGH; 71 case frontend::EmitLLVMOnly: 72 Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); 73 break; 74 } 75 return Act; 76 }()) {} 77 FrontendAction *getWrapped() const { return WrappedAction.get(); } 78 void ExecuteAction() override { 79 CompilerInstance &CI = getCompilerInstance(); 80 assert(CI.hasPreprocessor() && "No PP!"); 81 82 // FIXME: Move the truncation aspect of this into Sema, we delayed this till 83 // here so the source manager would be initialized. 84 if (hasCodeCompletionSupport() && 85 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 86 CI.createCodeCompletionConsumer(); 87 88 // Use a code completion consumer? 89 CodeCompleteConsumer *CompletionConsumer = nullptr; 90 if (CI.hasCodeCompletionConsumer()) 91 CompletionConsumer = &CI.getCodeCompletionConsumer(); 92 93 Preprocessor &PP = CI.getPreprocessor(); 94 PP.enableIncrementalProcessing(); 95 PP.EnterMainSourceFile(); 96 97 if (!CI.hasSema()) 98 CI.createSema(getTranslationUnitKind(), CompletionConsumer); 99 } 100 101 // Do not terminate after processing the input. This allows us to keep various 102 // clang objects alive and to incrementally grow the current TU. 103 void EndSourceFile() override { 104 // The WrappedAction can be nullptr if we issued an error in the ctor. 105 if (IsTerminating && getWrapped()) 106 WrapperFrontendAction::EndSourceFile(); 107 } 108 109 void FinalizeAction() { 110 assert(!IsTerminating && "Already finalized!"); 111 IsTerminating = true; 112 EndSourceFile(); 113 } 114}; 115 116IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance, 117 llvm::LLVMContext &LLVMCtx, 118 llvm::Error &Err) 119 : CI(std::move(Instance)) { 120 llvm::ErrorAsOutParameter EAO(&Err); 121 Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err); 122 if (Err) 123 return; 124 CI->ExecuteAction(*Act); 125 Consumer = &CI->getASTConsumer(); 126 P.reset( 127 new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); 128 P->Initialize(); 129} 130 131IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); } 132 133llvm::Expected<Transaction &> IncrementalParser::ParseOrWrapTopLevelDecl() { 134 DiagnosticsEngine &Diags = getCI()->getDiagnostics(); 135 136 if (Diags.hasErrorOccurred()) 137 llvm::report_fatal_error("Previous input had errors, " 138 "recovery not yet supported", 139 /*GenCrashDiag=*/false); 140 141 // Recover resources if we crash before exiting this method. 142 Sema &S = CI->getSema(); 143 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 144 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 145 Sema::LocalEagerInstantiationScope LocalInstantiations(S); 146 147 // Skip previous eof due to last incremental input. 148 if (P->getCurToken().is(tok::eof)) 149 P->ConsumeToken(); 150 151 Transactions.emplace_back(Transaction()); 152 Transaction &LastTransaction = Transactions.back(); 153 154 Parser::DeclGroupPtrTy ADecl; 155 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF; 156 AtEOF = P->ParseTopLevelDecl(ADecl)) { 157 // If we got a null return and something *was* parsed, ignore it. This 158 // is due to a top-level semicolon, an action override, or a parse error 159 // skipping something. 160 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 161 return llvm::make_error<llvm::StringError>("Parsing failed. " 162 "The consumer rejected a decl", 163 std::error_code()); 164 LastTransaction.Decls.push_back(ADecl.get()); 165 } 166 167 // Process any TopLevelDecls generated by #pragma weak. 168 for (Decl *D : S.WeakTopLevelDecls()) { 169 DeclGroupRef DGR(D); 170 LastTransaction.Decls.push_back(DGR); 171 Consumer->HandleTopLevelDecl(DGR); 172 } 173 174 LocalInstantiations.perform(); 175 GlobalInstantiations.perform(); 176 177 Consumer->HandleTranslationUnit(S.getASTContext()); 178 179 if (Diags.hasErrorOccurred()) 180 return llvm::make_error<llvm::StringError>("Parsing failed.", 181 std::error_code()); 182 183 return LastTransaction; 184} 185 186static CodeGenerator *getCodeGen(FrontendAction *Act) { 187 IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act); 188 FrontendAction *WrappedAct = IncrAct->getWrapped(); 189 if (!WrappedAct->hasIRSupport()) 190 return nullptr; 191 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); 192} 193 194llvm::Expected<Transaction &> IncrementalParser::Parse(llvm::StringRef input) { 195 Preprocessor &PP = CI->getPreprocessor(); 196 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); 197 198 std::ostringstream SourceName; 199 SourceName << "input_line_" << InputCount++; 200 201 // Create an uninitialized memory buffer, copy code in and append "\n" 202 size_t InputSize = input.size(); // don't include trailing 0 203 // MemBuffer size should *not* include terminating zero 204 std::unique_ptr<llvm::MemoryBuffer> MB( 205 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, 206 SourceName.str())); 207 char *MBStart = const_cast<char *>(MB->getBufferStart()); 208 memcpy(MBStart, input.data(), InputSize); 209 MBStart[InputSize] = '\n'; 210 211 SourceManager &SM = CI->getSourceManager(); 212 213 // FIXME: Create SourceLocation, which will allow clang to order the overload 214 // candidates for example 215 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); 216 217 // Create FileID for the current buffer. 218 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, 219 /*LoadedOffset=*/0, NewLoc); 220 221 // NewLoc only used for diags. 222 if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc)) 223 return llvm::make_error<llvm::StringError>("Parsing failed. " 224 "Cannot enter source file.", 225 std::error_code()); 226 227 auto ErrOrTransaction = ParseOrWrapTopLevelDecl(); 228 if (auto Err = ErrOrTransaction.takeError()) 229 return std::move(Err); 230 231 if (PP.getLangOpts().DelayedTemplateParsing) { 232 // Microsoft-specific: 233 // Late parsed templates can leave unswallowed "macro"-like tokens. 234 // They will seriously confuse the Parser when entering the next 235 // source file. So lex until we are EOF. 236 Token Tok; 237 do { 238 PP.Lex(Tok); 239 } while (Tok.isNot(tok::eof)); 240 } 241 242 Token AssertTok; 243 PP.Lex(AssertTok); 244 assert(AssertTok.is(tok::eof) && 245 "Lexer must be EOF when starting incremental parse!"); 246 247 if (CodeGenerator *CG = getCodeGen(Act.get())) { 248 std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); 249 CG->StartModule("incr_module_" + std::to_string(Transactions.size()), 250 M->getContext()); 251 252 ErrOrTransaction->TheModule = std::move(M); 253 } 254 255 return ErrOrTransaction; 256} 257} // end namespace clang 258