cling/lib/Interpreter/Interpreter.cpp
Manasij Mukherjee f474d63079 Generation of forward declarations of top level decls in an input file.
Consists of:
  ForwardDeclPrinter, adapted from clang::DeclPrinter
  Interpterer::GenerateAutoloadingMap for invoking the functionality
  It has hardcoded checks to prevent ForwardDeclPrinter from visiting decls from
standard library files. This restriction will be lifted after the
issues specifyed in the tests are fixed.
  Test cases for code which FowrardDeclPrinter can not deal with properly
2014-06-23 14:37:03 +02:00

1255 lines
44 KiB
C++

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Lukasz Janyst <ljanyst@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 "cling/Interpreter/Interpreter.h"
#include "cling-compiledata.h"
#include "DynamicLookup.h"
#include "IncrementalExecutor.h"
#include "IncrementalParser.h"
#include "ForwardDeclPrinter.h"
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/ClangInternalState.h"
#include "cling/Interpreter/CompilationOptions.h"
#include "cling/Interpreter/DynamicLibraryManager.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/LookupHelper.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Interpreter/Value.h"
#include "cling/Utils/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>
#include <string>
#include <vector>
using namespace clang;
namespace {
static cling::Interpreter::ExecutionResult
ConvertExecutionResult(cling::IncrementalExecutor::ExecutionResult ExeRes) {
switch (ExeRes) {
case cling::IncrementalExecutor::kExeSuccess:
return cling::Interpreter::kExeSuccess;
case cling::IncrementalExecutor::kExeFunctionNotCompiled:
return cling::Interpreter::kExeFunctionNotCompiled;
case cling::IncrementalExecutor::kExeUnresolvedSymbols:
return cling::Interpreter::kExeUnresolvedSymbols;
default: break;
}
return cling::Interpreter::kExeSuccess;
}
} // unnamed namespace
namespace cling {
namespace runtime {
namespace internal {
// "Declared" to the JIT in RuntimeUniverse.h
void local_cxa_atexit(void (*func) (void*), void* arg, void* interp) {
Interpreter* cling = (cling::Interpreter*)interp;
cling->AddAtExitFunc(func, arg);
}
} // end namespace internal
} // end namespace runtime
// FIXME: workaround until JIT supports exceptions
jmp_buf* Interpreter::m_JumpBuf;
Interpreter::PushTransactionRAII::PushTransactionRAII(const Interpreter* i)
: m_Interpreter(i) {
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = 0;
CO.Debug = 0;
CO.CodeGeneration = 1;
CO.CodeGenerationForModule = 0;
m_Transaction = m_Interpreter->m_IncrParser->beginTransaction(CO);
}
Interpreter::PushTransactionRAII::~PushTransactionRAII() {
pop();
}
void Interpreter::PushTransactionRAII::pop() const {
if (Transaction* T
= m_Interpreter->m_IncrParser->endTransaction(m_Transaction)) {
assert(T == m_Transaction && "Ended different transaction?");
m_Interpreter->m_IncrParser->commitTransaction(T);
}
}
Interpreter::StateDebuggerRAII::StateDebuggerRAII(const Interpreter* i)
: m_Interpreter(i) {
if (!i->isPrintingDebug())
return;
const CompilerInstance& CI = *m_Interpreter->getCI();
CodeGenerator* CG = i->m_IncrParser->getCodeGenerator();
// The ClangInternalState constructor can provoke deserialization,
// we need a transaction.
PushTransactionRAII pushedT(i);
m_State.reset(new ClangInternalState(CI.getASTContext(),
CI.getPreprocessor(),
CG ? CG->GetModule() : 0,
CG,
"aName"));
}
Interpreter::StateDebuggerRAII::~StateDebuggerRAII() {
// The ClangInternalState destructor can provoke deserialization,
// we need a transaction.
PushTransactionRAII pushedT(m_Interpreter);
pop();
}
void Interpreter::StateDebuggerRAII::pop() const {
if (!m_Interpreter->isPrintingDebug())
return;
m_State->compare("aName");
}
// This function isn't referenced outside its translation unit, but it
// can't use the "static" keyword because its address is used for
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
const Parser& Interpreter::getParser() const {
return *m_IncrParser->getParser();
}
bool Interpreter::isInSyntaxOnlyMode() const {
return getCI()->getFrontendOpts().ProgramAction
== clang::frontend::ParseSyntaxOnly;
}
Interpreter::Interpreter(int argc, const char* const *argv,
const char* llvmdir /*= 0*/) :
m_UniqueCounter(0), m_PrintDebug(false),
m_DynamicLookupEnabled(false), m_RawInputEnabled(false),
m_LastCustomPragmaDiagPopPoint(){
m_LLVMContext.reset(new llvm::LLVMContext);
std::vector<unsigned> LeftoverArgsIdx;
m_Opts = InvocationOptions::CreateFromArgs(argc, argv, LeftoverArgsIdx);
std::vector<const char*> LeftoverArgs;
for (size_t I = 0, N = LeftoverArgsIdx.size(); I < N; ++I) {
LeftoverArgs.push_back(argv[LeftoverArgsIdx[I]]);
}
m_DyLibManager.reset(new DynamicLibraryManager(getOptions()));
m_IncrParser.reset(new IncrementalParser(this, LeftoverArgs.size(),
&LeftoverArgs[0],
llvmdir));
Sema& SemaRef = getSema();
Preprocessor& PP = SemaRef.getPreprocessor();
// Enable incremental processing, which prevents the preprocessor destroying
// the lexer on EOF token.
PP.enableIncrementalProcessing();
m_LookupHelper.reset(new LookupHelper(new Parser(PP, SemaRef,
/*SkipFunctionBodies*/false,
/*isTemp*/true), this));
if (!isInSyntaxOnlyMode()) {
llvm::Module* theModule = m_IncrParser->getCodeGenerator()->GetModule();
m_Executor.reset(new IncrementalExecutor(theModule, SemaRef.Diags));
}
llvm::SmallVector<Transaction*, 2> IncrParserTransactions;
m_IncrParser->Initialize(IncrParserTransactions);
handleFrontendOptions();
AddRuntimeIncludePaths(argv[0]);
// Tell the diagnostic client that we are entering file parsing mode.
DiagnosticConsumer& DClient = getCI()->getDiagnosticClient();
DClient.BeginSourceFile(getCI()->getLangOpts(), &PP);
if (getCI()->getLangOpts().CPlusPlus)
IncludeCXXRuntime();
else
IncludeCRuntime();
// Commit the transactions, now that gCling is set up. It is needed for
// static initialization in these transactions through local_cxa_atexit().
for (llvm::SmallVectorImpl<Transaction*>::const_iterator
I = IncrParserTransactions.begin(), E = IncrParserTransactions.end();
I != E; ++I)
m_IncrParser->commitTransaction(*I);
}
Interpreter::~Interpreter() {
if (m_Executor)
m_Executor->shuttingDown();
for (size_t i = 0, e = m_StoredStates.size(); i != e; ++i)
delete m_StoredStates[i];
getCI()->getDiagnostics().getClient()->EndSourceFile();
}
const char* Interpreter::getVersion() const {
return CLING_VERSION;
}
void Interpreter::handleFrontendOptions() {
if (m_Opts.ShowVersion) {
llvm::errs() << getVersion() << '\n';
}
if (m_Opts.Help) {
m_Opts.PrintHelp();
}
}
void Interpreter::AddRuntimeIncludePaths(const char* argv0) {
// Add configuration paths to interpreter's include files.
#ifdef CLING_INCLUDE_PATHS
llvm::StringRef InclPaths(CLING_INCLUDE_PATHS);
for (std::pair<llvm::StringRef, llvm::StringRef> Split
= InclPaths.split(':');
!Split.second.empty(); Split = InclPaths.split(':')) {
if (llvm::sys::fs::is_directory(Split.first))
AddIncludePath(Split.first);
InclPaths = Split.second;
}
// Add remaining part
AddIncludePath(InclPaths);
#endif
llvm::SmallString<512> P(GetExecutablePath(argv0));
if (!P.empty()) {
// Remove /cling from foo/bin/clang
llvm::StringRef ExeIncl = llvm::sys::path::parent_path(P);
// Remove /bin from foo/bin
ExeIncl = llvm::sys::path::parent_path(ExeIncl);
P.resize(ExeIncl.size());
// Get foo/include
llvm::sys::path::append(P, "include");
if (llvm::sys::fs::is_directory(P.str()))
AddIncludePath(P.str());
}
}
void Interpreter::IncludeCXXRuntime() {
// Set up common declarations which are going to be available
// only at runtime
// Make sure that the universe won't be included to compile time by using
// -D __CLING__ as CompilerInstance's arguments
#ifdef _WIN32
// We have to use the #defined __CLING__ on windows first.
//FIXME: Find proper fix.
declare("#ifdef __CLING__ \n#endif");
#endif
declare("#include \"cling/Interpreter/RuntimeUniverse.h\"");
if (!isInSyntaxOnlyMode()) {
// Set up the gCling variable if it can be used
std::stringstream initializer;
initializer << "namespace cling {namespace runtime { "
"cling::Interpreter *gCling=(cling::Interpreter*)"
<< (uintptr_t)this << ";} }";
declare(initializer.str());
}
}
void Interpreter::IncludeCRuntime() {
// Set up the gCling variable if it can be used
std::stringstream initializer;
initializer << "void* gCling=(void*)" << (uintptr_t)this << ';';
declare(initializer.str());
// declare("void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT);");
// declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, float value);");
// declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, double value);");
// declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, long double value);");
// declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, unsigned long long value);");
// declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, const void* value);");
// declare("void* setValueWithAlloc(void* vpI, void* vpV, void* vpQT);");
declare("#include \"cling/Interpreter/CValuePrinter.h\"");
}
void Interpreter::AddIncludePath(llvm::StringRef incpath)
{
// Add the given path to the list of directories in which the interpreter
// looks for include files. Only one path item can be specified at a
// time, i.e. "path1:path2" is not supported.
CompilerInstance* CI = getCI();
HeaderSearchOptions& headerOpts = CI->getHeaderSearchOpts();
const bool IsFramework = false;
const bool IsSysRootRelative = true;
// Avoid duplicates; just return early if incpath is already in UserEntries.
for (std::vector<HeaderSearchOptions::Entry>::const_iterator
I = headerOpts.UserEntries.begin(),
E = headerOpts.UserEntries.end(); I != E; ++I)
if (I->Path == incpath)
return;
headerOpts.AddPath(incpath, frontend::Angled, IsFramework,
IsSysRootRelative);
Preprocessor& PP = CI->getPreprocessor();
ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), headerOpts,
PP.getLangOpts(),
PP.getTargetInfo().getTriple());
}
void Interpreter::DumpIncludePath() {
llvm::SmallVector<std::string, 100> IncPaths;
GetIncludePaths(IncPaths, true /*withSystem*/, true /*withFlags*/);
// print'em all
for (unsigned i = 0; i < IncPaths.size(); ++i) {
llvm::errs() << IncPaths[i] <<"\n";
}
}
void Interpreter::storeInterpreterState(const std::string& name) const {
// This may induce deserialization
PushTransactionRAII RAII(this);
CodeGenerator* CG = m_IncrParser->getCodeGenerator();
ClangInternalState* state
= new ClangInternalState(getCI()->getASTContext(),
getCI()->getPreprocessor(),
CG ? CG->GetModule() : 0,
CG, name);
m_StoredStates.push_back(state);
}
void Interpreter::compareInterpreterState(const std::string& name) const {
short foundAtPos = -1;
for (short i = 0, e = m_StoredStates.size(); i != e; ++i) {
if (m_StoredStates[i]->getName() == name) {
foundAtPos = i;
break;
}
}
assert(foundAtPos>-1 && "The name doesnt exist. Unbalanced store/compare");
// This may induce deserialization
PushTransactionRAII RAII(this);
m_StoredStates[foundAtPos]->compare(name);
}
void Interpreter::printIncludedFiles(llvm::raw_ostream& Out) const {
ClangInternalState::printIncludedFiles(Out, getCI()->getSourceManager());
}
// Adapted from clang/lib/Frontend/CompilerInvocation.cpp
void Interpreter::GetIncludePaths(llvm::SmallVectorImpl<std::string>& incpaths,
bool withSystem, bool withFlags) {
const HeaderSearchOptions Opts(getCI()->getHeaderSearchOpts());
if (withFlags && Opts.Sysroot != "/") {
incpaths.push_back("-isysroot");
incpaths.push_back(Opts.Sysroot);
}
/// User specified include entries.
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
if (E.IsFramework && E.Group != frontend::Angled)
llvm::report_fatal_error("Invalid option set!");
switch (E.Group) {
case frontend::After:
if (withFlags) incpaths.push_back("-idirafter");
break;
case frontend::Quoted:
if (withFlags) incpaths.push_back("-iquote");
break;
case frontend::System:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-isystem");
break;
case frontend::IndexHeaderMap:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-index-header-map");
if (withFlags) incpaths.push_back(E.IsFramework? "-F" : "-I");
break;
case frontend::CSystem:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-c-isystem");
break;
case frontend::ExternCSystem:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-extern-c-isystem");
break;
case frontend::CXXSystem:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-cxx-isystem");
break;
case frontend::ObjCSystem:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-objc-isystem");
break;
case frontend::ObjCXXSystem:
if (!withSystem) continue;
if (withFlags) incpaths.push_back("-objcxx-isystem");
break;
case frontend::Angled:
if (withFlags) incpaths.push_back(E.IsFramework ? "-F" : "-I");
break;
}
incpaths.push_back(E.Path);
}
if (withSystem && !Opts.ResourceDir.empty()) {
if (withFlags) incpaths.push_back("-resource-dir");
incpaths.push_back(Opts.ResourceDir);
}
if (withSystem && withFlags && !Opts.ModuleCachePath.empty()) {
incpaths.push_back("-fmodule-cache-path");
incpaths.push_back(Opts.ModuleCachePath);
}
if (withSystem && withFlags && !Opts.UseStandardSystemIncludes)
incpaths.push_back("-nostdinc");
if (withSystem && withFlags && !Opts.UseStandardCXXIncludes)
incpaths.push_back("-nostdinc++");
if (withSystem && withFlags && Opts.UseLibcxx)
incpaths.push_back("-stdlib=libc++");
if (withSystem && withFlags && Opts.Verbose)
incpaths.push_back("-v");
}
CompilerInstance* Interpreter::getCI() const {
return m_IncrParser->getCI();
}
const Sema& Interpreter::getSema() const {
return getCI()->getSema();
}
Sema& Interpreter::getSema() {
return getCI()->getSema();
}
llvm::ExecutionEngine* Interpreter::getExecutionEngine() const {
if (!m_Executor) return 0;
return m_Executor->getExecutionEngine();
}
///\brief Maybe transform the input line to implement cint command line
/// semantics (declarations are global) and compile to produce a module.
///
Interpreter::CompilationResult
Interpreter::process(const std::string& input, Value* V /* = 0 */,
Transaction** T /* = 0 */) {
if (isRawInputEnabled() || !ShouldWrapInput(input))
return declare(input, T);
CompilationOptions CO;
CO.DeclarationExtraction = 1;
CO.ValuePrinting = CompilationOptions::VPAuto;
CO.ResultEvaluation = (bool)V;
CO.DynamicScoping = isDynamicLookupEnabled();
CO.Debug = isPrintingDebug();
if (EvaluateInternal(input, CO, V, T) == Interpreter::kFailure) {
return Interpreter::kFailure;
}
return Interpreter::kSuccess;
}
Interpreter::CompilationResult
Interpreter::parse(const std::string& input, Transaction** T /*=0*/) const {
CompilationOptions CO;
CO.CodeGeneration = 0;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = isDynamicLookupEnabled();
CO.Debug = isPrintingDebug();
return DeclareInternal(input, CO, T);
}
Interpreter::CompilationResult
Interpreter::loadModuleForHeader(const std::string& headerFile) {
Preprocessor& PP = getCI()->getPreprocessor();
//Copied from clang's PPDirectives.cpp
bool isAngled = false;
// Clang doc says:
// "LookupFrom is set when this is a \#include_next directive, it specifies
// the file to start searching from."
const DirectoryLookup* LookupFrom = 0;
const DirectoryLookup* CurDir = 0;
ModuleMap::KnownHeader suggestedModule;
// PP::LookupFile uses it to issue 'nice' diagnostic
SourceLocation fileNameLoc;
PP.LookupFile(fileNameLoc, headerFile, isAngled, LookupFrom, CurDir,
/*SearchPath*/0, /*RelativePath*/ 0, &suggestedModule,
/*SkipCache*/false, /*OpenFile*/ false, /*CacheFail*/ false);
if (!suggestedModule)
return Interpreter::kFailure;
// Copied from PPDirectives.cpp
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> path;
for (Module *mod = suggestedModule.getModule(); mod; mod = mod->Parent) {
IdentifierInfo* II
= &getSema().getPreprocessor().getIdentifierTable().get(mod->Name);
path.push_back(std::make_pair(II, fileNameLoc));
}
std::reverse(path.begin(), path.end());
// Pretend that the module came from an inclusion directive, so that clang
// will create an implicit import declaration to capture it in the AST.
bool isInclude = true;
SourceLocation includeLoc;
if (getCI()->loadModule(includeLoc, path, Module::AllVisible, isInclude)) {
// After module load we need to "force" Sema to generate the code for
// things like dynamic classes.
getSema().ActOnEndOfTranslationUnit();
return Interpreter::kSuccess;
}
return Interpreter::kFailure;
}
Interpreter::CompilationResult
Interpreter::parseForModule(const std::string& input) {
CompilationOptions CO;
CO.CodeGeneration = 1;
CO.CodeGenerationForModule = 1;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = isDynamicLookupEnabled();
CO.Debug = isPrintingDebug();
// When doing parseForModule avoid warning about the user code
// being loaded ... we probably might as well extend this to
// ALL warnings ... but this will suffice for now (working
// around a real bug in QT :().
DiagnosticsEngine& Diag = getCI()->getDiagnostics();
Diag.setDiagnosticMapping(clang::diag::warn_field_is_uninit,
clang::diag::MAP_IGNORE, SourceLocation());
return DeclareInternal(input, CO);
}
Interpreter::CompilationResult
Interpreter::declare(const std::string& input, Transaction** T/*=0 */) {
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = isDynamicLookupEnabled();
CO.Debug = isPrintingDebug();
return DeclareInternal(input, CO, T);
}
Interpreter::CompilationResult
Interpreter::evaluate(const std::string& input, Value& V) {
// Here we might want to enforce further restrictions like: Only one
// ExprStmt can be evaluated and etc. Such enforcement cannot happen in the
// worker, because it is used from various places, where there is no such
// rule
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 1;
return EvaluateInternal(input, CO, &V);
}
Interpreter::CompilationResult
Interpreter::echo(const std::string& input, Value* V /* = 0 */) {
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = CompilationOptions::VPEnabled;
CO.ResultEvaluation = (bool)V;
return EvaluateInternal(input, CO, V);
}
Interpreter::CompilationResult
Interpreter::execute(const std::string& input) {
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = 0;
CO.Debug = isPrintingDebug();
return EvaluateInternal(input, CO);
}
Interpreter::CompilationResult Interpreter::emitAllDecls(Transaction* T) {
assert(!isInSyntaxOnlyMode() && "No CodeGenerator?");
m_IncrParser->markWholeTransactionAsUsed(T);
m_IncrParser->codeGenTransaction(T);
// 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...
T->setState(Transaction::kCommitted);
if (runStaticInitializersOnce(*T))
return Interpreter::kSuccess;
return Interpreter::kFailure;
}
bool Interpreter::ShouldWrapInput(const std::string& input) {
// TODO: For future reference.
// Parser* P = const_cast<clang::Parser*>(m_IncrParser->getParser());
// Parser::TentativeParsingAction TA(P);
// TPResult result = P->isCXXDeclarationSpecifier();
// TA.Revert();
// return result == TPResult::True();
// FIXME: can't skipToEndOfLine because we don't want to PragmaLex
// because we don't want to pollute the preprocessor. Without PragmaLex
// there is no "end of line" / eod token. So skip the #line before lexing.
size_t posStart = 0;
size_t lenInput = input.length();
while (lenInput > posStart && isspace(input[posStart]))
++posStart;
// Don't wrap empty input
if (posStart == lenInput)
return false;
if (input[posStart] == '#') {
size_t posDirective = posStart + 1;
while (lenInput > posDirective && isspace(input[posDirective]))
++posDirective;
// A single '#'? Weird... better don't wrap.
if (posDirective == lenInput)
return false;
if (!strncmp(&input[posDirective], "line ", 5)) {
// There is a line directive. It does affect the determination whether
// this input should be wrapped; skip the line.
size_t posEOD = input.find('\n', posDirective + 5);
if (posEOD != std::string::npos)
posStart = posEOD + 1;
}
}
//llvm::OwningPtr<llvm::MemoryBuffer> buf;
//buf.reset(llvm::MemoryBuffer::getMemBuffer(&input[posStart],
// "Cling Preparse Buf"));
Lexer WrapLexer(SourceLocation(), getSema().getLangOpts(),
input.c_str() + posStart,
input.c_str() + posStart,
input.c_str() + input.size());
Token Tok;
WrapLexer.LexFromRawLexer(Tok);
const tok::TokenKind kind = Tok.getKind();
if (kind == tok::raw_identifier && !Tok.needsCleaning()) {
StringRef keyword(Tok.getRawIdentifierData(), Tok.getLength());
if (keyword.equals("using")) {
// FIXME: Using definitions and declarations should be decl extracted.
// Until we have that, don't wrap them if they are the only input.
const char* cursor = keyword.data();
cursor = strchr(cursor, ';'); // advance to end of using decl / def.
if (!cursor) {
// Using decl / def without trailing ';' means input consists of only
// that using decl /def: should not wrap.
return false;
}
// Skip whitespace after ';'
do ++cursor;
while (*cursor && isspace(*cursor));
if (!*cursor)
return false;
// There is "more" - let's assume this input consists of a using
// declaration or definition plus some code that should be wrapped.
return true;
}
if (keyword.equals("extern"))
return false;
if (keyword.equals("namespace"))
return false;
if (keyword.equals("template"))
return false;
}
else if (kind == tok::hash) {
WrapLexer.LexFromRawLexer(Tok);
if (Tok.is(tok::raw_identifier) && !Tok.needsCleaning()) {
StringRef keyword(Tok.getRawIdentifierData(), Tok.getLength());
if (keyword.equals("include"))
return false;
}
}
return true;
}
void Interpreter::WrapInput(std::string& input, std::string& fname) {
fname = createUniqueWrapper();
input.insert(0, "void " + fname + "(void* vpClingValue) {\n ");
input.append("\n;\n}");
}
Interpreter::ExecutionResult
Interpreter::RunFunction(const FunctionDecl* FD, Value* res /*=0*/) {
if (getCI()->getDiagnostics().hasErrorOccurred())
return kExeCompilationError;
if (isInSyntaxOnlyMode()) {
return kExeNoCodeGen;
}
if (!FD)
return kExeUnkownFunction;
std::string mangledNameIfNeeded;
utils::Analyze::maybeMangleDeclName(FD, mangledNameIfNeeded);
IncrementalExecutor::ExecutionResult ExeRes =
m_Executor->executeFunction(mangledNameIfNeeded.c_str(), res);
return ConvertExecutionResult(ExeRes);
}
const FunctionDecl* Interpreter::DeclareCFunction(StringRef name,
StringRef code,
bool withAccessControl) {
/*
In CallFunc we currently always (intentionally and somewhat necessarily)
always fully specify member function template, however this can lead to
an ambiguity with a class template. For example in
roottest/cling/functionTemplate we get:
input_line_171:3:15: warning: lookup of 'set' in member access expression
is ambiguous; using member of 't'
((t*)obj)->set<int>(*(int*)args[0]);
^
roottest/cling/functionTemplate/t.h:19:9: note: lookup in the object type
't' refers here
void set(T targ) {
^
/usr/include/c++/4.4.5/bits/stl_set.h:87:11: note: lookup from the
current scope refers here
class set
^
This is an intention warning implemented in clang, see
http://llvm.org/viewvc/llvm-project?view=revision&revision=105518
which 'should have been' an error:
C++ [basic.lookup.classref] requires this to be an error, but,
because it's hard to work around, Clang downgrades it to a warning as
an extension.</p>
// C++98 [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
// immediately followed by an identifier followed by a <, the identifier
// must be looked up to determine whether the < is the beginning of a
// template argument list (14.2) or a less-than operator. The identifier
// is first looked up in the class of the object expression. If the
// identifier is not found, it is then looked up in the context of the
// entire postfix-expression and shall name a class or function template. If
// the lookup in the class of the object expression finds a template, the
// name is also looked up in the context of the entire postfix-expression
// and
// -- if the name is not found, the name found in the class of the
// object expression is used, otherwise
// -- if the name is found in the context of the entire postfix-expression
// and does not name a class template, the name found in the class of the
// object expression is used, otherwise
// -- if the name found is a class template, it must refer to the same
// entity as the one found in the class of the object expression,
// otherwise the program is ill-formed.
See -Wambiguous-member-template
An alternative to disabling the diagnostics is to use a pointer to
member function:
#include <set>
using namespace std;
extern "C" int printf(const char*,...);
struct S {
template <typename T>
void set(T) {};
virtual void virtua() { printf("S\n"); }
};
struct T: public S {
void virtua() { printf("T\n"); }
};
int main() {
S *s = new T();
typedef void (S::*Func_p)(int);
Func_p p = &S::set<int>;
(s->*p)(12);
typedef void (S::*Vunc_p)(void);
Vunc_p q = &S::virtua;
(s->*q)(); // prints "T"
return 0;
}
*/
DiagnosticsEngine& Diag = getCI()->getDiagnostics();
Diag.setDiagnosticMapping(
clang::diag::ext_nested_name_member_ref_lookup_ambiguous,
clang::diag::MAP_IGNORE, SourceLocation());
LangOptions& LO = const_cast<LangOptions&>(getCI()->getLangOpts());
bool savedAccessControl = LO.AccessControl;
LO.AccessControl = withAccessControl;
cling::Transaction* T = 0;
cling::Interpreter::CompilationResult CR = declare(code, &T);
LO.AccessControl = savedAccessControl;
if (CR != cling::Interpreter::kSuccess)
return 0;
for (cling::Transaction::const_iterator I = T->decls_begin(),
E = T->decls_end(); I != E; ++I) {
if (I->m_Call != cling::Transaction::kCCIHandleTopLevelDecl)
continue;
if (const LinkageSpecDecl* LSD
= dyn_cast<LinkageSpecDecl>(*I->m_DGR.begin())) {
DeclContext::decl_iterator DeclBegin = LSD->decls_begin();
if (DeclBegin == LSD->decls_end())
continue;
if (const FunctionDecl* D = dyn_cast<FunctionDecl>(*DeclBegin)) {
const IdentifierInfo* II = D->getDeclName().getAsIdentifierInfo();
if (II && II->getName() == name)
return D;
}
}
}
return 0;
}
void*
Interpreter::compileFunction(llvm::StringRef name, llvm::StringRef code,
bool ifUnique, bool withAccessControl) {
//
// Compile the wrapper code.
//
const llvm::GlobalValue* GV = 0;
if (isInSyntaxOnlyMode())
return 0;
if (ifUnique)
GV = getLastTransaction()->getModule()->getNamedValue(name);
if (!GV) {
const FunctionDecl* FD = DeclareCFunction(name, code, withAccessControl);
if (!FD) return 0;
//
// Get the wrapper function pointer
// from the ExecutionEngine (the JIT).
//
GV = getLastTransaction()->getModule()->getNamedValue(name);
}
if (!GV)
return 0;
return m_Executor->getPointerToGlobalFromJIT(*GV);
}
void Interpreter::createUniqueName(std::string& out) {
out += utils::Synthesize::UniquePrefix;
llvm::raw_string_ostream(out) << m_UniqueCounter++;
}
bool Interpreter::isUniqueName(llvm::StringRef name) {
return name.startswith(utils::Synthesize::UniquePrefix);
}
llvm::StringRef Interpreter::createUniqueWrapper() {
const size_t size
= sizeof(utils::Synthesize::UniquePrefix) + sizeof(m_UniqueCounter);
llvm::SmallString<size> out(utils::Synthesize::UniquePrefix);
llvm::raw_svector_ostream(out) << m_UniqueCounter++;
return (getCI()->getASTContext().Idents.getOwn(out)).getName();
}
bool Interpreter::isUniqueWrapper(llvm::StringRef name) {
return name.startswith(utils::Synthesize::UniquePrefix);
}
Interpreter::CompilationResult
Interpreter::DeclareInternal(const std::string& input,
const CompilationOptions& CO,
Transaction** T /* = 0 */) const {
StateDebuggerRAII stateDebugger(this);
if (Transaction* lastT = m_IncrParser->Compile(input, CO)) {
if (lastT->getIssuedDiags() != Transaction::kErrors) {
if (T)
*T = lastT;
return Interpreter::kSuccess;
}
return Interpreter::kFailure;
}
// Even if the transaction was empty it is still success.
return Interpreter::kSuccess;
}
Interpreter::CompilationResult
Interpreter::EvaluateInternal(const std::string& input,
const CompilationOptions& CO,
Value* V, /* = 0 */
Transaction** T /* = 0 */) {
StateDebuggerRAII stateDebugger(this);
// Wrap the expression
std::string WrapperName;
std::string Wrapper = input;
WrapInput(Wrapper, WrapperName);
// 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 = m_IncrParser->getLastMemoryBufferEndLoc();
DiagnosticsEngine& Diags = getCI()->getDiagnostics();
Diags.pushMappings(Loc);
// The source locations of #pragma warning ignore must be greater than
// the ones from #pragma push
Loc = Loc.getLocWithOffset(1);
Diags.setDiagnosticMapping(clang::diag::warn_unused_expr,
clang::diag::MAP_IGNORE, Loc);
Diags.setDiagnosticMapping(clang::diag::warn_unused_call,
clang::diag::MAP_IGNORE, Loc);
Diags.setDiagnosticMapping(clang::diag::warn_unused_comparison,
clang::diag::MAP_IGNORE, Loc);
Diags.setDiagnosticMapping(clang::diag::ext_return_has_expr,
clang::diag::MAP_IGNORE, Loc);
if (Transaction* lastT = m_IncrParser->Compile(Wrapper, CO)) {
Loc = m_IncrParser->getLastMemoryBufferEndLoc().getLocWithOffset(1);
// if the location was the same we are in recursive calls and to avoid an
// assert in clang we should increment by a value.
if (SourceLocation::getFromRawEncoding(m_LastCustomPragmaDiagPopPoint)
== Loc)
// Nested #pragma pop-s must be on different source locations.
Loc = Loc.getLocWithOffset(1);
m_LastCustomPragmaDiagPopPoint = Loc.getRawEncoding();
Diags.popMappings(Loc);
assert((lastT->getState() == Transaction::kCommitted
|| lastT->getState() == Transaction::kRolledBack)
&& "Not committed?");
if (lastT->getIssuedDiags() != Transaction::kErrors) {
Value resultV;
if (!V)
V = &resultV;
if (!lastT->getWrapperFD()) // no wrapper to run
return Interpreter::kSuccess;
else if (RunFunction(lastT->getWrapperFD(), V) < kExeFirstError){
if (lastT->getCompilationOpts().ValuePrinting
!= CompilationOptions::VPDisabled
&& V->isValid()
// the !V->needsManagedAllocation() case is handled by
// dumpIfNoStorage.
&& V->needsManagedAllocation())
V->dump();
return Interpreter::kSuccess;
}
}
if (V)
*V = Value();
return Interpreter::kFailure;
}
Diags.popMappings(Loc.getLocWithOffset(1));
return Interpreter::kSuccess;
}
std::string Interpreter::lookupFileOrLibrary(llvm::StringRef file) {
std::string canonicalFile = DynamicLibraryManager::normalizePath(file);
if (canonicalFile.empty())
canonicalFile = file;
const FileEntry* FE = 0;
//Copied from clang's PPDirectives.cpp
bool isAngled = false;
// Clang doc says:
// "LookupFrom is set when this is a \#include_next directive, it
// specifies the file to start searching from."
const DirectoryLookup* LookupFrom = 0;
const DirectoryLookup* CurDir = 0;
Preprocessor& PP = getCI()->getPreprocessor();
// PP::LookupFile uses it to issue 'nice' diagnostic
SourceLocation fileNameLoc;
FE = PP.LookupFile(fileNameLoc, canonicalFile, isAngled, LookupFrom, CurDir,
/*SearchPath*/0, /*RelativePath*/ 0,
/*suggestedModule*/0, /*SkipCache*/false,
/*OpenFile*/ false, /*CacheFail*/ false);
if (FE)
return FE->getName();
return getDynamicLibraryManager()->lookupLibrary(canonicalFile);
}
Interpreter::CompilationResult
Interpreter::loadFile(const std::string& filename,
bool allowSharedLib /*=true*/) {
DynamicLibraryManager* DLM = getDynamicLibraryManager();
std::string canonicalLib = DLM->lookupLibrary(filename);
if (allowSharedLib && !canonicalLib.empty()) {
switch (DLM->loadLibrary(filename, /*permanent*/false)) {
case DynamicLibraryManager::kLoadLibSuccess: // Intentional fall through
case DynamicLibraryManager::kLoadLibAlreadyLoaded:
return kSuccess;
case DynamicLibraryManager::kLoadLibNotFound:
assert(0 && "Cannot find library with existing canonical name!");
return kFailure;
default:
// Not a source file (canonical name is non-empty) but can't load.
return kFailure;
}
}
std::string code;
code += "#include \"" + filename + "\"";
CompilationResult res = declare(code);
return res;
}
void Interpreter::unload(unsigned numberOfTransactions) {
while(true) {
cling::Transaction* T = m_IncrParser->getLastTransaction();
if (InterpreterCallbacks* callbacks = getCallbacks())
callbacks->TransactionUnloaded(*T);
if (m_Executor) // we also might be in fsyntax-only mode.
m_Executor->runAndRemoveStaticDestructors(T);
m_IncrParser->rollbackTransaction(T);
if (!--numberOfTransactions)
break;
}
}
void Interpreter::installLazyFunctionCreator(void* (*fp)(const std::string&)) {
m_Executor->installLazyFunctionCreator(fp);
}
Value Interpreter::Evaluate(const char* expr, DeclContext* DC,
bool ValuePrinterReq) {
Sema& TheSema = getCI()->getSema();
// The evaluation should happen on the global scope, because of the wrapper
// that is created.
//
// We can't PushDeclContext, because we don't have scope.
Sema::ContextRAII pushDC(TheSema,
TheSema.getASTContext().getTranslationUnitDecl());
Value Result;
getCallbacks()->SetIsRuntime(true);
if (ValuePrinterReq)
echo(expr, &Result);
else
evaluate(expr, Result);
getCallbacks()->SetIsRuntime(false);
return Result;
}
void Interpreter::setCallbacks(InterpreterCallbacks* C) {
// We need it to enable LookupObject callback.
m_Callbacks.reset(C);
// FIXME: We should add a multiplexer in the ASTContext, too.
llvm::IntrusiveRefCntPtr<ExternalASTSource>
astContextExternalSource(getSema().getExternalSource());
clang::ASTContext& Ctx = getSema().getASTContext();
// FIXME: This is a gross hack. We must make multiplexer in the astcontext,
// or a derived class that extends what we need.
Ctx.ExternalSource.resetWithoutRelease(); // FIXME: make sure we delete it.
Ctx.setExternalSource(astContextExternalSource);
if (DynamicLibraryManager* DLM = getDynamicLibraryManager())
DLM->setCallbacks(C);
}
const Transaction* Interpreter::getFirstTransaction() const {
return m_IncrParser->getFirstTransaction();
}
const Transaction* Interpreter::getLastTransaction() const {
return m_IncrParser->getLastTransaction();
}
const Transaction* Interpreter::getCurrentTransaction() const {
return m_IncrParser->getCurrentTransaction();
}
void Interpreter::enableDynamicLookup(bool value /*=true*/) {
m_DynamicLookupEnabled = value;
if (isDynamicLookupEnabled()) {
if (loadModuleForHeader("cling/Interpreter/DynamicLookupRuntimeUniverse.h")
!= kSuccess)
declare("#include \"cling/Interpreter/DynamicLookupRuntimeUniverse.h\"");
}
}
Interpreter::ExecutionResult
Interpreter::runStaticInitializersOnce(const Transaction& T) const {
assert(!isInSyntaxOnlyMode() && "Running on what?");
assert(T.getState() == Transaction::kCommitted && "Must be committed");
// Forward to IncrementalExecutor; should not be called by
// anyone except for IncrementalParser.
llvm::Module* module = m_IncrParser->getCodeGenerator()->GetModule();
IncrementalExecutor::ExecutionResult ExeRes
= m_Executor->runStaticInitializersOnce(module);
// Avoid eternal additions to llvm.ident; see
// CodeGenModule::EmitVersionIdentMetadata().
llvm::NamedMDNode *IdentMetadata = module->getNamedMetadata("llvm.ident");
if (IdentMetadata)
module->eraseNamedMetadata(IdentMetadata);
// Reset the module builder to clean up global initializers, c'tors, d'tors
ASTContext& C = getCI()->getASTContext();
m_IncrParser->getCodeGenerator()->HandleTranslationUnit(C);
return ConvertExecutionResult(ExeRes);
}
bool Interpreter::addSymbol(const char* symbolName, void* symbolAddress) {
// Forward to IncrementalExecutor;
if (!symbolName || !symbolAddress )
return false;
return m_Executor->addSymbol(symbolName, symbolAddress);
}
void* Interpreter::getAddressOfGlobal(const GlobalDecl& GD,
bool* fromJIT /*=0*/) const {
// Return a symbol's address, and whether it was jitted.
std::string mangledName;
utils::Analyze::maybeMangleDeclName(GD, mangledName);
return getAddressOfGlobal(mangledName.c_str(), fromJIT);
}
void* Interpreter::getAddressOfGlobal(llvm::StringRef SymName,
bool* fromJIT /*=0*/) const {
// Return a symbol's address, and whether it was jitted.
if (isInSyntaxOnlyMode())
return 0;
llvm::Module* module = getLastTransaction()->getModule();
return m_Executor->getAddressOfGlobal(module, SymName, fromJIT);
}
void Interpreter::AddAtExitFunc(void (*Func) (void*), void* Arg) {
m_Executor->AddAtExitFunc(Func, Arg, getLastTransaction());
}
void Interpreter::GenerateAutoloadingMap(llvm::StringRef inFile,
llvm::StringRef outFile) {
// cling::Transaction* T = 0;
// CompilationResult result = this->declare(std::string("#include \"")
// + std::string(inFile) + "\"", &T);
llvm::SmallVector<std::string,30> incpaths;
GetIncludePaths(incpaths,true,false);
CompilationOptions CO;
CO.DeclarationExtraction = 0;
CO.ValuePrinting = 0;
CO.ResultEvaluation = 0;
CO.DynamicScoping = 0;
CO.Debug = isPrintingDebug();
cling::Transaction* T = m_IncrParser->Parse
(std::string("#include \"") + std::string(inFile) + "\"", CO);
// if (result != CompilationResult::kSuccess) {
// llvm::outs() << "Compilation failure\n";
// return;
// }
std::string err;
llvm::raw_fd_ostream out(outFile.data(), err,
llvm::sys::fs::OpenFlags::F_None);
ForwardDeclPrinter visitor(out,getSema().getSourceManager());
for(auto dcit = T->decls_begin(); dcit != T->decls_end(); ++dcit) {
Transaction::DelayCallInfo& dci = *dcit;
if(dci.m_DGR.isNull()) {
break;
}
if (dci.m_Call == Transaction::kCCIHandleTopLevelDecl) {
for(auto dit = dci.m_DGR.begin(); dit != dci.m_DGR.end(); ++dit) {
clang::Decl* decl = *dit;
//skip logic start
bool skip = false;
auto filename = getSema().getSourceManager().getFilename
(decl->getSourceRange().getBegin());
auto path = llvm::sys::path::parent_path(filename);
for (auto p : incpaths) {
if (llvm::sys::fs::equivalent(p,path)
|| llvm::sys::fs::equivalent
(p,llvm::sys::path::parent_path(path))) {
skip = true;
break;
}
}
if (skip)
continue;
//skip logic end
visitor.Visit(decl);
out << ";\n";
}
}
}
T->setState(Transaction::kCommitted);
return;
}
} //end namespace cling