166032069e
Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
500 lines
20 KiB
C++
500 lines
20 KiB
C++
//------------------------------------------------------------------------------
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// author: Vassil Vassilev <vasil.georgiev.vasilev@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 "ValueExtractionSynthesizer.h"
|
|
|
|
#include "cling/Interpreter/Interpreter.h"
|
|
#include "cling/Interpreter/Transaction.h"
|
|
#include "cling/Interpreter/Value.h"
|
|
|
|
#include "cling/Utils/AST.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/DeclGroup.h"
|
|
#include "clang/AST/StmtVisitor.h"
|
|
#include "clang/Sema/Lookup.h"
|
|
#include "clang/Sema/Sema.h"
|
|
|
|
using namespace clang;
|
|
|
|
namespace cling {
|
|
ValueExtractionSynthesizer::ValueExtractionSynthesizer(clang::Sema* S)
|
|
: WrapperTransformer(S), m_Context(&S->getASTContext()), m_gClingVD(0),
|
|
m_UnresolvedNoAlloc(0), m_UnresolvedWithAlloc(0),
|
|
m_UnresolvedCopyArray(0) { }
|
|
|
|
// pin the vtable here.
|
|
ValueExtractionSynthesizer::~ValueExtractionSynthesizer() { }
|
|
|
|
namespace {
|
|
class ReturnStmtCollector : public StmtVisitor<ReturnStmtCollector> {
|
|
private:
|
|
llvm::SmallVectorImpl<Stmt**>& m_Stmts;
|
|
public:
|
|
ReturnStmtCollector(llvm::SmallVectorImpl<Stmt**>& S)
|
|
: m_Stmts(S) {}
|
|
|
|
void VisitStmt(Stmt* S) {
|
|
for(Stmt::child_iterator I = S->child_begin(), E = S->child_end();
|
|
I != E; ++I) {
|
|
if (!*I)
|
|
continue;
|
|
if (isa<LambdaExpr>(*I))
|
|
continue;
|
|
Visit(*I);
|
|
if (isa<ReturnStmt>(*I))
|
|
m_Stmts.push_back(&*I);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
ASTTransformer::Result ValueExtractionSynthesizer::Transform(clang::Decl* D) {
|
|
const CompilationOptions& CO = getCompilationOpts();
|
|
// If we do not evaluate the result, or printing out the result return.
|
|
if (!(CO.ResultEvaluation || CO.ValuePrinting))
|
|
return Result(D, true);
|
|
|
|
FunctionDecl* FD = cast<FunctionDecl>(D);
|
|
assert(utils::Analyze::IsWrapper(FD) && "Expected wrapper");
|
|
|
|
int foundAtPos = -1;
|
|
Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
|
|
/*omitDS*/false,
|
|
m_Sema);
|
|
if (foundAtPos < 0)
|
|
return Result(D, true);
|
|
|
|
typedef llvm::SmallVector<Stmt**, 4> StmtIters;
|
|
StmtIters returnStmts;
|
|
ReturnStmtCollector collector(returnStmts);
|
|
CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
|
|
collector.VisitStmt(CS);
|
|
|
|
if (isa<Expr>(*(CS->body_begin() + foundAtPos)))
|
|
returnStmts.push_back(CS->body_begin() + foundAtPos);
|
|
|
|
// We want to support cases such as:
|
|
// gCling->evaluate("if() return 'A' else return 12", V), that puts in V,
|
|
// either A or 12.
|
|
// In this case the void wrapper is compiled with the stmts returning
|
|
// values. Sema would cast them to void, but the code will still be
|
|
// executed. For example:
|
|
// int g(); void f () { return g(); } will still call g().
|
|
//
|
|
for (StmtIters::iterator I = returnStmts.begin(), E = returnStmts.end();
|
|
I != E; ++I) {
|
|
ReturnStmt* RS = dyn_cast<ReturnStmt>(**I);
|
|
if (RS) {
|
|
// When we are handling a return stmt, the last expression must be the
|
|
// return stmt value. Ignore the calculation of the lastStmt because it
|
|
// might be wrong, in cases where the return is not in the end of the
|
|
// function.
|
|
lastExpr = RS->getRetValue();
|
|
if (lastExpr) {
|
|
assert (lastExpr->getType()->isVoidType() && "Must be void type.");
|
|
// Any return statement will have been "healed" by Sema
|
|
// to correspond to the original void return type of the
|
|
// wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
|
|
// Remove that.
|
|
if (ImplicitCastExpr* VoidCast
|
|
= dyn_cast<ImplicitCastExpr>(lastExpr)) {
|
|
lastExpr = VoidCast->getSubExpr();
|
|
}
|
|
}
|
|
// if no value assume void
|
|
else {
|
|
// We can't PushDeclContext, because we don't have scope.
|
|
Sema::ContextRAII pushedDC(*m_Sema, FD);
|
|
RS->setRetValue(SynthesizeSVRInit(0));
|
|
}
|
|
|
|
}
|
|
else
|
|
lastExpr = cast<Expr>(**I);
|
|
|
|
if (lastExpr) {
|
|
QualType lastExprTy = lastExpr->getType();
|
|
// May happen on auto types which resolve to dependent.
|
|
if (lastExprTy->isDependentType())
|
|
continue;
|
|
// Set up lastExpr properly.
|
|
// Change the void function's return type
|
|
// We can't PushDeclContext, because we don't have scope.
|
|
Sema::ContextRAII pushedDC(*m_Sema, FD);
|
|
|
|
if (lastExprTy->isFunctionType()) {
|
|
// A return type of function needs to be converted to
|
|
// pointer to function.
|
|
lastExprTy = m_Context->getPointerType(lastExprTy);
|
|
lastExpr = m_Sema->ImpCastExprToType(lastExpr, lastExprTy,
|
|
CK_FunctionToPointerDecay,
|
|
VK_RValue).get();
|
|
}
|
|
|
|
//
|
|
// Here we don't want to depend on the JIT runFunction, because of its
|
|
// limitations, when it comes to return value handling. There it is
|
|
// not clear who provides the storage and who cleans it up in a
|
|
// platform independent way.
|
|
//
|
|
// Depending on the type we need to synthesize a call to cling:
|
|
// 0) void : set the value's type to void;
|
|
// 1) enum, integral, float, double, referece, pointer types :
|
|
// call to cling::internal::setValueNoAlloc(...);
|
|
// 2) object type (alloc on the stack) :
|
|
// cling::internal::setValueWithAlloc
|
|
// 2.1) constant arrays:
|
|
// call to cling::runtime::internal::copyArray(...)
|
|
//
|
|
// We need to synthesize later:
|
|
// Wrapper has signature: void w(cling::Value SVR)
|
|
// case 1):
|
|
// setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr())
|
|
// case 2):
|
|
// new (setValueWithAlloc(gCling, &SVR, lastExprTy)) (lastExpr)
|
|
// case 2.1):
|
|
// copyArray(src, placement, size)
|
|
|
|
Expr* SVRInit = SynthesizeSVRInit(lastExpr);
|
|
// if we had return stmt update to execute the SVR init, even if the
|
|
// wrapper returns void.
|
|
if (RS) {
|
|
if (ImplicitCastExpr* VoidCast
|
|
= dyn_cast<ImplicitCastExpr>(RS->getRetValue()))
|
|
VoidCast->setSubExpr(SVRInit);
|
|
}
|
|
else
|
|
**I = SVRInit;
|
|
}
|
|
}
|
|
return Result(D, true);
|
|
}
|
|
|
|
// Helper function for the SynthesizeSVRInit
|
|
namespace {
|
|
static bool availableCopyConstructor(QualType QT, clang::Sema* S) {
|
|
// Check the the existance of the copy constructor the tha placement new will use.
|
|
if (CXXRecordDecl* RD = QT->getAsCXXRecordDecl()) {
|
|
// If it has a trivial copy constructor it is accessible and it is callable.
|
|
if(RD->hasTrivialCopyConstructor()) return true;
|
|
// Lookup the copy canstructor and check its accessiblity.
|
|
if (CXXConstructorDecl* CD = S->LookupCopyingConstructor(RD, QT.getCVRQualifiers())) {
|
|
if (!CD->isDeleted() && CD ->getAccess() == clang::AccessSpecifier::AS_public) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) {
|
|
if (!m_gClingVD)
|
|
FindAndCacheRuntimeDecls();
|
|
|
|
// Build a reference to gCling
|
|
ExprResult gClingDRE
|
|
= m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
|
|
VK_RValue, SourceLocation());
|
|
// We have the wrapper as Sema's CurContext
|
|
FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);
|
|
|
|
ExprWithCleanups* Cleanups = 0;
|
|
// In case of ExprWithCleanups we need to extend its 'scope' to the call.
|
|
if (E && isa<ExprWithCleanups>(E)) {
|
|
Cleanups = cast<ExprWithCleanups>(E);
|
|
E = Cleanups->getSubExpr();
|
|
}
|
|
|
|
// Build a reference to Value* in the wrapper, should be
|
|
// the only argument of the wrapper.
|
|
SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart();
|
|
SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd();
|
|
ExprResult wrapperSVRDRE
|
|
= m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
|
|
VK_RValue, locStart);
|
|
QualType ETy = (E) ? E->getType() : m_Context->VoidTy;
|
|
QualType desugaredTy = ETy.getDesugaredType(*m_Context);
|
|
|
|
// The expr result is transported as reference, pointer, array, float etc
|
|
// based on the desugared type. We should still expose the typedef'ed
|
|
// (sugared) type to the cling::Value.
|
|
if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) {
|
|
// returning a lvalue (not a temporary): the value should contain
|
|
// a reference to the lvalue instead of copying it.
|
|
desugaredTy = m_Context->getLValueReferenceType(desugaredTy);
|
|
ETy = m_Context->getLValueReferenceType(ETy);
|
|
}
|
|
Expr* ETyVP
|
|
= utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
|
|
(uint64_t)ETy.getAsOpaquePtr());
|
|
|
|
// Pass whether to Value::dump() or not:
|
|
Expr* EVPOn
|
|
= new (*m_Context) CharacterLiteral(getCompilationOpts().ValuePrinting,
|
|
CharacterLiteral::Ascii,
|
|
m_Context->CharTy,
|
|
SourceLocation());
|
|
|
|
llvm::SmallVector<Expr*, 6> CallArgs;
|
|
CallArgs.push_back(gClingDRE.get());
|
|
CallArgs.push_back(wrapperSVRDRE.get());
|
|
CallArgs.push_back(ETyVP);
|
|
CallArgs.push_back(EVPOn);
|
|
|
|
ExprResult Call;
|
|
SourceLocation noLoc;
|
|
if (desugaredTy->isVoidType()) {
|
|
// In cases where the cling::Value gets reused we need to reset the
|
|
// previous settings to void.
|
|
// We need to synthesize setValueNoAlloc(...), E, because we still need
|
|
// to run E.
|
|
|
|
// FIXME: Suboptimal: this discards the already created AST nodes.
|
|
QualType vpQT = m_Context->VoidPtrTy;
|
|
QualType vQT = m_Context->VoidTy;
|
|
Expr* vpQTVP
|
|
= utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT,
|
|
(uint64_t)vQT.getAsOpaquePtr());
|
|
CallArgs[2] = vpQTVP;
|
|
|
|
|
|
Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
|
|
locStart, CallArgs, locEnd);
|
|
|
|
if (E)
|
|
Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.get(), E);
|
|
|
|
}
|
|
else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()
|
|
|| desugaredTy->isMemberPointerType()) {
|
|
// 2) object types :
|
|
// check existance of copy constructor before call
|
|
if (!desugaredTy->isMemberPointerType()
|
|
&& !availableCopyConstructor(desugaredTy, m_Sema))
|
|
return E;
|
|
// call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
|
|
Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
|
|
locStart, CallArgs, locEnd);
|
|
Expr* placement = Call.get();
|
|
if (const ConstantArrayType* constArray
|
|
= dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) {
|
|
CallArgs.clear();
|
|
CallArgs.push_back(E);
|
|
CallArgs.push_back(placement);
|
|
uint64_t arrSize
|
|
= m_Context->getConstantArrayElementCount(constArray);
|
|
Expr* arrSizeExpr
|
|
= utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);
|
|
|
|
CallArgs.push_back(arrSizeExpr);
|
|
// 2.1) arrays:
|
|
// call copyArray(T* src, void* placement, int size)
|
|
Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
|
|
locStart, CallArgs, locEnd);
|
|
|
|
}
|
|
else {
|
|
TypeSourceInfo* ETSI
|
|
= m_Context->getTrivialTypeSourceInfo(ETy, noLoc);
|
|
|
|
Call = m_Sema->BuildCXXNew(E->getSourceRange(),
|
|
/*useGlobal ::*/true,
|
|
/*placementLParen*/ noLoc,
|
|
MultiExprArg(placement),
|
|
/*placementRParen*/ noLoc,
|
|
/*TypeIdParens*/ SourceRange(),
|
|
/*allocType*/ ETSI->getType(),
|
|
/*allocTypeInfo*/ETSI,
|
|
/*arraySize*/0,
|
|
/*directInitRange*/E->getSourceRange(),
|
|
/*initializer*/E,
|
|
/*mayContainAuto*/false
|
|
);
|
|
}
|
|
}
|
|
else if (desugaredTy->isIntegralOrEnumerationType()
|
|
|| desugaredTy->isReferenceType()
|
|
|| desugaredTy->isPointerType()
|
|
|| desugaredTy->isNullPtrType()
|
|
|| desugaredTy->isFloatingType()) {
|
|
if (desugaredTy->isIntegralOrEnumerationType()) {
|
|
// 1) enum, integral, float, double, referece, pointer types :
|
|
// call to cling::internal::setValueNoAlloc(...);
|
|
|
|
// If the type is enum or integral we need to force-cast it into
|
|
// uint64 in order to pick up the correct overload.
|
|
if (desugaredTy->isIntegralOrEnumerationType()) {
|
|
QualType UInt64Ty = m_Context->UnsignedLongLongTy;
|
|
TypeSourceInfo* TSI
|
|
= m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
|
|
Expr* castedE
|
|
= m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get();
|
|
CallArgs.push_back(castedE);
|
|
}
|
|
}
|
|
else if (desugaredTy->isReferenceType()) {
|
|
// we need to get the address of the references
|
|
Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
|
|
E).get();
|
|
CallArgs.push_back(AddrOfE);
|
|
}
|
|
else if (desugaredTy->isPointerType()) {
|
|
// function pointers need explicit void* cast.
|
|
QualType VoidPtrTy = m_Context->VoidPtrTy;
|
|
TypeSourceInfo* TSI
|
|
= m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
|
|
Expr* castedE
|
|
= m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get();
|
|
CallArgs.push_back(castedE);
|
|
}
|
|
else if (desugaredTy->isNullPtrType()) {
|
|
// nullptr should decay to void* just fine.
|
|
CallArgs.push_back(E);
|
|
}
|
|
else if (desugaredTy->isFloatingType()) {
|
|
// floats and double will fall naturally in the correct
|
|
// case, because of the overload resolution.
|
|
CallArgs.push_back(E);
|
|
}
|
|
Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
|
|
locStart, CallArgs, locEnd);
|
|
}
|
|
else
|
|
assert(0 && "Unhandled code path?");
|
|
|
|
assert(!Call.isInvalid() && "Invalid Call");
|
|
|
|
// Extend the scope of the temporary cleaner if applicable.
|
|
if (Cleanups) {
|
|
Cleanups->setSubExpr(Call.get());
|
|
Cleanups->setValueKind(Call.get()->getValueKind());
|
|
Cleanups->setType(Call.get()->getType());
|
|
return Cleanups;
|
|
}
|
|
return Call.get();
|
|
}
|
|
|
|
void ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() {
|
|
assert(!m_gClingVD && "Called multiple times!?");
|
|
DeclContext* NSD = m_Context->getTranslationUnitDecl();
|
|
if (m_Sema->getLangOpts().CPlusPlus) {
|
|
NSD = utils::Lookup::Namespace(m_Sema, "cling");
|
|
NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD);
|
|
m_gClingVD = cast<VarDecl>(utils::Lookup::Named(m_Sema, "gCling", NSD));
|
|
NSD = utils::Lookup::Namespace(m_Sema, "internal",NSD);
|
|
}
|
|
LookupResult R(*m_Sema, &m_Context->Idents.get("setValueNoAlloc"),
|
|
SourceLocation(), Sema::LookupOrdinaryName,
|
|
Sema::ForRedeclaration);
|
|
|
|
m_Sema->LookupQualifiedName(R, NSD);
|
|
assert(!R.empty()
|
|
&& "Cannot find cling::runtime::internal::setValueNoAlloc");
|
|
|
|
CXXScopeSpec CSS;
|
|
m_UnresolvedNoAlloc
|
|
= m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get();
|
|
|
|
R.clear();
|
|
R.setLookupName(&m_Context->Idents.get("setValueWithAlloc"));
|
|
m_Sema->LookupQualifiedName(R, NSD);
|
|
assert(!R.empty()
|
|
&& "Cannot find cling::runtime::internal::setValueWithAlloc");
|
|
m_UnresolvedWithAlloc
|
|
= m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get();
|
|
|
|
R.clear();
|
|
R.setLookupName(&m_Context->Idents.get("copyArray"));
|
|
m_Sema->LookupQualifiedName(R, NSD);
|
|
assert(!R.empty() && "Cannot find cling::runtime::internal::copyArray");
|
|
m_UnresolvedCopyArray
|
|
= m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get();
|
|
}
|
|
} // end namespace cling
|
|
|
|
|
|
// Provide implementation of the functions that ValueExtractionSynthesizer calls
|
|
namespace {
|
|
|
|
static void dumpIfNoStorage(void* vpV, char vpOn) {
|
|
const cling::Value& V = *(cling::Value*)vpV;
|
|
// If the value copies over the temporary we must delay the printing until
|
|
// the temporary gets copied over. For the rest of the temporaries we *must*
|
|
// dump here because their lifetime will be gone otherwise. Eg.
|
|
//
|
|
// std::string f(); f().c_str() // have to dump during the same stmt.
|
|
//
|
|
assert(!V.needsManagedAllocation() && "Must contain non managed temporary");
|
|
assert(vpOn != (char)cling::CompilationOptions::VPAuto
|
|
&& "VPAuto must have been expanded earlier.");
|
|
if (vpOn == (char)cling::CompilationOptions::VPEnabled)
|
|
V.dump();
|
|
}
|
|
|
|
///\brief Allocate the Value and return the Value
|
|
/// for an expression evaluated at the prompt.
|
|
///
|
|
///\param [in] interp - The cling::Interpreter to allocate the SToredValueRef.
|
|
///\param [in] vpQT - The opaque ptr for the clang::QualType of value stored.
|
|
///\param [out] vpStoredValRef - The Value that is allocated.
|
|
static cling::Value&
|
|
allocateStoredRefValueAndGetGV(void* vpI, void* vpSVR, void* vpQT) {
|
|
cling::Interpreter* i = (cling::Interpreter*)vpI;
|
|
clang::QualType QT = clang::QualType::getFromOpaquePtr(vpQT);
|
|
cling::Value& SVR = *(cling::Value*)vpSVR;
|
|
// Here the copy keeps the refcounted value alive.
|
|
SVR = cling::Value(QT, *i);
|
|
return SVR;
|
|
}
|
|
}
|
|
namespace cling {
|
|
namespace runtime {
|
|
namespace internal {
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn) {
|
|
// In cases of void we 'just' need to change the type of the value.
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT);
|
|
}
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn,
|
|
float value) {
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT).getAs<float>() = value;
|
|
dumpIfNoStorage(vpSVR, vpOn);
|
|
}
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn,
|
|
double value) {
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT).getAs<double>() = value;
|
|
dumpIfNoStorage(vpSVR, vpOn);
|
|
}
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn,
|
|
long double value) {
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT).getAs<long double>()
|
|
= value;
|
|
dumpIfNoStorage(vpSVR, vpOn);
|
|
}
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn,
|
|
unsigned long long value) {
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT)
|
|
.getAs<unsigned long long>() = value;
|
|
dumpIfNoStorage(vpSVR, vpOn);
|
|
}
|
|
void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn,
|
|
const void* value){
|
|
allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT).getAs<void*>()
|
|
= const_cast<void*>(value);
|
|
dumpIfNoStorage(vpSVR, vpOn);
|
|
}
|
|
void* setValueWithAlloc(void* vpI, void* vpSVR, void* vpQT, char vpOn) {
|
|
return allocateStoredRefValueAndGetGV(vpI, vpSVR, vpQT).getAs<void*>();
|
|
}
|
|
} // end namespace internal
|
|
} // end namespace runtime
|
|
} // end namespace cling
|