/// 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); } } }
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()); } } }