diff --git a/interpreter/cling/include/cling/Interpreter/Interpreter.h b/interpreter/cling/include/cling/Interpreter/Interpreter.h index 4ded5c4f7182d..fe9aae303c9d8 100644 --- a/interpreter/cling/include/cling/Interpreter/Interpreter.h +++ b/interpreter/cling/include/cling/Interpreter/Interpreter.h @@ -18,6 +18,7 @@ #include "cling/Interpreter/RuntimeOptions.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" #include #include @@ -178,9 +179,9 @@ namespace cling { /// InvocationOptions m_Opts; - ///\brief The llvm library state, a per-thread object. + ///\brief Thread-safe llvm library state. /// - std::unique_ptr m_LLVMContext; + std::unique_ptr TSCtx; ///\brief Cling's execution engine - a well wrapped llvm execution engine. /// @@ -395,10 +396,10 @@ namespace cling { cling::runtime::RuntimeOptions& getRuntimeOptions() { return m_RuntimeOptions; } const llvm::LLVMContext* getLLVMContext() const { - return m_LLVMContext.get(); + return TSCtx->getContext(); } - llvm::LLVMContext* getLLVMContext() { return m_LLVMContext.get(); } + llvm::LLVMContext* getLLVMContext() { return TSCtx->getContext(); } LookupHelper& getLookupHelper() const { return *m_LookupHelper; } diff --git a/interpreter/cling/lib/Interpreter/IncrementalParser.cpp b/interpreter/cling/lib/Interpreter/IncrementalParser.cpp index 83f8b961c1f85..7a522bd1b5499 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +++ b/interpreter/cling/lib/Interpreter/IncrementalParser.cpp @@ -873,7 +873,8 @@ namespace cling { PP.enableIncrementalProcessing(); smallstream source_name; - source_name << "input_line_" << (m_MemoryBuffers.size() + 1); + // FIXME: Pre-increment to avoid failing tests. + source_name << "input_line_" << ++InputCount; // Create an uninitialized memory buffer, copy code in and append "\n" size_t InputSize = input.size(); // don't include trailing 0 @@ -891,8 +892,6 @@ namespace cling { // candidates for example SourceLocation NewLoc = getNextAvailableUniqueSourceLoc(); - llvm::MemoryBuffer* MBNonOwn = MB.get(); - // Create FileID for the current buffer. FileID FID; // Create FileEntry and FileID for the current buffer. @@ -909,38 +908,72 @@ namespace cling { CO.CodeCompletionOffset+1/* 1-based column*/); } - m_MemoryBuffers.push_back(std::make_pair(MBNonOwn, FID)); - // NewLoc only used for diags. PP.EnterSourceFile(FID, /*DirLookup*/nullptr, NewLoc); m_Consumer->getTransaction()->setBufferFID(FID); + if (!ParseOrWrapTopLevelDecl()) + return kFailed; + + if (PP.getLangOpts().DelayedTemplateParsing) { + // Microsoft-specific: + // Late parsed templates can leave unswallowed "macro"-like tokens. + // They will seriously confuse the Parser when entering the next + // source file. So lex until we are EOF. + Token Tok; + do { + PP.Lex(Tok); + } while (Tok.isNot(tok::eof)); + } + + Token AssertTok; + PP.Lex(AssertTok); + assert(AssertTok.is(tok::eof) && + "Lexer must be EOF when starting incremental parse!"); + DiagnosticsEngine& Diags = getCI()->getDiagnostics(); + if (m_Consumer->getTransaction()->getIssuedDiags() == Transaction::kErrors) + return kFailed; + else if (Diags.getNumWarnings()) + return kSuccessWithWarnings; + return kSuccess; + } + + llvm::Expected IncrementalParser::ParseOrWrapTopLevelDecl() { + // Recover resources if we crash before exiting this method. + Sema& S = getCI()->getSema(); + DiagnosticsEngine& Diags = getCI()->getDiagnostics(); + + const CompilationOptions& CO = + m_Consumer->getTransaction()->getCompilationOpts(); FilteringDiagConsumer::RAAI RAAITmp(*m_DiagConsumer, CO.IgnorePromptDiags); - DiagnosticErrorTrap Trap(Diags); - // FIXME: SavePendingInstantiationsRAII should be obsolvete as - // GlobalEagerInstantiationScope and LocalEagerInstantiationScope do the - // same thing. - Sema::SavePendingInstantiationsRAII SavedPendingInstantiations(S); + llvm::CrashRecoveryContextCleanupRegistrar CleanupSema(&S); Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); Sema::LocalEagerInstantiationScope LocalInstantiations(S); Parser::DeclGroupPtrTy ADecl; - Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module; - while (!m_Parser->ParseTopLevelDecl(ADecl, IS)) { - // 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 (Trap.hasErrorOccurred()) + Sema::ModuleImportState ImportState; + for (bool AtEOF = m_Parser->ParseFirstTopLevelDecl(ADecl, ImportState); + !AtEOF; AtEOF = m_Parser->ParseTopLevelDecl(ADecl, ImportState)) { + if (ADecl && !m_Consumer->HandleTopLevelDecl(ADecl.get())) { m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors); - if (ADecl) - m_Consumer->HandleTopLevelDecl(ADecl.get()); - }; + return llvm::make_error( + "Parsing failed. " + "The consumer rejected a decl", + std::error_code()); + } + } + // If never entered the while block, there's a chance an error occured - if (Trap.hasErrorOccurred()) + if (Diags.hasErrorOccurred()) { m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors); + // Diags.Reset(/*soft=*/true); + // Diags.getClient()->clear(); + return llvm::make_error("Parsing failed.", + std::error_code()); + } if (CO.CodeCompletionOffset != -1) { assert((int)SM.getFileOffset(PP.getCodeCompletionLoc()) @@ -952,40 +985,19 @@ namespace cling { // Let's ignore this transaction: m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors); - return kSuccess; + return true; } - LocalInstantiations.perform(); - GlobalInstantiations.perform(); -#ifdef _WIN32 - // Microsoft-specific: - // Late parsed templates can leave unswallowed "macro"-like tokens. - // They will seriously confuse the Parser when entering the next - // source file. So lex until we are EOF. - Token Tok; - Tok.setKind(tok::eof); - do { - PP.Lex(Tok); - } while (Tok.isNot(tok::eof)); -#endif - -#ifndef NDEBUG - Token AssertTok; - PP.Lex(AssertTok); - assert(AssertTok.is(tok::eof) && "Lexer must be EOF when starting incremental parse!"); -#endif // 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)); + for (Decl* D : S.WeakTopLevelDecls()) { + DeclGroupRef DGR(D); + m_Consumer->HandleTopLevelDecl(DGR); } - if (m_Consumer->getTransaction()->getIssuedDiags() == Transaction::kErrors) - return kFailed; - else if (Diags.getNumWarnings()) - return kSuccessWithWarnings; + LocalInstantiations.perform(); + GlobalInstantiations.perform(); - return kSuccess; + return true; } void IncrementalParser::printTransactionStructure() const { diff --git a/interpreter/cling/lib/Interpreter/IncrementalParser.h b/interpreter/cling/lib/Interpreter/IncrementalParser.h index 582e2bd575bc2..44b2bf023335d 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalParser.h +++ b/interpreter/cling/lib/Interpreter/IncrementalParser.h @@ -64,8 +64,8 @@ namespace cling { // parser (incremental) std::unique_ptr m_Parser; - // One buffer for each command line, owner by the source file manager - std::deque> m_MemoryBuffers; + /// Counts the number of direct user input lines that have been parsed. + unsigned InputCount = 0; // file ID of the memory buffer clang::FileID m_VirtualFileID; @@ -253,6 +253,8 @@ namespace cling { /// EParseResult ParseInternal(llvm::StringRef input); + llvm::Expected ParseOrWrapTopLevelDecl(); + ///\brief Create a unique name for the next llvm::Module /// std::string makeModuleName(); diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp index 74cdf8481cbc7..f6582ad1c343f 100644 --- a/interpreter/cling/lib/Interpreter/Interpreter.cpp +++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp @@ -215,7 +215,8 @@ namespace cling { if (handleSimpleOptions(m_Opts)) return; - m_LLVMContext.reset(new llvm::LLVMContext); + auto LLVMCtx = std::make_unique(); + TSCtx = std::make_unique(std::move(LLVMCtx)); m_IncrParser.reset(new IncrementalParser(this, llvmdir, moduleExtensions)); if (!m_IncrParser->isValid(false)) return; @@ -355,7 +356,7 @@ namespace cling { m_IncrParser->SetTransformers(parentInterp); - if (!m_LLVMContext) { + if (!TSCtx->getContext()) { // Never true, but don't tell the compiler. // Force symbols needed by runtime to be included in binaries. // Prevents stripping the symbol due to dead-code optimization.