cling/lib/Interpreter/IncrementalParser.cpp

874 lines
33 KiB
C++
Raw Normal View History

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2014-01-07 14:08:37 +04:00
//
// 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"
2014-03-27 20:30:09 +04:00
#include "AutoSynthesizer.h"
#include "BackendPasses.h"
#include "CheckEmptyTransactionTransformer.h"
#include "DeclCollector.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "IncrementalExecutor.h"
2013-07-15 00:35:00 +04:00
#include "NullDerefProtectionTransformer.h"
#include "ValueExtractionSynthesizer.h"
#include "TransactionPool.h"
2014-03-27 20:30:09 +04:00
#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"
2014-01-15 18:40:52 +04:00
#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 <iostream>
#include <stdio.h>
#include <sstream>
// 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 <Windows.h>
#include <sstream>
#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, &regVS) == 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<clang::DefMacroDirective>(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<DeclCollector>(&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(),
*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));
2013-09-11 15:31:14 +04:00
m_ASTTransformers.push_back(new NullDerefProtectionTransformer(TheSema));
m_ASTTransformers.push_back(new CheckEmptyTransactionTransformer(TheSema));
}
void
IncrementalParser::Initialize(llvm::SmallVectorImpl<Transaction*> &result) {
2014-03-28 17:53:34 +04:00
m_TransactionPool.reset(new TransactionPool(getCI()->getSema()));
if (hasCodeGenerator()) {
getCodeGenerator()->Initialize(getCI()->getASTContext());
m_BackendPasses.reset(new BackendPasses(getCI()->getCodeGenOpts(),
getCI()->getTargetOpts(),
getCI()->getLangOpts()));
}
2013-05-23 13:05:02 +04:00
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);
// <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>");
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
2014-08-04 06:05:42 +04:00
|| 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];
}
2014-08-04 06:05:42 +04:00
Transaction* IncrementalParser::beginTransaction(const CompilationOptions&
Opts) {
Transaction* OldCurT = m_Consumer->getTransaction();
Transaction* NewCurT = m_TransactionPool->takeTransaction();
NewCurT->setCompilationOpts(Opts);
2014-08-04 06:05:42 +04:00
// If we are in the middle of transaction and we see another begin
// transaction - it must be nested transaction.
2014-08-04 06:05:42 +04:00
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()) {
2014-08-04 06:05:42 +04:00
assert((!m_Consumer->getTransaction()
2013-08-05 17:15:37 +04:00
|| (m_Consumer->getTransaction() == T))
&& "Cannot release different T");
2014-08-04 06:05:42 +04:00
// 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;
}
2014-08-04 06:05:42 +04:00
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()) {
2013-07-06 15:03:21 +04:00
for (Transaction::const_nested_iterator I = T->nested_begin(),
E = T->nested_end(); I != E; ++I)
if ((*I)->getState() != Transaction::kCommitted)
commitTransaction(*I);
}
2013-07-06 15:01:48 +04:00
// If there was an error coming from the transformers.
if (T->getIssuedDiags() == Transaction::kErrors) {
rollbackTransaction(T);
return;
2013-07-06 15:01:48 +04:00
}
// 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->executeTransaction(*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 {
2014-03-28 17:53:34 +04:00
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<clang::UsedAttr>())
D->addAttr(::new (D->getASTContext())
clang::UsedAttr(D->getSourceRange(), D->getASTContext(),
0/*AttributeSpellingListIndex*/));
}
2014-08-04 06:05:42 +04:00
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<clang::UsedAttr>())
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");
2013-07-31 11:04:30 +04:00
assert(T->getState() == Transaction::kCompleted && "Must be completed");
assert(hasCodeGenerator() && "No CodeGen");
// 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<TagDecl>(I.m_DGR.getSingleDecl());
getCodeGenerator()->HandleTagDeclDefinition(TD);
}
else if (I.m_Call == Transaction::kCCIHandleVTable) {
CXXRecordDecl* CXXRD = cast<CXXRecordDecl>(I.m_DGR.getSingleDecl());
2015-01-21 15:29:31 +03:00
getCodeGenerator()->HandleVTable(CXXRD);
}
else if (I.m_Call
== Transaction::kCCIHandleCXXImplicitFunctionInstantiation) {
FunctionDecl* FD = cast<FunctionDecl>(I.m_DGR.getSingleDecl());
getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD);
}
else if (I.m_Call
== Transaction::kCCIHandleCXXStaticMemberVarInstantiation) {
VarDecl* VD = cast<VarDecl>(I.m_DGR.getSingleDecl());
getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD);
}
else if (I.m_Call == Transaction::kCCICompleteTentativeDefinition) {
VarDecl* VD = cast<VarDecl>(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.
2014-08-04 06:05:42 +04:00
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<NamespaceDecl>(*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<TagDecl>(*DI);
getCodeGenerator()->HandleTagDeclDefinition(TD);
}
else if (I->m_Call == Transaction::kCCIHandleVTable) {
CXXRecordDecl* CXXRD = cast<CXXRecordDecl>(*DI);
2015-01-21 15:29:31 +03:00
getCodeGenerator()->HandleVTable(CXXRD);
}
else if (I->m_Call
== Transaction::kCCIHandleCXXImplicitFunctionInstantiation) {
FunctionDecl* FD = cast<FunctionDecl>(*DI);
getCodeGenerator()->HandleCXXImplicitFunctionInstantiation(FD);
}
else if (I->m_Call
== Transaction::kCCIHandleCXXStaticMemberVarInstantiation) {
VarDecl* VD = cast<VarDecl>(*DI);
getCodeGenerator()->HandleCXXStaticMemberVarInstantiation(VD);
}
else if (I->m_Call == Transaction::kCCICompleteTentativeDefinition) {
VarDecl* VD = cast<VarDecl>(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
// 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**)MainFile
&& "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();
getCodeGenerator()->HandleTranslationUnit(Context);
FileName = OldName;
// Commit this transaction first - T might need symbols from it, so
// trigger emission of weak symbols by providing use.
if ((deserT = endTransaction(deserT)))
commitTransaction(deserT);
// This llvm::Module is done; finalize it and pass it to the execution
// engine.
if (!T->isNestedTransaction() && hasCodeGenerator()) {
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
if (M) {
2015-02-10 13:13:59 +03:00
m_Interpreter->addModule(M.get());
T->setModule(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());
}
}
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)
2013-07-06 15:01:48 +04:00
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);
if (m_BackendPasses && T->getModule())
m_BackendPasses->runOnModule(*T->getModule());
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());
2014-03-27 20:30:09 +04:00
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<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();
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)
2014-02-20 13:16:47 +04:00
&& "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);
2015-02-10 13:18:15 +03:00
llvm::MemoryBuffer* MBNonOwn = MB.get();
// Create FileID for the current buffer
FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User,
/*LoadedID*/0,
/*LoadedOffset*/0, NewLoc);
2015-02-10 13:18:15 +03:00
m_MemoryBuffers.push_back(std::make_pair(MBNonOwn, 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)
2013-09-23 17:36:32 +04:00
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<Decl*,2>::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;
}
2013-07-06 15:02:49 +04:00
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<FunctionDecl>(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<VarDecl>(D))
if (VD->hasGlobalStorage() && !VD->getType().isConstQualified()
&& VD->getTemplateSpecializationKind() == TSK_Undeclared)
return true;
return false;
}
} // namespace cling