/// Adjust the given return statements so that they formally return /// the given type. It should require, at most, an IntegralCast. static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns, QualType returnType) { for (ArrayRef<ReturnStmt*>::iterator i = returns.begin(), e = returns.end(); i != e; ++i) { ReturnStmt *ret = *i; Expr *retValue = ret->getRetValue(); if (S.Context.hasSameType(retValue->getType(), returnType)) continue; // Right now we only support integral fixup casts. assert(returnType->isIntegralOrUnscopedEnumerationType()); assert(retValue->getType()->isIntegralOrUnscopedEnumerationType()); ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(retValue); Expr *E = (cleanups ? cleanups->getSubExpr() : retValue); E = ImplicitCastExpr::Create(S.Context, returnType, CK_IntegralCast, E, /*base path*/ 0, VK_RValue); if (cleanups) { cleanups->setSubExpr(E); } else { ret->setRetValue(E); } } }
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand /// if the function returns void, or may be missing one if the function returns /// non-void. Fun stuff :). void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // Emit the result value, even if unused, to evalute the side effects. const Expr *RV = S.getRetValue(); // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. if (!ReturnValue) { // Make sure not to return anything, but evaluate the expression // for side effects. if (RV) EmitAnyExpr(RV); } else if (RV == 0) { // Do nothing (return value is left uninitialized) } else if (FnRetTy->isReferenceType()) { // If this function returns a reference, take the address of the expression // rather than the value. Builder.CreateStore(EmitLValue(RV).getAddress(), ReturnValue); } else if (!hasAggregateLLVMType(RV->getType())) { Builder.CreateStore(EmitScalarExpr(RV), ReturnValue); } else if (RV->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(RV, ReturnValue, false); } else { EmitAggExpr(RV, ReturnValue, false); } EmitBranchThroughCleanup(ReturnBlock); }
void SimpleInliner::copyFunctionBody(void) { Stmt *Body = CurrentFD->getBody(); TransAssert(Body && "NULL Body!"); std::string FuncBodyStr(""); RewriteHelper->getStmtString(Body, FuncBodyStr); TransAssert(FuncBodyStr[0] == '{'); SourceLocation StartLoc = Body->getLocStart(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::vector< std::pair<ReturnStmt *, int> > SortedReturnStmts; sortReturnStmtsByOffs(StartBuf, SortedReturnStmts); // Now we start rewriting int Delta = 1; // skip the first { symbol FuncBodyStr.insert(Delta, "\n"); ++Delta; for(SmallVector<std::string, 10>::iterator I = ParmStrings.begin(), E = ParmStrings.end(); I != E; ++I) { std::string PStr = (*I); FuncBodyStr.insert(Delta, PStr); Delta += PStr.size(); } // restore the effect of { Delta--; int ReturnSZ = 6; std::string TmpVarStr = TmpVarName + " = "; int TmpVarNameSize = static_cast<int>(TmpVarStr.size()); for(std::vector< std::pair<ReturnStmt *, int> >::iterator I = SortedReturnStmts.begin(), E = SortedReturnStmts.end(); I != E; ++I) { ReturnStmt *RS = (*I).first; int Off = (*I).second + Delta; Expr *Exp = RS->getRetValue(); if (Exp) { const Type *T = Exp->getType().getTypePtr(); if (!T->isVoidType()) { FuncBodyStr.replace(Off, ReturnSZ, TmpVarStr); Delta += (TmpVarNameSize - ReturnSZ); continue; } } FuncBodyStr.replace(Off, ReturnSZ, ""); Delta -= ReturnSZ; } RewriteHelper->addStringBeforeStmt(TheStmt, FuncBodyStr, NeedParen); }
NamedDecl* RedundantLocalVariableRule::extractFromReturnStmt(Stmt *stmt) { ReturnStmt *returnStmt = dyn_cast<ReturnStmt>(stmt); if (returnStmt) { Expr *returnValue = returnStmt->getRetValue(); if (returnValue) { ImplicitCastExpr *implicitCastExpr = dyn_cast<ImplicitCastExpr>(returnValue); if (implicitCastExpr) { DeclRefExpr *returnExpr = dyn_cast<DeclRefExpr>(implicitCastExpr->getSubExpr()); if (returnExpr) { return returnExpr->getFoundDecl(); } } } } return NULL; }
void ValueExtractionSynthesizer::Transform() { const CompilationOptions& CO = getTransaction()->getCompilationOpts(); // If we do not evaluate the result, or printing out the result return. if (!(CO.ResultEvaluation || CO.ValuePrinting)) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (foundAtPos < 0) return; 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).take(); } // // 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; } } }
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { assert(CSI.HasImplicitReturnType); // First case: no return statements, implicit void return type. ASTContext &Ctx = getASTContext(); if (CSI.Returns.empty()) { // It's possible there were simply no /valid/ return statements. // In this case, the first one we found may have at least given us a type. if (CSI.ReturnType.isNull()) CSI.ReturnType = Ctx.VoidTy; return; } // Second case: at least one return statement has dependent type. // Delay type checking until instantiation. assert(!CSI.ReturnType.isNull() && "We should have a tentative return type."); if (CSI.ReturnType->isDependentType()) return; // Third case: only one return statement. Don't bother doing extra work! SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(), E = CSI.Returns.end(); if (I+1 == E) return; // General case: many return statements. // Check that they all have compatible return types. // For now, that means "identical", with an exception for enum constants. // (In C, enum constants have the type of their underlying integer type, // not the type of the enum. C++ uses the type of the enum.) QualType AlternateType; // We require the return types to strictly match here. for (; I != E; ++I) { const ReturnStmt *RS = *I; const Expr *RetE = RS->getRetValue(); if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) { // FIXME: This is a poor diagnostic for ReturnStmts without expressions. Diag(RS->getLocStart(), diag::err_typecheck_missing_return_type_incompatible) << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType << isa<LambdaScopeInfo>(CSI); // Don't bother fixing up the return statements in the block if some of // them are unfixable anyway. AlternateType = Ctx.VoidTy; // Continue iterating so that we keep emitting diagnostics. } } // If our return statements turned out to be compatible, but we needed to // pick a different return type, go through and fix the ones that need it. if (AlternateType == Ctx.DependentTy) { for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(), E = CSI.Returns.end(); I != E; ++I) { ReturnStmt *RS = *I; Expr *RetE = RS->getRetValue(); if (RetE->getType() == CSI.ReturnType) continue; // Right now we only support integral fixup casts. assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType()); assert(RetE->getType()->isIntegralOrUnscopedEnumerationType()); ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType, CK_IntegralCast); assert(Casted.isUsable()); RS->setRetValue(Casted.take()); } } }