Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cling] Make parts of the cling codebase similar to upstream clang-repl #15374

Merged
merged 8 commits into from
May 6, 2024
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
Loading