cling/lib/Interpreter/DynamicLookup.cpp
Axel Naumann cea02a82e7 From Vassil: substitute then / else (ROOT-6345).
VisitCompoundStmt correctly substitutes the child Stmts. When calling Visit()
on a Stmt, this substitution needs to be carried out by the caller: only
it knows what target type to request. This fixes the issue for if statements
which do not fall back to VisitStmt() because of the conditional being of bool
type. In principle we are still missing do / while statements, too - again due
to the conditional part.
2014-06-13 11:11:57 +02:00

921 lines
36 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 "DynamicLookup.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/DynamicExprInfo.h"
#include "cling/Interpreter/Value.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "cling/Interpreter/DynamicLookupLifetimeHandler.h"
using namespace clang;
namespace {
class StmtPrinterHelper : public PrinterHelper {
private:
PrintingPolicy m_Policy;
llvm::SmallVector<DeclRefExpr*, 4>& m_Addresses;
Sema* m_Sema;
public:
StmtPrinterHelper(const PrintingPolicy& Policy,
llvm::SmallVector<DeclRefExpr*, 4>& Addresses,
Sema* S) :
m_Policy(Policy), m_Addresses(Addresses), m_Sema(S) {}
virtual ~StmtPrinterHelper() {}
// Handle only DeclRefExprs since they are local and the call wrapper
// won't "see" them. Consequently we don't need to handle:
// * DependentScopeDeclRefExpr
// * CallExpr
// * MemberExpr
// * CXXDependentScopeMemberExpr
virtual bool handledStmt(Stmt* S, llvm::raw_ostream& OS) {
if (DeclRefExpr* Node = dyn_cast<DeclRefExpr>(S))
// Exclude the artificially dependent DeclRefExprs, created by the
// Lookup
if (!Node->isTypeDependent()) {
if (NestedNameSpecifier* Qualifier = Node->getQualifier())
Qualifier->print(OS, m_Policy);
m_Addresses.push_back(Node);
QualType T = Node->getType();
if (!T->isArrayType())
OS << '*';
OS << '(';
ASTContext &Ctx = m_Sema->getASTContext();
OS << Ctx.getBaseElementType(T).getAsString();
// We need to handle the arrays differently
if (const ArrayType* AT = dyn_cast<ArrayType>(T.getTypePtr())) {
OS << "(*)";
T = AT->getElementType();
while ((AT = dyn_cast<ArrayType>(T))) {
// TODO: Fix other types of arrays
if (const ConstantArrayType* CAT
= dyn_cast<ConstantArrayType>(AT))
OS <<'[' << CAT->getSize().getZExtValue() << ']';
T = AT->getElementType();
}
}
else
OS << '*';
// end
OS <<")@";
if (Node->hasExplicitTemplateArgs())
TemplateSpecializationType::PrintTemplateArgumentList(OS,
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
m_Policy);
if (Node->hasExplicitTemplateArgs())
assert((Node->getTemplateArgs() || Node->getNumTemplateArgs()) && \
"There shouldn't be template paramlist");
return true;
}
return false;
}
};
} // end anonymous namespace
namespace cling {
// Constructors
EvaluateTSynthesizer::EvaluateTSynthesizer(Sema* S)
: TransactionTransformer(S), m_EvalDecl(0), m_LifetimeHandlerDecl(0),
m_LHgetMemoryDecl(0), m_DynamicExprInfoDecl(0), m_DeclContextDecl(0),
m_gCling(0), m_CurDeclContext(0), m_Context(&S->getASTContext()),
m_UniqueNameCounter(0), m_NestedCompoundStmts(0)
{ }
// pin the vtable here.
EvaluateTSynthesizer::~EvaluateTSynthesizer()
{ }
void EvaluateTSynthesizer::Initialize() {
// Most of the declaration we are looking up are in cling::runtime::internal
NamespaceDecl* NSD = utils::Lookup::Namespace(m_Sema, "cling");
NamespaceDecl* clingRuntimeNSD
= utils::Lookup::Namespace(m_Sema, "runtime", NSD);
NSD = utils::Lookup::Namespace(m_Sema, "internal", clingRuntimeNSD);
// Find and set up EvaluateT
DeclarationName Name = &m_Context->Idents.get("EvaluateT");
LookupResult R(*m_Sema, Name, SourceLocation(), Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
assert(NSD && "There must be a valid namespace.");
m_Sema->LookupQualifiedName(R, NSD);
// We have specialized EvaluateT but we don't care because the templated
// decl is needed.
TemplateDecl* TplD = dyn_cast_or_null<TemplateDecl>(*R.begin());
m_EvalDecl = dyn_cast<FunctionDecl>(TplD->getTemplatedDecl());
assert(m_EvalDecl && "The Eval function not found!");
// Find the LifetimeHandler declaration
R.clear();
Name = &m_Context->Idents.get("LifetimeHandler");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
m_LifetimeHandlerDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_LifetimeHandlerDecl && "LifetimeHandler could not be found.");
// Find the LifetimeHandler::getMemory declaration
R.clear();
Name = &m_Context->Idents.get("getMemory");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, m_LifetimeHandlerDecl);
m_LHgetMemoryDecl = R.getAsSingle<CXXMethodDecl>();
assert(m_LHgetMemoryDecl && "LifetimeHandler::getMemory couldn't be found.");
// Find the DynamicExprInfo declaration
R.clear();
Name = &m_Context->Idents.get("DynamicExprInfo");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
m_DynamicExprInfoDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_DynamicExprInfoDecl && "DynExprInfo could not be found.");
// Find the DeclContext declaration
R.clear();
Name = &m_Context->Idents.get("DeclContext");
R.setLookupName(Name);
NamespaceDecl* clangNSD = utils::Lookup::Namespace(m_Sema, "clang");
m_Sema->LookupQualifiedName(R, clangNSD);
m_DeclContextDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_DeclContextDecl && "clang::DeclContext decl could not be found.");
// Find the gCling declaration
R.clear();
Name = &m_Context->Idents.get("gCling");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, clingRuntimeNSD);
m_gCling = R.getAsSingle<VarDecl>();
assert(m_gCling && "gCling decl could not be found.");
// Find and set the source locations to valid ones.
R.clear();
Name
= &m_Context->Idents.get(
"InterpreterGeneratedCodeDiagnosticsMaybeIncorrect");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
assert(!R.empty()
&& "Cannot find InterpreterGeneratedCodeDiagnosticsMaybeIncorrect");
NamedDecl* ND = R.getFoundDecl();
m_NoRange = ND->getSourceRange();
m_NoSLoc = m_NoRange.getBegin();
m_NoELoc = m_NoRange.getEnd();
}
void EvaluateTSynthesizer::Transform() {
if (!getTransaction()->getCompilationOpts().DynamicScoping)
return;
// Find DynamicLookup specific builtins
if (!m_EvalDecl) {
Initialize();
}
const Transaction* T = getTransaction();
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;
for (DeclGroupRef::const_iterator J = DCI.m_DGR.begin(),
JE = DCI.m_DGR.end(); J != JE; ++J)
if (ShouldVisit(*J) && (*J)->hasBody()) {
if (FunctionDecl* FD = dyn_cast<FunctionDecl>(*J)) {
// Set the decl context, which is needed by Evaluate.
m_CurDeclContext = FD;
ASTNodeInfo NewBody = Visit((*J)->getBody());
if (NewBody.hasErrorOccurred()) {
// Report unsupported feature.
DiagnosticsEngine& Diags = m_Sema->getDiagnostics();
unsigned diagID
= Diags.getCustomDiagID(DiagnosticsEngine::Error,
"Feature not supported yet");
Diags.Report(NewBody.getAsSingleNode()->getLocStart(), diagID);
return; // Signal a fatal error.
}
FD->setBody(NewBody.getAsSingleNode());
}
assert ((!isa<BlockDecl>(*J) || !isa<ObjCMethodDecl>(*J))
&& "Not implemented yet!");
}
}
//TODO: Check for error before returning.
}
// StmtVisitor
ASTNodeInfo EvaluateTSynthesizer::VisitStmt(Stmt* Node) {
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
ASTNodeInfo NewNode = Visit(*I);
assert(NewNode.hasSingleNode() &&
"Cannot have more than one stmt at that point");
if (NewNode.isForReplacement()) {
if (Expr* E = NewNode.getAs<Expr>())
// Assume void if still not escaped
*I = SubstituteUnknownSymbol(m_Context->VoidTy, E);
}
else {
*I = NewNode.getAsSingleNode();
}
}
}
return ASTNodeInfo(Node, 0);
}
// If the dynamic expression is in the conditional clause of the if
// assume that the return type is bool, because we know that
// everything in the condition of IfStmt is implicitly converted into bool
ASTNodeInfo EvaluateTSynthesizer::VisitIfStmt(IfStmt* Node) {
// See whether there is var defined. Eg: if (int i = f->call())
// It will fall into DeclStmt.
if (Node->getConditionVariableDeclStmt()) {
// Removing the const, which shouldn't be dangerous
VisitDeclStmt(const_cast<DeclStmt*>(
Node->getConditionVariableDeclStmt()));
}
// Handle the case where the dynamic expression is in the condition of the
// stmt.
ASTNodeInfo IfCondInfo = Visit(Node->getCond());
if (IfCondInfo.isForReplacement())
if (Expr* IfCondExpr = IfCondInfo.getAs<Expr>()) {
Node->setCond(SubstituteUnknownSymbol(m_Context->BoolTy, IfCondExpr));
//return ASTNodeInfo(Node, /*needs eval*/false);
}
// Visit the other parts - they will fall naturally into CompoundStmt
// where we know what to do. For Stmt, though, we need to substitute here,
// knowing the "target" type.
ASTNodeInfo thenInfo = Visit(Node->getThen());
if (thenInfo.isForReplacement())
Node->setThen(SubstituteUnknownSymbol(m_Context->VoidTy,
thenInfo.getAs<Expr>()));
if (Stmt* ElseExpr = Node->getElse()) {
ASTNodeInfo elseInfo = Visit(ElseExpr);
if (elseInfo.isForReplacement())
Node->setElse(SubstituteUnknownSymbol(m_Context->VoidTy,
elseInfo.getAs<Expr>()));
}
return ASTNodeInfo(Node, false);
}
ASTNodeInfo EvaluateTSynthesizer::VisitCompoundStmt(CompoundStmt* Node) {
++m_NestedCompoundStmts;
ASTNodes Children;
ASTNodes NewChildren;
if (GetChildren(Children, Node)) {
ASTNodes::iterator it;
for (it = Children.begin(); it != Children.end(); ++it) {
ASTNodeInfo NewNode = Visit(*it);
if (NewNode.hasErrorOccurred())
return NewNode; // abort.
if (!NewNode.hasSingleNode()) {
ASTNodes& NewStmts(NewNode.getNodes());
for(unsigned i = 0; i < NewStmts.size(); ++i)
NewChildren.push_back(NewStmts[i]);
Node->setStmts(*m_Context, NewChildren.data(), NewChildren.size());
// Resolve all 1:n replacements
Visit(Node);
}
else {
if (NewNode.isForReplacement()) {
if (Expr* E = NewNode.getAs<Expr>()) {
// Check whether value printer has been requested
bool valuePrinterReq = false;
// If this was the last or the last is not null stmt, means that
// we need to value print.
// If this is in a wrapper function's body then look for VP.
if (FunctionDecl* FD = dyn_cast<FunctionDecl>(m_CurDeclContext))
valuePrinterReq
= m_NestedCompoundStmts < 2 && utils::Analyze::IsWrapper(FD)
&& ((it+1) == Children.end() || ((it+2) == Children.end()
&& !isa<NullStmt>(*(it+1))));
// Assume void if still not escaped
NewChildren.push_back(SubstituteUnknownSymbol(m_Context->VoidTy,E,
valuePrinterReq));
}
}
else
NewChildren.push_back(*it);
}
}
}
Node->setStmts(*m_Context, NewChildren.data(), NewChildren.size());
--m_NestedCompoundStmts;
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) {
// Visit all the children, which are the contents of the DeclGroupRef
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
Expr* E = cast_or_null<Expr>(*I);
if (!E || !IsArtificiallyDependent(E))
continue;
//FIXME: don't assume there is only one decl.
assert(Node->isSingleDecl() && "There is more that one decl in stmt");
VarDecl* CuredDecl = cast_or_null<VarDecl>(Node->getSingleDecl());
assert(CuredDecl && "Not a variable declaration!");
QualType CuredDeclTy = CuredDecl->getType();
if (isa<AutoType>(CuredDeclTy)) {
ASTNodeInfo result(Node, false);
result.setErrorOccurred();
return result;
}
// check if the case is sometype * somevar = init;
// or some_builtin_type somevar = init;
if (CuredDecl->hasInit() &&
(CuredDeclTy->isAnyPointerType() || !CuredDeclTy->isRecordType())) {
*I = SubstituteUnknownSymbol(CuredDeclTy, CuredDecl->getInit());
continue;
}
// 1. Check whether this is the case of MyClass A(dep->symbol())
// 2. Insert the RuntimeUniverse's LifetimeHandler instance
// 3. Change the A's initializer to *(MyClass*)instance.getMemory()
// 4. Make A reference (&A)
// 5. Set the new initializer of A
if (CuredDeclTy->isLValueReferenceType())
continue;
// Set Sema's Current DeclContext to the one we need
DeclContext* OldDC = m_Sema->CurContext;
m_Sema->CurContext = CuredDecl->getDeclContext();
ASTNodeInfo NewNode;
// 2.1 Get unique name for the LifetimeHandler instance and
// initialize it
std::string UniqueName;
createUniqueName(UniqueName);
IdentifierInfo& II = m_Context->Idents.get(UniqueName);
// Prepare the initialization Exprs.
// We want to call LifetimeHandler(DynamicExprInfo* ExprInfo,
// DeclContext DC,
// const char* type)
// Interpreter* interp)
llvm::SmallVector<Expr*, 4> Inits;
// Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo
// DC,
// "MyClass"
// Interpreter* Interp)
// Build Arg0 DynamicExprInfo
Inits.push_back(BuildDynamicExprInfo(E));
// Build Arg1 DeclContext* DC
QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl);
Inits.push_back(utils::Synthesize::CStyleCastPtrExpr(m_Sema, DCTy,
(uint64_t)m_CurDeclContext)
);
// Build Arg2 llvm::StringRef
// Get the type of the type without specifiers
PrintingPolicy Policy(m_Context->getLangOpts());
Policy.SuppressTagKeyword = 1;
std::string Res;
CuredDeclTy.getAsStringInternal(Res, Policy);
Inits.push_back(ConstructConstCharPtrExpr(Res.c_str()));
// Build Arg3 cling::Interpreter
CXXScopeSpec CXXSS;
DeclarationNameInfo NameInfo(m_gCling->getDeclName(),
m_gCling->getLocStart());
Expr* gClingDRE
= m_Sema->BuildDeclarationNameExpr(CXXSS, NameInfo ,m_gCling).take();
Inits.push_back(gClingDRE);
// 2.3 Create a variable from LifetimeHandler.
QualType HandlerTy = m_Context->getTypeDeclType(m_LifetimeHandlerDecl);
TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(HandlerTy,
m_NoSLoc);
VarDecl* HandlerInstance = VarDecl::Create(*m_Context,
CuredDecl->getDeclContext(),
m_NoSLoc,
m_NoSLoc,
&II,
HandlerTy,
TSI,
SC_None);
// 2.4 Call the best-match constructor. The method does overload
// resolution of the constructors and then initializes the new
// variable with it
ExprResult InitExprResult
= m_Sema->ActOnParenListExpr(m_NoSLoc,
m_NoELoc,
Inits);
m_Sema->AddInitializerToDecl(HandlerInstance,
InitExprResult.take(),
/*DirectInit*/ true,
/*TypeMayContainAuto*/ false);
// 2.5 Register the instance in the enclosing context
CuredDecl->getDeclContext()->addDecl(HandlerInstance);
NewNode.addNode(new (m_Context)
DeclStmt(DeclGroupRef(HandlerInstance),
m_NoSLoc,
m_NoELoc)
);
// 3.1 Build a DeclRefExpr, which holds the object
DeclRefExpr* MemberExprBase
= m_Sema->BuildDeclRefExpr(HandlerInstance,
HandlerTy,
VK_LValue,
m_NoSLoc
).takeAs<DeclRefExpr>();
// 3.2 Create a MemberExpr to getMemory from its declaration.
CXXScopeSpec SS;
LookupResult MemberLookup(*m_Sema, m_LHgetMemoryDecl->getDeclName(),
m_NoSLoc, Sema::LookupMemberName);
// Add the declaration as if doesn't exist.
// TODO: Check whether this is the most appropriate variant
MemberLookup.addDecl(m_LHgetMemoryDecl, AS_public);
MemberLookup.resolveKind();
Expr* MemberExpr = m_Sema->BuildMemberReferenceExpr(MemberExprBase,
HandlerTy,
m_NoSLoc,
/*IsArrow=*/false,
SS,
m_NoSLoc,
/*FirstQualifierInScope=*/0,
MemberLookup,
/*TemplateArgs=*/0
).take();
// 3.3 Build the actual call
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
Expr* theCall = m_Sema->ActOnCallExpr(S,
MemberExpr,
m_NoSLoc,
MultiExprArg(),
m_NoELoc).take();
// Cast to the type LHS type
Expr* Result
= utils::Synthesize::CStyleCastPtrExpr(m_Sema, CuredDeclTy, theCall);
// Cast once more (dereference the cstyle cast)
Result = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_Deref, Result).take();
// 4.
CuredDecl->setType(m_Context->getLValueReferenceType(CuredDeclTy));
// 5.
CuredDecl->setInit(Result);
NewNode.addNode(Node);
// Restore Sema's original DeclContext
m_Sema->CurContext = OldDC;
return NewNode;
}
}
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitCXXDeleteExpr(CXXDeleteExpr* Node) {
ASTNodeInfo deleteArg = Visit(Node->getArgument());
return ASTNodeInfo(Node, /*needs eval*/deleteArg.isForReplacement());
}
ASTNodeInfo EvaluateTSynthesizer::VisitExpr(Expr* Node) {
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
ASTNodeInfo NewNode = Visit(*I);
assert(NewNode.hasSingleNode() &&
"Cannot have more than one stmt at that point");
if (NewNode.isForReplacement()) {
if (Expr *E = NewNode.getAs<Expr>())
// Assume void if still not escaped
*I = SubstituteUnknownSymbol(m_Context->VoidTy, E);
}
else {
*I = NewNode.getAsSingleNode();
}
}
}
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitBinaryOperator(BinaryOperator* Node) {
ASTNodeInfo rhs = Visit(Node->getRHS());
ASTNodeInfo lhs;
lhs = Visit(Node->getLHS());
assert((lhs.hasSingleNode() || rhs.hasSingleNode()) &&
"1:N replacements are not implemented yet!");
// Try find out the type of the left-hand-side of the operator
// and give the hint to the right-hand-side in order to replace the
// dependent symbol
if (Node->isAssignmentOp() && rhs.isForReplacement() &&
!lhs.isForReplacement()) {
if (Expr* LHSExpr = lhs.getAs<Expr>())
if (!IsArtificiallyDependent(LHSExpr)) {
const QualType LHSTy = LHSExpr->getType();
Node->setRHS(SubstituteUnknownSymbol(LHSTy, rhs.castTo<Expr>()));
Node->setTypeDependent(false);
Node->setValueDependent(false);
return ASTNodeInfo(Node, /*needs eval*/false);
}
}
return ASTNodeInfo(Node, IsArtificiallyDependent(Node));
}
ASTNodeInfo EvaluateTSynthesizer::VisitCallExpr(CallExpr* E) {
// FIXME: Maybe we need to handle the arguments
//ASTNodeInfo NewNode = Visit(E->getCallee());
return ASTNodeInfo (E, IsArtificiallyDependent(E));
}
ASTNodeInfo EvaluateTSynthesizer::VisitDeclRefExpr(DeclRefExpr* DRE) {
return ASTNodeInfo(DRE, IsArtificiallyDependent(DRE));
}
ASTNodeInfo EvaluateTSynthesizer::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr* Node) {
return ASTNodeInfo(Node, IsArtificiallyDependent(Node));
}
// end StmtVisitor
// EvalBuilder
Expr* EvaluateTSynthesizer::SubstituteUnknownSymbol(const QualType InstTy,
Expr* SubTree,
bool ValuePrinterReq) {
assert(SubTree && "No subtree specified!");
//Build the arguments for the call
llvm::SmallVector<Expr*, 2> CallArgs;
// Build Arg0
Expr* Arg0 = BuildDynamicExprInfo(SubTree, ValuePrinterReq);
CallArgs.push_back(Arg0);
// Build Arg1
QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl);
Expr* Arg1 = utils::Synthesize::CStyleCastPtrExpr(m_Sema, DCTy,
(uint64_t)m_CurDeclContext);
CallArgs.push_back(Arg1);
// Build the call
assert(Arg0 && Arg1 && "Arguments missing!");
CallExpr* EvalCall = BuildEvalCallExpr(InstTy, SubTree, CallArgs);
// Add substitution mapping
getSubstSymbolMap()[EvalCall] = SubTree;
return EvalCall;
}
Expr* EvaluateTSynthesizer::BuildDynamicExprInfo(Expr* SubTree,
bool ValuePrinterReq) {
// We need to evaluate it in its own context. Evaluation on the global
// scope per se can break for example the compound literals, which have
// to be constants (see [C99 6.5.2.5])
Sema::ContextRAII pushedDC(*m_Sema, m_CurDeclContext);
// 1. Get the expression containing @-s and get the variable addresses
std::string Template;
llvm::SmallVector<DeclRefExpr*, 4> Addresses;
llvm::raw_string_ostream OS(Template);
const PrintingPolicy& Policy = m_Context->getPrintingPolicy();
StmtPrinterHelper helper(Policy, Addresses, m_Sema);
// In case when we print non paren inits like int i = h->Draw();
// not int i(h->Draw()). This simplifies the LifetimeHandler's
// constructor, there we don't need to add parenthesis while
// wrapping the expression.
if (!isa<ParenListExpr>(SubTree))
OS << '(';
SubTree->printPretty(OS, &helper, Policy);
if (!isa<ParenListExpr>(SubTree))
OS << ')';
OS.flush();
// 2. Build the template
Expr* ExprTemplate = ConstructConstCharPtrExpr(Template.c_str());
// 3. Build the array of addresses
QualType VarAddrTy = m_Sema->BuildArrayType(m_Context->VoidPtrTy,
ArrayType::Normal,
/*ArraySize*/0,
/*IndexTypeQuals*/0,
m_NoRange,
DeclarationName() );
llvm::SmallVector<Expr*, 2> Inits;
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
for (unsigned int i = 0; i < Addresses.size(); ++i) {
Expr* UnOp
= m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_AddrOf, Addresses[i]).take();
m_Sema->ImpCastExprToType(UnOp,
m_Context->getPointerType(m_Context->VoidPtrTy),
CK_BitCast);
Inits.push_back(UnOp);
}
// We need valid source locations to avoid assert(InitList.isExplicit()...)
InitListExpr* ILE = m_Sema->ActOnInitList(m_NoSLoc,
Inits,
m_NoELoc).takeAs<InitListExpr>();
TypeSourceInfo* TSI
= m_Context->getTrivialTypeSourceInfo(VarAddrTy, m_NoSLoc);
Expr* ExprAddresses = m_Sema->BuildCompoundLiteralExpr(m_NoSLoc,
TSI,
m_NoELoc,
ILE).take();
assert (ExprAddresses && "Could not build the void* array");
m_Sema->ImpCastExprToType(ExprAddresses,
m_Context->getPointerType(m_Context->VoidPtrTy),
CK_ArrayToPointerDecay);
// Is the result of the expression to be printed or not
Expr* VPReq = 0;
if (ValuePrinterReq)
VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_true).take();
else
VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_false).take();
llvm::SmallVector<Expr*, 4> CtorArgs;
CtorArgs.push_back(ExprTemplate);
CtorArgs.push_back(ExprAddresses);
CtorArgs.push_back(VPReq);
// 4. Call the constructor
QualType ExprInfoTy = m_Context->getTypeDeclType(m_DynamicExprInfoDecl);
ExprResult Initializer = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc,
CtorArgs);
TypeSourceInfo* TrivialTSI
= m_Context->getTrivialTypeSourceInfo(ExprInfoTy, SourceLocation());
Expr* Result = m_Sema->BuildCXXNew(m_NoSLoc,
/*UseGlobal=*/false,
m_NoSLoc,
/*PlacementArgs=*/MultiExprArg(),
m_NoELoc,
m_NoRange,
ExprInfoTy,
TrivialTSI,
/*ArraySize=*/0,
//BuildCXXNew depends on the SLoc to be
//valid!
// TODO: Propose a patch in clang
m_NoRange,
Initializer.take(),
/*TypeMayContainAuto*/false
).take();
return Result;
}
Expr* EvaluateTSynthesizer::ConstructConstCharPtrExpr(const char* Val) {
const QualType CChar = m_Context->CharTy.withConst();
llvm::StringRef Value(Val);
unsigned bitSize = m_Context->getTypeSize(m_Context->VoidPtrTy);
llvm::APInt ArraySize(bitSize, Value.size() + 1);
const QualType CCArray = m_Context->getConstantArrayType(CChar,
ArraySize,
ArrayType::Normal,
/*IndexTypeQuals=*/0);
StringLiteral::StringKind Kind = StringLiteral::Ascii;
Expr* Result = StringLiteral::Create(*m_Context,
Value,
Kind,
/*Pascal=*/false,
CCArray,
m_NoSLoc);
m_Sema->ImpCastExprToType(Result,
m_Context->getPointerType(CChar),
CK_ArrayToPointerDecay);
return Result;
}
// Here is the test Eval function specialization. Here the CallExpr to the
// function is created.
CallExpr*
EvaluateTSynthesizer::BuildEvalCallExpr(const QualType InstTy,
Expr* SubTree,
llvm::SmallVector<Expr*, 2>& CallArgs) {
// Set up new context for the new FunctionDecl
DeclContext* PrevContext = m_Sema->CurContext;
m_Sema->CurContext = m_EvalDecl->getDeclContext();
// Create template arguments
Sema::InstantiatingTemplate Inst(*m_Sema, m_NoSLoc, m_EvalDecl);
// Before instantiation we need the canonical type
TemplateArgument Arg(InstTy.getCanonicalType());
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, &Arg, 1U);
// Substitute the declaration of the templated function, with the
// specified template argument
Decl* D = m_Sema->SubstDecl(m_EvalDecl,
m_EvalDecl->getDeclContext(),
MultiLevelTemplateArgumentList(TemplateArgs));
FunctionDecl* Fn = dyn_cast<FunctionDecl>(D);
// We expect incoming declarations (instantiations) and we
// need to open the transaction to collect them.
Transaction::State oldState = getTransaction()->getState();
getTransaction()->setState(Transaction::kCollecting);
// Creates new body of the substituted declaration
m_Sema->InstantiateFunctionDefinition(Fn->getLocation(), Fn, true, true);
m_Sema->CurContext = PrevContext;
const FunctionProtoType* FPT = Fn->getType()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
llvm::ArrayRef<QualType> ArgTypes(FPT->param_type_begin(),
FPT->getNumParams());
QualType FnTy = m_Context->getFunctionType(Fn->getReturnType(),
ArgTypes,
EPI);
DeclRefExpr* DRE = m_Sema->BuildDeclRefExpr(Fn,
FnTy,
VK_RValue,
m_NoSLoc
).takeAs<DeclRefExpr>();
getTransaction()->setState(oldState);
// TODO: Figure out a way to avoid passing in wrong source locations
// of the symbol being replaced. This is important when we calculate the
// size of the memory buffers and may lead to creation of wrong wrappers.
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
CallExpr* EvalCall = m_Sema->ActOnCallExpr(S,
DRE,
SubTree->getLocStart(),
CallArgs,
SubTree->getLocEnd()
).takeAs<CallExpr>();
assert (EvalCall && "Cannot create call to Eval");
return EvalCall;
}
// end EvalBuilder
// Helpers
// Class extracting recursively every decl defined somewhere.
class DeclVisitor : public RecursiveASTVisitor<DeclVisitor> {
private:
bool m_ShouldVisitSubTree;
public:
DeclVisitor() : m_ShouldVisitSubTree(false) {}
bool getShouldVisitSubTree() const { return m_ShouldVisitSubTree; }
bool isCandidate(Decl* D) {
// FIXME: Here we should have our custom attribute.
if (AnnotateAttr* A = D->getAttr<AnnotateAttr>())
if (A->getAnnotation().equals("__ResolveAtRuntime"))
return true;
return false;
}
bool VisitDeclStmt(DeclStmt* DS) {
DeclGroupRef DGR = DS->getDeclGroup();
for (DeclGroupRef::const_iterator I = DGR.begin(),
E = DGR.end(); I != E; ++I) {
if (isCandidate(*I)) {
m_ShouldVisitSubTree = true;
return false; // returning false will abort the in-depth traversal.
}
}
return true;
}
// In cases when there is no decl stmt, like dep->Call();
bool VisitDeclRefExpr(DeclRefExpr* DRE) {
if (isCandidate(DRE->getDecl())) {
m_ShouldVisitSubTree = true;
return false; // returning false will abort the in-depth traversal.
}
return true;
}
};
bool EvaluateTSynthesizer::ShouldVisit(Decl* D) {
DeclVisitor Visitor;
Visitor.TraverseStmt(D->getBody());
return Visitor.getShouldVisitSubTree();
}
bool EvaluateTSynthesizer::IsArtificiallyDependent(Expr* Node) {
if (!Node->isValueDependent() || !Node->isTypeDependent())
return false;
DeclContext* DC = m_CurDeclContext;
while (DC) {
if (DC->isDependentContext())
return false;
DC = DC->getParent();
}
return true;
}
bool EvaluateTSynthesizer::GetChildren(ASTNodes& Children, Stmt* Node) {
if (std::distance(Node->child_begin(), Node->child_end()) < 1)
return false;
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Children.push_back(*I);
}
return true;
}
void EvaluateTSynthesizer::createUniqueName(std::string& out) {
out = "__dynamic";
out += utils::Synthesize::UniquePrefix;
llvm::raw_string_ostream(out) << m_UniqueNameCounter++;
}
// end Helpers
namespace runtime {
namespace internal {
// Implementations from DynamicLookupLifetimeHandler.h
LifetimeHandler::LifetimeHandler(DynamicExprInfo* ExprInfo,
clang::DeclContext* DC,
const char* type,
Interpreter* Interp):
m_Interpreter(Interp), m_Type(type) {
std::string ctor("new ");
ctor += type;
ctor += ExprInfo->getExpr();
Value res = Interp->Evaluate(ctor.c_str(), DC,
ExprInfo->isValuePrinterRequested()
);
m_Memory = (void*)res.getAs<void*>();
}
LifetimeHandler::~LifetimeHandler() {
std::string str;
llvm::raw_string_ostream stream(str);
stream << "delete (" << m_Type << "*) " << m_Memory << ";";
stream.flush();
m_Interpreter->execute(str);
}
} // end namespace internal
} // end namespace runtime
} // end namespace cling