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(); // 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); }
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::BuildDynamicExprInfo(Expr* SubTree, bool ValuePrinterReq) { // 1. Find the DynamicExprInfo class CXXRecordDecl* ExprInfo = cast_or_null<CXXRecordDecl>(m_Interpreter->LookupDecl("cling"). LookupDecl("DynamicExprInfo"). getSingleDecl()); assert(ExprInfo && "DynamicExprInfo declaration not found!"); // 2. 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(); // 3. Build the template Expr* ExprTemplate = ConstructConstCharPtrExpr(Template.c_str()); // 4. Build the array of addresses QualType VarAddrTy = m_Sema->BuildArrayType(m_Context->VoidPtrTy, ArrayType::Normal, /*ArraySize*/0, Qualifiers(), m_NoRange, DeclarationName() ); ASTOwningVector<Expr*> Inits(*m_Sema); 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, move_arg(Inits), m_NoELoc).takeAs<InitListExpr>(); Expr* ExprAddresses = m_Sema->BuildCompoundLiteralExpr(m_NoSLoc, m_Context->CreateTypeSourceInfo(VarAddrTy), 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(); ASTOwningVector<Expr*> CtorArgs(*m_Sema); CtorArgs.push_back(ExprTemplate); CtorArgs.push_back(ExprAddresses); CtorArgs.push_back(VPReq); // 5. Call the constructor QualType ExprInfoTy = m_Context->getTypeDeclType(ExprInfo); ExprResult Initializer = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc, move_arg(CtorArgs)); Expr* Result = m_Sema->BuildCXXNew(m_NoSLoc, /*UseGlobal=*/false, m_NoSLoc, /*PlacementArgs=*/MultiExprArg(), m_NoELoc, m_NoRange, ExprInfoTy, m_Context->CreateTypeSourceInfo(ExprInfoTy), /*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; }