rustc: Teach rustc to use block results as fn return values. Closes #372
This commit is contained in:
parent
223c7dfb11
commit
9daa00bf83
6 changed files with 141 additions and 3 deletions
|
|
@ -6892,7 +6892,14 @@ fn trans_fn(@local_ctxt cx, &ast::span sp, &ast::_fn f, ast::def_id fid,
|
|||
|
||||
auto lltop = bcx.llbb;
|
||||
|
||||
auto res = trans_block(bcx, f.body, return);
|
||||
auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
|
||||
auto res = if (!ty::type_is_nil(cx.ccx.tcx, block_ty)
|
||||
&& !ty::type_is_bot(cx.ccx.tcx, block_ty)) {
|
||||
trans_block(bcx, f.body, save_in(fcx.llretptr))
|
||||
} else {
|
||||
trans_block(bcx, f.body, return)
|
||||
};
|
||||
|
||||
if (!is_terminated(res.bcx)) {
|
||||
// FIXME: until LLVM has a unit type, we are moving around
|
||||
// C_nil values rather than their void type.
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ import front::ast::stmt_expr;
|
|||
import front::ast::block;
|
||||
import front::ast::block_;
|
||||
|
||||
import middle::ty::expr_ann;
|
||||
|
||||
import util::common::new_def_hash;
|
||||
import util::common::decl_lhs;
|
||||
import util::common::uistr;
|
||||
|
|
@ -696,6 +698,15 @@ fn find_pre_post_block(&fn_ctxt fcx, block b) -> () {
|
|||
|
||||
fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) -> () {
|
||||
find_pre_post_block(fcx, f.body);
|
||||
|
||||
// Treat the tail expression as a return statement
|
||||
alt (f.body.node.expr) {
|
||||
case (some(?tailexpr)) {
|
||||
auto tailann = expr_ann(tailexpr);
|
||||
set_postcond_false(fcx.ccx, tailann);
|
||||
}
|
||||
case (none) { /* fallthrough */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_pre_post(crate_ctxt ccx, &_fn f, &span sp, &ident i, &def_id id,
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ import front::ast::stmt_expr;
|
|||
import front::ast::block;
|
||||
import front::ast::block_;
|
||||
|
||||
import middle::ty::expr_ann;
|
||||
import middle::ty::expr_ty;
|
||||
import middle::ty::type_is_nil;
|
||||
import middle::ty::type_is_bot;
|
||||
|
||||
import util::common::new_def_hash;
|
||||
import util::common::decl_lhs;
|
||||
import util::common::uistr;
|
||||
|
|
@ -753,8 +758,36 @@ fn find_pre_post_state_block(&fn_ctxt fcx, &prestate pres0, &block b)
|
|||
|
||||
fn find_pre_post_state_fn(&fn_ctxt fcx, &_fn f) -> bool {
|
||||
auto num_local_vars = num_locals(fcx.enclosing);
|
||||
ret find_pre_post_state_block(fcx,
|
||||
empty_prestate(num_local_vars), f.body);
|
||||
auto changed = find_pre_post_state_block(fcx,
|
||||
empty_prestate(num_local_vars), f.body);
|
||||
|
||||
// Treat the tail expression as a return statement
|
||||
alt (f.body.node.expr) {
|
||||
case (some(?tailexpr)) {
|
||||
auto tailann = expr_ann(tailexpr);
|
||||
auto tailty = expr_ty(fcx.ccx.tcx, tailexpr);
|
||||
|
||||
// Since blocks and alts and ifs that don't have results
|
||||
// implicitly result in nil, we have to be careful to not
|
||||
// interpret nil-typed block results as the result of a
|
||||
// function with some other return type
|
||||
if (!type_is_nil(fcx.ccx.tcx, tailty)
|
||||
&& !type_is_bot(fcx.ccx.tcx, tailty)) {
|
||||
|
||||
set_poststate_ann(fcx.ccx, tailann,
|
||||
false_postcond(num_local_vars));
|
||||
alt (fcx.enclosing.cf) {
|
||||
case (noreturn) {
|
||||
kill_poststate(fcx, tailann, fcx.id);
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none) { /* fallthrough */ }
|
||||
}
|
||||
|
||||
ret changed;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue