cling/lib/Interpreter/IncrementalParser.cpp
2017-06-08 10:29:13 +02:00

831 lines
31 KiB
C++

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
//
// 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 "ASTTransformer.h"
#include "AutoSynthesizer.h"
#include "BackendPasses.h"
#include "CheckEmptyTransactionTransformer.h"
#include "ClingPragmas.h"
#include "DeclCollector.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "IncrementalExecutor.h"
#include "NullDerefProtectionTransformer.h"
#include "TransactionPool.h"
#include "ValueExtractionSynthesizer.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 "cling/Utils/Diagnostics.h"
#include "cling/Utils/Output.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.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 <iostream>
#include <sstream>
#include <stdio.h>
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 bool CheckABICompatibility(cling::Interpreter& Interp) {
#if defined(__GLIBCXX__)
#define CLING_CXXABI_VERS std::to_string(__GLIBCXX__)
const char* CLING_CXXABI_NAME = "__GLIBCXX__";
#elif defined(_LIBCPP_VERSION)
#define CLING_CXXABI_VERS std::to_string(_LIBCPP_VERSION)
const char* CLING_CXXABI_NAME = "_LIBCPP_VERSION";
#elif defined(_CRT_MSVCP_CURRENT)
#define CLING_CXXABI_VERS _CRT_MSVCP_CURRENT
const char* CLING_CXXABI_NAME = "_CRT_MSVCP_CURRENT";
#else
#error "Unknown platform for ABI check";
#endif
const std::string CurABI = Interp.getMacroValue(CLING_CXXABI_NAME);
if (CurABI == CLING_CXXABI_VERS)
return true;
cling::errs() <<
"Warning in cling::IncrementalParser::CheckABICompatibility():\n"
" Possible C++ standard library mismatch, compiled with "
<< CLING_CXXABI_NAME << " '" << CLING_CXXABI_VERS << "'\n"
" Extraction of runtime standard library version was: '"
<< CurABI << "'\n";
return false;
}
class FilteringDiagConsumer : public cling::utils::DiagnosticsOverride {
std::stack<bool> m_IgnorePromptDiags;
void SyncDiagCountWithTarget() {
NumWarnings = m_PrevClient.getNumWarnings();
NumErrors = m_PrevClient.getNumErrors();
}
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP=nullptr) override {
m_PrevClient.BeginSourceFile(LangOpts, PP);
}
void EndSourceFile() override {
m_PrevClient.EndSourceFile();
SyncDiagCountWithTarget();
}
void finish() override {
m_PrevClient.finish();
SyncDiagCountWithTarget();
}
void clear() override {
m_PrevClient.clear();
SyncDiagCountWithTarget();
}
bool IncludeInDiagnosticCounts() const override {
return m_PrevClient.IncludeInDiagnosticCounts();
}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override {
if (Ignoring()) {
if (Info.getID() == diag::warn_unused_expr
|| Info.getID() == diag::warn_unused_call
|| Info.getID() == diag::warn_unused_comparison)
return; // ignore!
if (Info.getID() == diag::warn_falloff_nonvoid_function) {
DiagLevel = DiagnosticsEngine::Error;
}
if (Info.getID() == diag::ext_return_has_expr) {
// An error that we need to suppress.
auto Diags = const_cast<DiagnosticsEngine*>(Info.getDiags());
assert(Diags->hasErrorOccurred() && "Expected ErrorOccurred");
if (m_PrevClient.getNumErrors() == 0) { // first error
Diags->Reset(true /*soft - only counts, not mappings*/);
} // else we had other errors, too.
return; // ignore!
}
}
m_PrevClient.HandleDiagnostic(DiagLevel, Info);
SyncDiagCountWithTarget();
}
bool Ignoring() const {
return !m_IgnorePromptDiags.empty() && m_IgnorePromptDiags.top();
}
public:
FilteringDiagConsumer(DiagnosticsEngine& Diags, bool Own) :
DiagnosticsOverride(Diags, Own) {
}
struct RAAI {
FilteringDiagConsumer& m_Client;
RAAI(DiagnosticConsumer& F, bool Ignore) :
m_Client(static_cast<FilteringDiagConsumer&>(F)) {
m_Client.m_IgnorePromptDiags.push(Ignore);
}
~RAAI() { m_Client.m_IgnorePromptDiags.pop(); }
};
};
} // unnamed namespace
namespace cling {
IncrementalParser::IncrementalParser(Interpreter* interp, const char* llvmdir):
m_Interpreter(interp),
m_CI(CIFactory::createCI("", interp->getOptions(), llvmdir)),
m_Consumer(nullptr), m_ModuleNo(0) {
if (!m_CI) {
cling::errs() << "Compiler instance could not be created.\n";
return;
}
// Is the CompilerInstance being used to generate output only?
if (m_Interpreter->getOptions().CompilerOpts.HasOutput)
return;
m_Consumer = dyn_cast<DeclCollector>(&m_CI->getSema().getASTConsumer());
if (!m_Consumer) {
cling::errs() << "No AST consumer available.\n";
return;
}
DiagnosticsEngine& Diag = m_CI->getDiagnostics();
if (m_CI->getFrontendOpts().ProgramAction != frontend::ParseSyntaxOnly) {
m_CodeGen.reset(CreateLLVMCodeGen(
Diag, "cling-module-0", m_CI->getHeaderSearchOpts(),
m_CI->getPreprocessorOpts(), m_CI->getCodeGenOpts(),
*m_Interpreter->getLLVMContext()));
m_Consumer->setContext(this, m_CodeGen.get());
} else {
m_Consumer->setContext(this, 0);
}
m_DiagConsumer.reset(new FilteringDiagConsumer(Diag, false));
initializeVirtualFile();
}
bool
IncrementalParser::Initialize(llvm::SmallVectorImpl<ParseResultTransaction>&
result, bool isChildInterpreter) {
m_TransactionPool.reset(new TransactionPool);
if (hasCodeGenerator())
getCodeGenerator()->Initialize(getCI()->getASTContext());
CompilationOptions CO = m_Interpreter->makeDefaultCompilationOpts();
Transaction* CurT = beginTransaction(CO);
Preprocessor& PP = m_CI->getPreprocessor();
DiagnosticsEngine& Diags = m_CI->getSema().getDiagnostics();
// Pull in PCH.
const std::string& PCHFileName
= m_CI->getInvocation().getPreprocessorOpts().ImplicitPCHInclude;
if (!PCHFileName.empty()) {
Transaction* PchT = beginTransaction(CO);
DiagnosticErrorTrap Trap(Diags);
m_CI->createPCHExternalASTSource(PCHFileName,
true /*DisablePCHValidation*/,
true /*AllowPCHWithCompilerErrors*/,
0 /*DeserializationListener*/,
true /*OwnsDeserializationListener*/);
result.push_back(endTransaction(PchT));
if (Trap.hasErrorOccurred()) {
result.push_back(endTransaction(CurT));
return false;
}
}
addClingPragmas(*m_Interpreter);
// Must happen after attaching the PCH, else PCH elements will end up
// being lexed.
PP.EnterMainSourceFile();
Sema* TheSema = &m_CI->getSema();
m_Parser.reset(new Parser(PP, *TheSema, false /*skipFuncBodies*/));
// Initialize the parser after PP has entered the main source file.
m_Parser->Initialize();
ExternalASTSource *External = TheSema->getASTContext().getExternalSource();
if (External)
External->StartTranslationUnit(m_Consumer);
// Start parsing the "main file" to warm up lexing (enter caching lex mode
// for ParseInternal()'s call EnterSourceFile() to make sense.
while (!m_Parser->ParseTopLevelDecl()) {}
// If I belong to the parent Interpreter, am using C++, and -noruntime
// wasn't given on command line, then #include <new> and check ABI
if (!isChildInterpreter && m_CI->getLangOpts().CPlusPlus &&
!m_Interpreter->getOptions().NoRuntime) {
// <new> 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 <new>");
// That's really C++ ABI compatibility. C has other problems ;-)
CheckABICompatibility(*m_Interpreter);
}
// DO NOT commit the transactions here: static initialization in these
// transactions requires gCling through local_cxa_atexit(), but that has not
// been defined yet!
ParseResultTransaction PRT = endTransaction(CurT);
result.push_back(PRT);
return true;
}
bool IncrementalParser::isValid(bool initialized) const {
return m_CI && m_CI->hasFileManager() && m_Consumer
&& !m_VirtualFileID.isInvalid()
&& (!initialized || (m_TransactionPool && m_Parser));
}
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() {
Transaction* T = const_cast<Transaction*>(getFirstTransaction());
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?");
const Transaction* nextT = T->getNext();
m_TransactionPool->releaseTransaction(T, false);
T = const_cast<Transaction*>(nextT);
}
}
void IncrementalParser::addTransaction(Transaction* T) {
if (!T->isNestedTransaction() && T != getLastTransaction()) {
if (getLastTransaction())
m_Transactions.back()->setNext(T);
m_Transactions.push_back(T);
}
}
Transaction* IncrementalParser::beginTransaction(const CompilationOptions&
Opts) {
Transaction* OldCurT = m_Consumer->getTransaction();
Transaction* NewCurT = m_TransactionPool->takeTransaction(m_CI->getSema());
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;
}
IncrementalParser::ParseResultTransaction
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);
DiagnosticsEngine& Diag = getCI()->getSema().getDiagnostics();
//TODO: Make the enum orable.
EParseResult ParseResult = kSuccess;
assert((Diag.hasFatalErrorOccurred() ? Diag.hasErrorOccurred() : true)
&& "Diag.hasFatalErrorOccurred without Diag.hasErrorOccurred !");
if (Diag.hasErrorOccurred() || T->getIssuedDiags() == Transaction::kErrors) {
T->setIssuedDiags(Transaction::kErrors);
ParseResult = kFailed;
} else if (Diag.getNumWarnings() > 0) {
T->setIssuedDiags(Transaction::kWarnings);
ParseResult = kSuccessWithWarnings;
}
// 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 ParseResultTransaction(nullptr, ParseResult);
}
addTransaction(T);
return ParseResultTransaction(T, ParseResult);
}
void IncrementalParser::commitTransaction(ParseResultTransaction& PRT,
bool ClearDiagClient) {
Transaction* T = PRT.getPointer();
if (!T) {
if (PRT.getInt() != kSuccess) {
// Nothing has been emitted to Codegen, reset the Diags.
DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics();
Diags.Reset(/*soft=*/true);
if (ClearDiagClient)
Diags.getClient()->clear();
}
return;
}
assert(T->isCompleted() && "Transaction not ended!?");
assert(T->getState() != Transaction::kCommitted
&& "Committing an already committed transaction.");
assert((T->getIssuedDiags() == Transaction::kErrors || !T->empty())
&& "Valid 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) {
// Make module visible to TransactionUnloader.
bool MustStartNewModule = false;
if (!T->isNestedTransaction() && hasCodeGenerator()) {
MustStartNewModule = true;
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
if (M) {
T->setModule(std::move(M));
}
}
// Module has been released from Codegen, reset the Diags now.
DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics();
Diags.Reset(/*soft=*/true);
if (ClearDiagClient)
Diags.getClient()->clear();
PRT.setPointer(nullptr);
PRT.setInt(kFailed);
m_Interpreter->unload(*T);
if (MustStartNewModule) {
// Create a new module.
stdstrstream ModuleName;
ModuleName << "cling-module-" << ++m_ModuleNo;
getCodeGenerator()->StartModule(ModuleName.str(),
*m_Interpreter->getLLVMContext(),
getCI()->getCodeGenOpts());
}
return;
}
if (T->hasNestedTransactions()) {
Transaction* TopmostParent = T->getTopmostParent();
EParseResult PR = kSuccess;
if (TopmostParent->getIssuedDiags() == Transaction::kErrors)
PR = kFailed;
else if (TopmostParent->getIssuedDiags() == Transaction::kWarnings)
PR = kSuccessWithWarnings;
for (Transaction::const_nested_iterator I = T->nested_begin(),
E = T->nested_end(); I != E; ++I)
if ((*I)->getState() != Transaction::kCommitted) {
ParseResultTransaction PRT(*I, PR);
commitTransaction(PRT);
}
}
// If there was an error coming from the transformers.
if (T->getIssuedDiags() == Transaction::kErrors) {
m_Interpreter->unload(*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(T->getCompilationOpts());
// Pull all template instantiations in that came from the consumers.
getCI()->getSema().PerformPendingInstantiations();
ParseResultTransaction nestedPRT = endTransaction(nestedT);
commitTransaction(nestedPRT);
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);
T->setState(Transaction::kCommitted);
if (!T->getParent()) {
if (m_Interpreter->executeTransaction(*T)
>= Interpreter::kExeFirstError) {
// Roll back on error in initializers.
// T maybe pointing to freed memory after this call:
// Interpreter::unload
// IncrementalParser::deregisterTransaction
// TransactionPool::releaseTransaction
m_Interpreter->unload(*T);
return;
}
}
m_Consumer->setTransaction(prevConsumerT);
}
T->setState(Transaction::kCommitted);
if (InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks())
callbacks->TransactionCommitted(*T);
}
void IncrementalParser::emitTransaction(Transaction* T) {
for (auto DI = T->decls_begin(), DE = T->decls_end(); DI != DE; ++DI)
m_Consumer->HandleTopLevelDecl(DI->m_DGR);
}
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");
// Could trigger derserialization of decls.
Transaction* deserT = beginTransaction(CompilationOptions());
// Commit this transaction first - T might need symbols from it, so
// trigger emission of weak symbols by providing use.
ParseResultTransaction PRT = endTransaction(deserT);
commitTransaction(PRT);
deserT = PRT.getPointer();
// This llvm::Module is done; finalize it and pass it to the execution
// engine.
if (!T->isNestedTransaction() && hasCodeGenerator()) {
// The initializers are emitted to the symbol "_GLOBAL__sub_I_" + filename.
// Make that unique!
ASTContext& Context = getCI()->getASTContext();
SourceManager &SM = Context.getSourceManager();
const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID());
FileEntry* NcMainFile = const_cast<FileEntry*>(MainFile);
// Hack to temporarily set the file entry's name to a unique name.
assert(MainFile->getName() == *(const char**)NcMainFile
&& "FileEntry does not start with the name");
const char* &FileName = *(const char**)NcMainFile;
const char* OldName = FileName;
std::string ModName = getCodeGenerator()->GetModule()->getName().str();
FileName = ModName.c_str();
deserT = beginTransaction(CompilationOptions());
// Reset the module builder to clean up global initializers, c'tors, d'tors
getCodeGenerator()->HandleTranslationUnit(Context);
FileName = OldName;
auto PRT = endTransaction(deserT);
commitTransaction(PRT);
deserT = PRT.getPointer();
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
if (M) {
m_Interpreter->addModule(M.get(), T->getCompilationOpts().OptLevel);
T->setModule(std::move(M));
}
if (T->getIssuedDiags() != Transaction::kNone) {
// Module has been released from Codegen, reset the Diags now.
DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics();
Diags.Reset(/*soft=*/true);
Diags.getClient()->clear();
}
// Create a new module.
smallstream ModuleName;
ModuleName << "cling-module-" << ++m_ModuleNo;
getCodeGenerator()->StartModule(ModuleName.str(),
*m_Interpreter->getLLVMContext(),
getCI()->getCodeGenOpts());
}
}
void IncrementalParser::deregisterTransaction(Transaction& T) {
if (&T == m_Consumer->getTransaction())
m_Consumer->setTransaction(T.getParent());
if (Transaction* Parent = T.getParent()) {
Parent->removeNestedTransaction(&T);
T.setParent(0);
} else {
// Remove from the queue
assert(&T == m_Transactions.back() && "Out of order transaction removal");
m_Transactions.pop_back();
if (!m_Transactions.empty())
m_Transactions.back()->setNext(0);
}
m_TransactionPool->releaseTransaction(&T);
}
std::vector<const Transaction*> IncrementalParser::getAllTransactions() {
std::vector<const Transaction*> 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();
if (m_VirtualFileID.isInvalid())
cling::errs() << "VirtualFileID could not be created.\n";
}
IncrementalParser::ParseResultTransaction
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);
ParseResultTransaction PRT = endTransaction(CurT);
commitTransaction(PRT);
return PRT;
}
// 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<Sema> 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<llvm::MemoryBuffer>
MB(llvm::MemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
source_name.str()));
char* MBStart = const_cast<char*>(MB->getBufferStart());
memcpy(MBStart, input.data(), InputSize);
memcpy(MBStart + InputSize, "\n", 2);
SourceManager& SM = getCI()->getSourceManager();
// Create SourceLocation, which will allow clang to order the overload
// candidates for example
SourceLocation NewLoc = getLastMemoryBufferEndLoc().getLocWithOffset(1);
llvm::MemoryBuffer* MBNonOwn = MB.get();
// Create FileID for the current buffer.
FileID FID;
if (CO.CodeCompletionOffset == -1)
{
FID = SM.createFileID(std::move(MB), SrcMgr::C_User,
/*LoadedID*/0,
/*LoadedOffset*/0, NewLoc);
} else {
// Create FileEntry and FileID for the current buffer.
// Enabling the completion point only works on FileEntries.
const clang::FileEntry* FE
= SM.getFileManager().getVirtualFile("vfile for " + source_name.str(),
InputSize, 0 /* mod time*/);
SM.overrideFileContents(FE, std::move(MB));
FID = SM.createFileID(FE, NewLoc, SrcMgr::C_User);
// The completion point is set one a 1-based line/column numbering.
// It relies on the implementation to account for the wrapper extra line.
PP.SetCodeCompletionPoint(FE, 1/* start point 1-based line*/,
CO.CodeCompletionOffset+1/* 1-based column*/);
}
m_MemoryBuffers.push_back(std::make_pair(MBNonOwn, FID));
// NewLoc only used for diags.
PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);
m_Consumer->getTransaction()->setBufferFID(FID);
DiagnosticsEngine& Diags = getCI()->getDiagnostics();
FilteringDiagConsumer::RAAI RAAITmp(*m_DiagConsumer, CO.IgnorePromptDiags);
DiagnosticErrorTrap Trap(Diags);
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 (Trap.hasErrorOccurred())
m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors);
if (ADecl)
m_Consumer->HandleTopLevelDecl(ADecl.get());
};
// If never entered the while block, there's a chance an error occured
if (Trap.hasErrorOccurred())
m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors);
if (CO.CodeCompletionOffset != -1) {
assert((int)SM.getFileOffset(PP.getCodeCompletionLoc())
== CO.CodeCompletionOffset
&& "Completion point wrongly set!");
assert(PP.isCodeCompletionReached()
&& "Code completion set but not reached!");
// Let's ignore this transaction:
m_Consumer->getTransaction()->setIssuedDiags(Transaction::kErrors);
return kSuccess;
}
#ifdef LLVM_ON_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;
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));
}
if (m_Consumer->getTransaction()->getIssuedDiags() == Transaction::kErrors)
return kFailed;
else if (Diags.getNumWarnings())
return kSuccessWithWarnings;
return kSuccess;
}
void IncrementalParser::printTransactionStructure() const {
for(size_t i = 0, e = m_Transactions.size(); i < e; ++i) {
m_Transactions[i]->printStructureBrief();
}
}
void IncrementalParser::SetTransformers(bool isChildInterpreter) {
// Add transformers to the IncrementalParser, which owns them
Sema* TheSema = &m_CI->getSema();
// Register the AST Transformers
typedef std::unique_ptr<ASTTransformer> ASTTPtr_t;
std::vector<ASTTPtr_t> ASTTransformers;
ASTTransformers.emplace_back(new AutoSynthesizer(TheSema));
ASTTransformers.emplace_back(new EvaluateTSynthesizer(TheSema));
if (hasCodeGenerator() && !m_Interpreter->getOptions().NoRuntime) {
// Don't protect against crashes if we cannot run anything.
// cling might also be in a PCH-generation mode; don't inject our Sema pointer
// into the PCH.
ASTTransformers.emplace_back(new NullDerefProtectionTransformer(m_Interpreter));
}
typedef std::unique_ptr<WrapperTransformer> WTPtr_t;
std::vector<WTPtr_t> WrapperTransformers;
if (!m_Interpreter->getOptions().NoRuntime)
WrapperTransformers.emplace_back(new ValuePrinterSynthesizer(TheSema));
WrapperTransformers.emplace_back(new DeclExtractor(TheSema));
if (!m_Interpreter->getOptions().NoRuntime)
WrapperTransformers.emplace_back(new ValueExtractionSynthesizer(TheSema,
isChildInterpreter));
WrapperTransformers.emplace_back(new CheckEmptyTransactionTransformer(TheSema));
m_Consumer->SetTransformers(std::move(ASTTransformers),
std::move(WrapperTransformers));
}
} // namespace cling