ASTTransformer::Result NullDerefProtectionTransformer::Transform(clang::Decl* D) { if (getCompilationOpts().CheckPointerValidity) { PointerCheckInjector injector(*m_Interp); injector.TraverseDecl(D); } return Result(D, true); }
bool Transaction::comesFromASTReader(DeclGroupRef DGR) const { assert(!DGR.isNull() && "DeclGroupRef is Null!"); if (getCompilationOpts().CodeGenerationForModule) return true; // Take the first/only decl in the group. Decl* D = *DGR.begin(); return D->isFromASTFile(); }
ASTTransformer::Result ValuePrinterSynthesizer::Transform(clang::Decl* D) { if (getCompilationOpts().ValuePrinting == CompilationOptions::VPDisabled) return Result(D, true); FunctionDecl* FD = cast<FunctionDecl>(D); assert(utils::Analyze::IsWrapper(FD) && "Expected wrapper"); if (tryAttachVP(FD)) return Result(FD, true); return Result(0, false); }
void Transaction::append(DelayCallInfo DCI) { if (!DCI.m_DGR.isNull() && getState() == kCommitting) { // We are committing and getting enw decls in. // Move them into a sub transaction that will be processed // recursively at the end of of commitTransaction. Transaction* subTransactionWhileCommitting = 0; if (hasNestedTransactions() && m_NestedTransactions->back()->getState() == kCollecting) subTransactionWhileCommitting = m_NestedTransactions->back(); else { // FIXME: is this correct (Axel says "yes") CompilationOptions Opts(getCompilationOpts()); Opts.DeclarationExtraction = 0; Opts.ValuePrinting = CompilationOptions::VPDisabled; Opts.ResultEvaluation = 0; Opts.DynamicScoping = 0; subTransactionWhileCommitting = new Transaction(Opts, getModule()); addNestedTransaction(subTransactionWhileCommitting); } subTransactionWhileCommitting->append(DCI); return; } assert(DCI.m_DGR.isNull() || (getState() == kCollecting || getState() == kCompleted) || "Cannot append declarations in current state."); bool checkForWrapper = !m_WrapperFD; assert(checkForWrapper = true && "Check for wrappers with asserts"); // register the wrapper if any. if (checkForWrapper && !DCI.m_DGR.isNull() && DCI.m_DGR.isSingleDecl()) { if (FunctionDecl* FD = dyn_cast<FunctionDecl>(DCI.m_DGR.getSingleDecl())) if (utils::Analyze::IsWrapper(FD)) { assert(!m_WrapperFD && "Two wrappers in one transaction?"); m_WrapperFD = FD; } } // Lazy create the container on first append. if (!m_DeclQueue) m_DeclQueue.reset(new DeclQueue()); m_DeclQueue->push_back(DCI); }
bool ValuePrinterSynthesizer::tryAttachVP(FunctionDecl* FD) { // We have to be able to mark the expression for printout. There are // three scenarios: // 0: Expression printing disabled - don't do anything just exit. // 1: Expression printing enabled - print no matter what. // 2: Expression printing auto - analyze - rely on the omitted ';' to // not produce the suppress marker. int indexOfLastExpr = -1; Expr* To = utils::Analyze::GetOrCreateLastExpr(FD, &indexOfLastExpr, /*omitDS*/false, m_Sema); if (To) { // Update the CompoundStmt body, avoiding alloc/dealloc of all the el. CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); switch (getCompilationOpts().ValuePrinting) { case CompilationOptions::VPDisabled: assert(0 && "Don't wait that long. Exit early!"); break; case CompilationOptions::VPEnabled: break; case CompilationOptions::VPAuto: { // FIXME: Propagate the flag to the nested transactions also, they // must have the same CO as their parents. getCompilationOpts().ValuePrinting = CompilationOptions::VPEnabled; if ((int)CS->size() > indexOfLastExpr+1 && (*(CS->body_begin() + indexOfLastExpr + 1)) && isa<NullStmt>(*(CS->body_begin() + indexOfLastExpr + 1))) { // If next is NullStmt disable VP is disabled - exit. Signal this in // the CO of the transaction. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; } if (getCompilationOpts().ValuePrinting == CompilationOptions::VPDisabled) return true; } break; } // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); if (To) { // Strip the parenthesis if any if (ParenExpr* PE = dyn_cast<ParenExpr>(To)) To = PE->getSubExpr(); Expr* Result = 0; // if (!m_Sema->getLangOpts().CPlusPlus) // Result = SynthesizeVP(To); if (Result) *(CS->body_begin()+indexOfLastExpr) = Result; } // Clear the artificial NullStmt-s if (!ClearNullStmts(CS)) { // FIXME: Why it is here? Shouldn't it be in DeclExtractor? // if no body remove the wrapper DeclContext* DC = FD->getDeclContext(); Scope* S = m_Sema->getScopeForContext(DC); if (S) S->RemoveDecl(FD); DC->removeDecl(FD); } } else // if nothing to attach to set the CO's ValuePrinting to disabled. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; return true; }
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 if (SVRInit) **I = SVRInit; } } return Result(D, 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, (uintptr_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 = locStart; 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, (uintptr_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 existence 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); size_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, size_t size) Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray, locStart, CallArgs, locEnd); } else { if (!E->getSourceRange().isValid()) { // We cannot do CXXNewExpr::CallInit (see Sema::BuildCXXNew) but // that's what we want. Fail... return E; } 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 ); // Handle possible cleanups: Call = m_Sema->ActOnFinishFullExpr(Call.get()); } } else { // Mark the current number of arguemnts const size_t nArgs = CallArgs.size(); 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->isAnyPointerType()) { // 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); } // Test CallArgs.size to make sure an additional argument (the value) // has been pushed on, if not than we didn't know how to handle the type if (CallArgs.size() > nArgs) { Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc, locStart, CallArgs, locEnd); } else { m_Sema->Diag(locStart, diag::err_unsupported_unknown_any_decl) << utils::TypeName::GetFullyQualifiedName(desugaredTy, *m_Context) << SourceRange(locStart, locEnd); } } 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(); }