//------------------------------------------------------------------------------ // CLING - the C++ LLVM-based InterpreterG :) // author: Axel Naumann // // This file is dual-licensed: you can choose to license it under the University // of Illinois Open Source License or the GNU Lesser General Public License. See // LICENSE.TXT for details. //------------------------------------------------------------------------------ #include "IncrementalParser.h" #include "AutoSynthesizer.h" #include "CheckEmptyTransactionTransformer.h" #include "DeclCollector.h" #include "DeclExtractor.h" #include "DynamicLookup.h" #include "IncrementalExecutor.h" #include "NullDerefProtectionTransformer.h" #include "ValueExtractionSynthesizer.h" #include "TransactionPool.h" #include "TransactionUnloader.h" #include "ValuePrinterSynthesizer.h" #include "cling/Interpreter/CIFactory.h" #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/InterpreterCallbacks.h" #include "cling/Interpreter/Transaction.h" #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/FileManager.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Parse/Parser.h" #include "clang/Lex/Preprocessor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_os_ostream.h" #include #include #include // Include the necessary headers to interface with the Windows registry and // environment. #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN #define NOGDI #define NOMINMAX #include #include #define popen _popen #define pclose _pclose #pragma comment(lib, "Advapi32.lib") #endif using namespace clang; namespace { ///\brief Check the compile-time C++ ABI version vs the run-time ABI version, /// a mismatch could cause havoc. Reports if ABI versions differ. static void CheckABICompatibility(clang::CompilerInstance* CI) { #ifdef __GLIBCXX__ # define CLING_CXXABIV __GLIBCXX__ # define CLING_CXXABIS "__GLIBCXX__" #elif _LIBCPP_VERSION # define CLING_CXXABIV _LIBCPP_VERSION # define CLING_CXXABIS "_LIBCPP_VERSION" #elif defined (_MSC_VER) // For MSVC we do not use CLING_CXXABI* #else # define CLING_CXXABIV -1 // intentionally invalid macro name # define CLING_CXXABIS "-1" // intentionally invalid macro name llvm::errs() << "Warning in cling::CIFactory::createCI():\n " "C++ ABI check not implemented for this standard library\n"; return; #endif #ifdef _MSC_VER HKEY regVS; int VSVersion = (_MSC_VER / 100) - 6; std::stringstream subKey; subKey << "VisualStudio.DTE." << VSVersion << ".0"; if (RegOpenKeyEx(HKEY_CLASSES_ROOT, subKey.str().c_str(), 0, KEY_READ, ®VS) == ERROR_SUCCESS) { RegCloseKey(regVS); } else { llvm::errs() << "Warning in cling::CIFactory::createCI():\n " "Possible C++ standard library mismatch, compiled with Visual Studio v" << VSVersion << ".0,\n" "but this version of Visual Studio was not found in your system's registry.\n"; } #else struct EarlyReturnWarn { bool shouldWarn = true; ~EarlyReturnWarn() { if (shouldWarn) { llvm::errs() << "Warning in cling::IncrementalParser::CheckABICompatibility():\n " "Possible C++ standard library mismatch, compiled with " CLING_CXXABIS " v" << CLING_CXXABIV << " but extraction of runtime standard library version failed.\n"; } } } warnAtReturn; clang::Preprocessor& PP = CI->getPreprocessor(); clang::IdentifierInfo* II = PP.getIdentifierInfo(CLING_CXXABIS); if (!II) return; const clang::DefMacroDirective* MD = llvm::dyn_cast(PP.getMacroDirective(II)); if (!MD) return; const clang::MacroInfo* MI = MD->getMacroInfo(); if (!MI || MI->getNumTokens() != 1) return; const clang::Token& Tok = *MI->tokens_begin(); if (!Tok.isLiteral()) return; if (!Tok.getLength() || !Tok.getLiteralData()) return; std::string cxxabivStr; { llvm::raw_string_ostream cxxabivStrStrm(cxxabivStr); cxxabivStrStrm << CLING_CXXABIV; } llvm::StringRef tokStr(Tok.getLiteralData(), Tok.getLength()); warnAtReturn.shouldWarn = false; if (!tokStr.equals(cxxabivStr)) { llvm::errs() << "Warning in cling::IncrementalParser::CheckABICompatibility():\n " "C++ ABI mismatch, compiled with " CLING_CXXABIS " v" << CLING_CXXABIV << " running with v" << tokStr << "\n"; } #endif #undef CLING_CXXABIV #undef CLING_CXXABIS } } // unnamed namespace namespace cling { IncrementalParser::IncrementalParser(Interpreter* interp, int argc, const char* const *argv, const char* llvmdir): m_Interpreter(interp), m_Consumer(0), m_ModuleNo(0) { CompilerInstance* CI = CIFactory::createCI("", argc, argv, llvmdir); assert(CI && "CompilerInstance is (null)!"); m_Consumer = dyn_cast(&CI->getSema().getASTConsumer()); assert(m_Consumer && "Expected ChainedConsumer!"); m_CI.reset(CI); if (CI->getFrontendOpts().ProgramAction != clang::frontend::ParseSyntaxOnly){ m_CodeGen.reset(CreateLLVMCodeGen(CI->getDiagnostics(), "cling-module-0", CI->getCodeGenOpts(), CI->getTargetOpts(), *m_Interpreter->getLLVMContext() )); } initializeVirtualFile(); // Add transformers to the IncrementalParser, which owns them Sema* TheSema = &CI->getSema(); // Register the AST Transformers m_ASTTransformers.push_back(new AutoSynthesizer(TheSema)); m_ASTTransformers.push_back(new EvaluateTSynthesizer(TheSema)); m_ASTTransformers.push_back(new ValuePrinterSynthesizer(TheSema, 0)); m_ASTTransformers.push_back(new DeclExtractor(TheSema)); m_ASTTransformers.push_back(new ValueExtractionSynthesizer(TheSema)); m_ASTTransformers.push_back(new NullDerefProtectionTransformer(TheSema)); m_ASTTransformers.push_back(new CheckEmptyTransactionTransformer(TheSema)); } void IncrementalParser::Initialize(llvm::SmallVectorImpl &result) { m_TransactionPool.reset(new TransactionPool(getCI()->getSema())); if (hasCodeGenerator()) getCodeGenerator()->Initialize(getCI()->getASTContext()); CompilationOptions CO; CO.DeclarationExtraction = 0; CO.ValuePrinting = CompilationOptions::VPDisabled; CO.CodeGeneration = hasCodeGenerator(); // pull in PCHs const std::string& PCHFileName = m_CI->getInvocation ().getPreprocessorOpts().ImplicitPCHInclude; if (!PCHFileName.empty()) { Transaction* CurT = beginTransaction(CO); m_CI->createPCHExternalASTSource(PCHFileName, true /*DisablePCHValidation*/, true /*AllowPCHWithCompilerErrors*/, 0 /*DeserializationListener*/, true /*OwnsDeserializationListener*/); if (Transaction* EndedT = endTransaction(CurT)) result.push_back(EndedT); } Transaction* CurT = beginTransaction(CO); Sema* TheSema = &m_CI->getSema(); m_Parser.reset(new Parser(m_CI->getPreprocessor(), *TheSema, false /*skipFuncBodies*/)); m_CI->getPreprocessor().EnterMainSourceFile(); // Initialize the parser after we have entered the main source file. m_Parser->Initialize(); // Perform initialization that occurs after the parser has been initialized // but before it parses anything. Initializes the consumers too. // No - already done by m_Parser->Initialize(). // TheSema->Initialize(); ExternalASTSource *External = TheSema->getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(m_Consumer); // is needed by the ValuePrinter so it's a good thing to include it. // We need to include it to determine the version number of the standard // library implementation. ParseInternal("#include "); CheckABICompatibility(m_CI.get()); // DO NOT commit the transactions here: static initialization in these // transactions requires gCling through local_cxa_atexit(), but that has not // been defined yet! if (Transaction* EndedT = endTransaction(CurT)) result.push_back(EndedT); } const Transaction* IncrementalParser::getCurrentTransaction() const { return m_Consumer->getTransaction(); } SourceLocation IncrementalParser::getLastMemoryBufferEndLoc() const { const SourceManager& SM = getCI()->getSourceManager(); SourceLocation Result = SM.getLocForStartOfFile(m_VirtualFileID); return Result.getLocWithOffset(m_MemoryBuffers.size() + 1); } IncrementalParser::~IncrementalParser() { const Transaction* T = getFirstTransaction(); const Transaction* nextT = 0; while (T) { assert((T->getState() == Transaction::kCommitted || T->getState() == Transaction::kRolledBackWithErrors || T->getState() == Transaction::kNumStates // reset from the pool || T->getState() == Transaction::kRolledBack) && "Not committed?"); nextT = T->getNext(); delete T; T = nextT; } for (size_t i = 0; i < m_ASTTransformers.size(); ++i) delete m_ASTTransformers[i]; for (size_t i = 0; i < m_IRTransformers.size(); ++i) delete m_IRTransformers[i]; } Transaction* IncrementalParser::beginTransaction(const CompilationOptions& Opts) { Transaction* OldCurT = m_Consumer->getTransaction(); Transaction* NewCurT = m_TransactionPool->takeTransaction(); NewCurT->setCompilationOpts(Opts); // If we are in the middle of transaction and we see another begin // transaction - it must be nested transaction. if (OldCurT && OldCurT != NewCurT && (OldCurT->getState() == Transaction::kCollecting || OldCurT->getState() == Transaction::kCompleted)) { OldCurT->addNestedTransaction(NewCurT); // takes the ownership } m_Consumer->setTransaction(NewCurT); return NewCurT; } Transaction* IncrementalParser::endTransaction(Transaction* T) { assert(T && "Null transaction!?"); assert(T->getState() == Transaction::kCollecting); #ifndef NDEBUG if (T->hasNestedTransactions()) { for(Transaction::const_nested_iterator I = T->nested_begin(), E = T->nested_end(); I != E; ++I) assert((*I)->isCompleted() && "Nested transaction not completed!?"); } #endif T->setState(Transaction::kCompleted); // Empty transaction send it back to the pool. if (T->empty()) { assert((!m_Consumer->getTransaction() || (m_Consumer->getTransaction() == T)) && "Cannot release different T"); // If a nested transaction the active one should be its parent // from now on. FIXME: Merge conditional with commitTransaction if (T->isNestedTransaction()) m_Consumer->setTransaction(T->getParent()); else m_Consumer->setTransaction((Transaction*)0); m_TransactionPool->releaseTransaction(T); return 0; } transformTransactionAST(T); if (T->empty()) { m_TransactionPool->releaseTransaction(T); return 0; } const DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics(); //TODO: Make the enum orable. if (Diags.getNumWarnings() > 0) T->setIssuedDiags(Transaction::kWarnings); if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) T->setIssuedDiags(Transaction::kErrors); if (!T->isNestedTransaction() && T != getLastTransaction()) { if (getLastTransaction()) m_Transactions.back()->setNext(T); m_Transactions.push_back(T); } return T; } void IncrementalParser::commitTransaction(Transaction* T) { //Transaction* CurT = m_Consumer->getTransaction(); assert(T->isCompleted() && "Transaction not ended!?"); assert(T->getState() != Transaction::kCommitted && "Committing an already committed transaction."); assert(!T->empty() && "Transactions must not be empty;"); // If committing a nested transaction the active one should be its parent // from now on. if (T->isNestedTransaction()) m_Consumer->setTransaction(T->getParent()); // Check for errors... if (T->getIssuedDiags() == Transaction::kErrors) { rollbackTransaction(T); return; } if (T->hasNestedTransactions()) { for (Transaction::const_nested_iterator I = T->nested_begin(), E = T->nested_end(); I != E; ++I) if ((*I)->getState() != Transaction::kCommitted) commitTransaction(*I); } // If there was an error coming from the transformers. if (T->getIssuedDiags() == Transaction::kErrors) { rollbackTransaction(T); return; } // Here we expect a template instantiation. We need to open the transaction // that we are currently work with. { Transaction* prevConsumerT = m_Consumer->getTransaction(); m_Consumer->setTransaction(T); Transaction* nestedT = beginTransaction(CompilationOptions()); // Pull all template instantiations in that came from the consumers. getCI()->getSema().PerformPendingInstantiations(); if (Transaction* T = endTransaction(nestedT)) commitTransaction(T); m_Consumer->setTransaction(prevConsumerT); } m_Consumer->HandleTranslationUnit(getCI()->getASTContext()); // The static initializers might run anything and can thus cause more // decls that need to end up in a transaction. But this one is done // with CodeGen... if (T->getCompilationOpts().CodeGeneration && hasCodeGenerator()) { Transaction* prevConsumerT = m_Consumer->getTransaction(); m_Consumer->setTransaction(T); codeGenTransaction(T); transformTransactionIR(T); T->setState(Transaction::kCommitted); if (!T->getParent()) { if (m_Interpreter->runStaticInitializersOnce(*T) >= Interpreter::kExeFirstError) { // Roll back on error in initializers //assert(0 && "Error on inits."); rollbackTransaction(T); T->setState(Transaction::kRolledBackWithErrors); return; } } m_Consumer->setTransaction(prevConsumerT); } T->setState(Transaction::kCommitted); if (InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks()) callbacks->TransactionCommitted(*T); } void IncrementalParser::markWholeTransactionAsUsed(Transaction* T) const { ASTContext& C = m_CI->getASTContext(); for (Transaction::const_iterator I = T->decls_begin(), E = T->decls_end(); I != E; ++I) { // Copy DCI; it might get relocated below. Transaction::DelayCallInfo DCI = *I; // FIXME: implement for multiple decls in a DGR. assert(DCI.m_DGR.isSingleDecl()); Decl* D = DCI.m_DGR.getSingleDecl(); if (!D->hasAttr()) D->addAttr(::new (D->getASTContext()) clang::UsedAttr(D->getSourceRange(), D->getASTContext(), 0/*AttributeSpellingListIndex*/)); } for (Transaction::iterator I = T->deserialized_decls_begin(), E = T->deserialized_decls_end(); I != E; ++I) { // FIXME: implement for multiple decls in a DGR. assert(I->m_DGR.isSingleDecl()); Decl* D = I->m_DGR.getSingleDecl(); if (!D->hasAttr()) D->addAttr(::new (C) clang::UsedAttr(D->getSourceRange(), C, 0/*AttributeSpellingListIndex*/)); } } void IncrementalParser::codeGenTransaction(Transaction* T) { // codegen the transaction assert(T->getCompilationOpts().CodeGeneration && "CodeGen turned off"); assert(T->getState() == Transaction::kCompleted && "Must be completed"); assert(hasCodeGenerator() && "No CodeGen"); T->setModule(getCodeGenerator()->GetModule()); // Could trigger derserialization of decls. Transaction* deserT = beginTransaction(CompilationOptions()); for (Transaction::const_iterator TI = T->decls_begin(), TE = T->decls_end(); TI != TE; ++TI) { // Copy DCI; it might get relocated below. Transaction::DelayCallInfo I = *TI; if (I.m_Call == Transaction::kCCIHandleTopLevelDecl) getCodeGenerator()->HandleTopLevelDecl(I.m_DGR); else if (I.m_Call == Transaction::kCCIHandleInterestingDecl) { // Usually through BackendConsumer which doesn't implement // HandleInterestingDecl() and thus calls // ASTConsumer::HandleInterestingDecl() getCodeGenerator()->HandleTopLevelDecl(I.m_DGR); } else if(I.m_Call == Transaction::kCCIHandleTagDeclDefinition) { TagDecl* TD = cast(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleTagDeclDefinition(TD); } else if (I.m_Call == Transaction::kCCIHandleVTable) { CXXRecordDecl* CXXRD = cast(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleVTable(CXXRD, /*isRequired*/true); } else if (I.m_Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation) { FunctionDecl* FD = cast(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD); } else if (I.m_Call == Transaction::kCCIHandleCXXStaticMemberVarInstantiation) { VarDecl* VD = cast(I.m_DGR.getSingleDecl()); getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD); } else if (I.m_Call == Transaction::kCCICompleteTentativeDefinition) { VarDecl* VD = cast(I.m_DGR.getSingleDecl()); getCodeGenerator()->CompleteTentativeDefinition(VD); } else if (I.m_Call == Transaction::kCCINone) ; // We use that internally as delimiter in the Transaction. else llvm_unreachable("We shouldn't have decl without call info."); } // Treat the deserialized decls differently. for (Transaction::iterator I = T->deserialized_decls_begin(), E = T->deserialized_decls_end(); I != E; ++I) { for (DeclGroupRef::iterator DI = I->m_DGR.begin(), DE = I->m_DGR.end(); DI != DE; ++DI) { DeclGroupRef SplitDGR(*DI); if (I->m_Call == Transaction::kCCIHandleTopLevelDecl) { // FIXME: The special namespace treatment (not sending itself to // CodeGen, but only its content - if the contained decl should be // emitted) works around issue with the static initialization when // having a PCH and loading a library. We don't want to generate // code for the static that will come through the library. // // This will be fixed with the clang::Modules. Make sure we remember. assert(!getCI()->getLangOpts().Modules && "Please revisit!"); if (NamespaceDecl* ND = dyn_cast(*DI)) { for (NamespaceDecl::decl_iterator NDI = ND->decls_begin(), EN = ND->decls_end(); NDI != EN; ++NDI) { // Recurse over decls inside the namespace, like // CodeGenModule::EmitNamespace() does. if (!shouldIgnore(*NDI)) getCodeGenerator()->HandleTopLevelDecl(DeclGroupRef(*NDI)); } } else if (!shouldIgnore(*DI)) { getCodeGenerator()->HandleTopLevelDecl(SplitDGR); } continue; } // HandleTopLevel if (shouldIgnore(*DI)) continue; if (I->m_Call == Transaction::kCCIHandleInterestingDecl) { // Usually through BackendConsumer which doesn't implement // HandleInterestingDecl() and thus calls // ASTConsumer::HandleInterestingDecl() getCodeGenerator()->HandleTopLevelDecl(SplitDGR); } else if(I->m_Call == Transaction::kCCIHandleTagDeclDefinition) { TagDecl* TD = cast(*DI); getCodeGenerator()->HandleTagDeclDefinition(TD); } else if (I->m_Call == Transaction::kCCIHandleVTable) { CXXRecordDecl* CXXRD = cast(*DI); getCodeGenerator()->HandleVTable(CXXRD, /*isRequired*/true); } else if (I->m_Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation) { FunctionDecl* FD = cast(*DI); getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD); } else if (I->m_Call == Transaction::kCCIHandleCXXStaticMemberVarInstantiation) { VarDecl* VD = cast(*DI); getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD); } else if (I->m_Call == Transaction::kCCICompleteTentativeDefinition) { VarDecl* VD = cast(I->m_DGR.getSingleDecl()); getCodeGenerator()->CompleteTentativeDefinition(VD); } else if (I->m_Call == Transaction::kCCINone) ; // We use that internally as delimiter in the Transaction. else llvm_unreachable("We shouldn't have decl without call info."); } // for decls in DGR } // for deserialized DGRs getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext()); // This llvm::Module is done; finalize it and pass it to the execution // engine. if (!T->isNestedTransaction() && hasCodeGenerator()) { std::unique_ptr M(getCodeGenerator()->ReleaseModule()); if (M) { assert(M.get() == T->getModule() && "Transaction has inconsistent module"); m_Interpreter->addModule(std::move(M)); } // Create a new module. std::string ModuleName; { llvm::raw_string_ostream strm(ModuleName); strm << "cling-module-" << ++m_ModuleNo; } getCodeGenerator()->StartModule(ModuleName, *m_Interpreter->getLLVMContext()); } if ((deserT = endTransaction(deserT))) commitTransaction(deserT); } void IncrementalParser::transformTransactionAST(Transaction* T) { bool success = true; // We are sure it's safe to pipe it through the transformers // Consume late transformers init Transaction* initT = beginTransaction(CompilationOptions()); for (size_t i = 0; success && i < m_ASTTransformers.size(); ++i) success = m_ASTTransformers[i]->TransformTransaction(*T); if (endTransaction(initT)) commitTransaction(initT); if (!success) T->setIssuedDiags(Transaction::kErrors); } bool IncrementalParser::transformTransactionIR(Transaction* T) { // Transform IR bool success = true; for (size_t i = 0; success && i < m_IRTransformers.size(); ++i) success = m_IRTransformers[i]->TransformTransaction(*T); if (!success) rollbackTransaction(T); return success; } void IncrementalParser::rollbackTransaction(Transaction* T) { assert(T && "Must have value"); assert(T == getLastTransaction() && "We always must revert the last T"); assert((T->getState() != Transaction::kRolledBack || T->getState() != Transaction::kRolledBackWithErrors) && "Transaction already rolled back."); if (m_Interpreter->getOptions().ErrorOut) return; TransactionUnloader U(&getCI()->getSema(), m_CodeGen.get(), m_Interpreter->getExecutionEngine()); if (U.RevertTransaction(T)) T->setState(Transaction::kRolledBack); else T->setState(Transaction::kRolledBackWithErrors); // Remove from the queue m_Transactions.pop_back(); //m_TransactionPool->releaseTransaction(T); } std::vector IncrementalParser::getAllTransactions() { std::vector result(m_Transactions.size()); const cling::Transaction* T = getFirstTransaction(); while (T) { result.push_back(T); T = T->getNext(); } return result; } // Each input line is contained in separate memory buffer. The SourceManager // assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry // for the MemoryBuffer's FileID. That in turn is problem because invalid // SourceLocations are given to the diagnostics. Thus the diagnostics cannot // order the overloads, for example // // Our work-around is creating a virtual file, which doesn't exist on the disk // with enormous size (no allocation is done). That file has valid FileEntry // and so on... We use it for generating valid SourceLocations with valid // offsets so that it doesn't cause any troubles to the diagnostics. // // +---------------------+ // | Main memory buffer | // +---------------------+ // | Virtual file SLoc | // | address space |<-----------------+ // | ... |<------------+ | // | ... | | | // | ... |<----+ | | // | ... | | | | // +~~~~~~~~~~~~~~~~~~~~~+ | | | // | input_line_1 | ....+.......+..--+ // +---------------------+ | | // | input_line_2 | ....+.....--+ // +---------------------+ | // | ... | | // +---------------------+ | // | input_line_N | ..--+ // +---------------------+ // void IncrementalParser::initializeVirtualFile() { SourceManager& SM = getCI()->getSourceManager(); m_VirtualFileID = SM.getMainFileID(); assert(!m_VirtualFileID.isInvalid() && "No VirtualFileID created?"); } Transaction* IncrementalParser::Compile(llvm::StringRef input, const CompilationOptions& Opts) { Transaction* CurT = beginTransaction(Opts); EParseResult ParseRes = ParseInternal(input); if (ParseRes == kSuccessWithWarnings) CurT->setIssuedDiags(Transaction::kWarnings); else if (ParseRes == kFailed) CurT->setIssuedDiags(Transaction::kErrors); if ((CurT = endTransaction(CurT))) { commitTransaction(CurT); } return CurT; } Transaction* IncrementalParser::Parse(llvm::StringRef input, const CompilationOptions& Opts) { Transaction* CurT = beginTransaction(Opts); ParseInternal(input); Transaction* EndedT = endTransaction(CurT); return EndedT; } // Add the input to the memory buffer, parse it, and add it to the AST. IncrementalParser::EParseResult IncrementalParser::ParseInternal(llvm::StringRef input) { if (input.empty()) return IncrementalParser::kSuccess; Sema& S = getCI()->getSema(); const CompilationOptions& CO = m_Consumer->getTransaction()->getCompilationOpts(); assert(!(S.getLangOpts().Modules && CO.CodeGenerationForModule) && "CodeGenerationForModule to be removed once PCMs are available!"); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CleanupSema(&S); Preprocessor& PP = m_CI->getPreprocessor(); if (!PP.getCurrentLexer()) { PP.EnterSourceFile(m_CI->getSourceManager().getMainFileID(), 0, SourceLocation()); } assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); PP.enableIncrementalProcessing(); std::ostringstream source_name; source_name << "input_line_" << (m_MemoryBuffers.size() + 1); // Create an uninitialized memory buffer, copy code in and append "\n" size_t InputSize = input.size(); // don't include trailing 0 // MemBuffer size should *not* include terminating zero std::unique_ptr MB(llvm::MemoryBuffer::getNewUninitMemBuffer(InputSize + 1, source_name.str())); char* MBStart = const_cast(MB->getBufferStart()); memcpy(MBStart, input.data(), InputSize); memcpy(MBStart + InputSize, "\n", 2); m_MemoryBuffers.push_back(MB.get()); SourceManager& SM = getCI()->getSourceManager(); // Create SourceLocation, which will allow clang to order the overload // candidates for example SourceLocation NewLoc = getLastMemoryBufferEndLoc().getLocWithOffset(1); // Create FileID for the current buffer FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID*/0, /*LoadedOffset*/0, NewLoc); m_MemoryBuffers.push_back(std::make_pair(MB, FID)); PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc); m_Consumer->getTransaction()->setBufferFID(FID); DiagnosticsEngine& Diags = getCI()->getDiagnostics(); bool IgnorePromptDiags = CO.IgnorePromptDiags; if (IgnorePromptDiags) { // Disable warnings which doesn't make sense when using the prompt // This gets reset with the clang::Diagnostics().Reset(/*soft*/=false) // using clang's API we simulate: // #pragma warning push // #pragma warning ignore ... // #pragma warning ignore ... // #pragma warning pop SourceLocation Loc = SM.getLocForStartOfFile(FID); Diags.pushMappings(Loc); // The source locations of #pragma warning ignore must be greater than // the ones from #pragma push auto setIgnore = [&](clang::diag::kind Diag) { Diags.setSeverity(Diag, diag::Severity::Ignored, SourceLocation()); }; setIgnore(clang::diag::warn_unused_expr); setIgnore(clang::diag::warn_unused_call); setIgnore(clang::diag::warn_unused_comparison); setIgnore(clang::diag::ext_return_has_expr); } Sema::SavePendingInstantiationsRAII SavedPendingInstantiations(S); Parser::DeclGroupPtrTy ADecl; while (!m_Parser->ParseTopLevelDecl(ADecl)) { // If we got a null return and something *was* parsed, ignore it. This // is due to a top-level semicolon, an action override, or a parse error // skipping something. if (ADecl) m_Consumer->HandleTopLevelDecl(ADecl.get()); }; if (IgnorePromptDiags) { SourceLocation Loc = SM.getLocForEndOfFile(m_MemoryBuffers.back().second); Diags.popMappings(Loc); } // Process any TopLevelDecls generated by #pragma weak. for (llvm::SmallVector::iterator I = S.WeakTopLevelDecls().begin(), E = S.WeakTopLevelDecls().end(); I != E; ++I) { m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); } if (Diags.hasErrorOccurred()) return IncrementalParser::kFailed; else if (Diags.getNumWarnings()) return IncrementalParser::kSuccessWithWarnings; return IncrementalParser::kSuccess; } void IncrementalParser::printTransactionStructure() const { for(size_t i = 0, e = m_Transactions.size(); i < e; ++i) { m_Transactions[i]->printStructureBrief(); } } bool IncrementalParser::shouldIgnore(const Decl* D) const { // This function is called for all "deserialized" decls, where the // "deserialized" decl either really comes from an AST file or from // a header that's loaded to import the AST for a library with a dictionary // (the non-PCM case). // // Functions that are inlined must be sent to CodeGen - they will not have a // symbol in the library. if (const FunctionDecl* FD = dyn_cast(D)) { if (D->isFromASTFile()) { return !FD->hasBody(); } else { // If the decl must be emitted then it will be in the library. // If not, we must expose it to CodeGen now because it might // not be in the library. Does this correspond to a weak symbol // by definition? return !(FD->isInlined() || FD->isTemplateInstantiation()); } } // Don't codegen statics coming in from a module; they are already part of // the library. // We do need to expose static variables from template instantiations. if (const VarDecl* VD = dyn_cast(D)) if (VD->hasGlobalStorage() && !VD->getType().isConstQualified() && VD->getTemplateSpecializationKind() == TSK_Undeclared) return true; return false; } } // namespace cling