//------------------------------------------------------------------------------ // CLING - the C++ LLVM-based InterpreterG :) // author: Vassil Vassilev // // 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& m_Addresses; Sema* m_Sema; public: StmtPrinterHelper(const PrintingPolicy& Policy, llvm::SmallVector& 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(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(T.getTypePtr())) { OS << "(*)"; T = AT->getElementType(); while ((AT = dyn_cast(T))) { // TODO: Fix other types of arrays if (const ConstantArrayType* CAT = dyn_cast(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(*R.begin()); m_EvalDecl = dyn_cast(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(); 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(); 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(); 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(); 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(); 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(*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(*J) || !isa(*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()) // 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( 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()) { 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())); if (Stmt* ElseExpr = Node->getElse()) { ASTNodeInfo elseInfo = Visit(ElseExpr); if (elseInfo.isForReplacement()) Node->setElse(SubstituteUnknownSymbol(m_Context->VoidTy, elseInfo.getAs())); } 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()) { // 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(m_CurDeclContext)) valuePrinterReq = m_NestedCompoundStmts < 2 && utils::Analyze::IsWrapper(FD) && ((it+1) == Children.end() || ((it+2) == Children.end() && !isa(*(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(*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(Node->getSingleDecl()); assert(CuredDecl && "Not a variable declaration!"); QualType CuredDeclTy = CuredDecl->getType(); if (isa(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 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(); // 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()) // 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()) if (!IsArtificiallyDependent(LHSExpr)) { const QualType LHSTy = LHSExpr->getType(); Node->setRHS(SubstituteUnknownSymbol(LHSTy, rhs.castTo())); 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 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 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(SubTree)) OS << '('; SubTree->printPretty(OS, &helper, Policy); if (!isa(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 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(); 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 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& 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(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::ExtProtoInfo EPI = FPT->getExtProtoInfo(); llvm::ArrayRef 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(); 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(); assert (EvalCall && "Cannot create call to Eval"); return EvalCall; } // end EvalBuilder // Helpers // Class extracting recursively every decl defined somewhere. class DeclVisitor : public RecursiveASTVisitor { 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()) 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(); } 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