Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions interpreter/cling/include/cling/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "cling/Interpreter/RuntimeOptions.h"

#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"

#include <cstdlib>
#include <memory>
Expand Down Expand Up @@ -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<llvm::LLVMContext> m_LLVMContext;
std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx;

///\brief Cling's execution engine - a well wrapped llvm execution engine.
///
Expand Down Expand Up @@ -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; }

Expand Down
108 changes: 60 additions & 48 deletions interpreter/cling/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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<bool> 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<Sema> 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<llvm::StringError>(
"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<llvm::StringError>("Parsing failed.",
std::error_code());
}

if (CO.CodeCompletionOffset != -1) {
assert((int)SM.getFileOffset(PP.getCodeCompletionLoc())
Expand All @@ -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<Decl*,2>::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 {
Expand Down
6 changes: 4 additions & 2 deletions interpreter/cling/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ namespace cling {
// parser (incremental)
std::unique_ptr<clang::Parser> m_Parser;

// One buffer for each command line, owner by the source file manager
std::deque<std::pair<llvm::MemoryBuffer*, clang::FileID>> 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;
Expand Down Expand Up @@ -253,6 +253,8 @@ namespace cling {
///
EParseResult ParseInternal(llvm::StringRef input);

llvm::Expected<bool> ParseOrWrapTopLevelDecl();

///\brief Create a unique name for the next llvm::Module
///
std::string makeModuleName();
Expand Down
5 changes: 3 additions & 2 deletions interpreter/cling/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ namespace cling {
if (handleSimpleOptions(m_Opts))
return;

m_LLVMContext.reset(new llvm::LLVMContext);
auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
m_IncrParser.reset(new IncrementalParser(this, llvmdir, moduleExtensions));
if (!m_IncrParser->isValid(false))
return;
Expand Down Expand Up @@ -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.
Expand Down