Skip to content

Commit 9daa00b

Browse files
committed
rustc: Teach rustc to use block results as fn return values. Closes #372
1 parent 223c7df commit 9daa00b

File tree

6 files changed

+141
-3
lines changed

6 files changed

+141
-3
lines changed

src/comp/middle/trans.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6892,7 +6892,14 @@ fn trans_fn(@local_ctxt cx, &ast::span sp, &ast::_fn f, ast::def_id fid,
68926892

68936893
auto lltop = bcx.llbb;
68946894

6895-
auto res = trans_block(bcx, f.body, return);
6895+
auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
6896+
auto res = if (!ty::type_is_nil(cx.ccx.tcx, block_ty)
6897+
&& !ty::type_is_bot(cx.ccx.tcx, block_ty)) {
6898+
trans_block(bcx, f.body, save_in(fcx.llretptr))
6899+
} else {
6900+
trans_block(bcx, f.body, return)
6901+
};
6902+
68966903
if (!is_terminated(res.bcx)) {
68976904
// FIXME: until LLVM has a unit type, we are moving around
68986905
// C_nil values rather than their void type.

src/comp/middle/tstate/pre_post_conditions.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ import front::ast::stmt_expr;
140140
import front::ast::block;
141141
import front::ast::block_;
142142

143+
import middle::ty::expr_ann;
144+
143145
import util::common::new_def_hash;
144146
import util::common::decl_lhs;
145147
import util::common::uistr;
@@ -696,6 +698,15 @@ fn find_pre_post_block(&fn_ctxt fcx, block b) -> () {
696698

697699
fn find_pre_post_fn(&fn_ctxt fcx, &_fn f) -> () {
698700
find_pre_post_block(fcx, f.body);
701+
702+
// Treat the tail expression as a return statement
703+
alt (f.body.node.expr) {
704+
case (some(?tailexpr)) {
705+
auto tailann = expr_ann(tailexpr);
706+
set_postcond_false(fcx.ccx, tailann);
707+
}
708+
case (none) { /* fallthrough */ }
709+
}
699710
}
700711

701712
fn fn_pre_post(crate_ctxt ccx, &_fn f, &span sp, &ident i, &def_id id,

src/comp/middle/tstate/states.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ import front::ast::stmt_expr;
150150
import front::ast::block;
151151
import front::ast::block_;
152152

153+
import middle::ty::expr_ann;
154+
import middle::ty::expr_ty;
155+
import middle::ty::type_is_nil;
156+
import middle::ty::type_is_bot;
157+
153158
import util::common::new_def_hash;
154159
import util::common::decl_lhs;
155160
import util::common::uistr;
@@ -753,8 +758,36 @@ fn find_pre_post_state_block(&fn_ctxt fcx, &prestate pres0, &block b)
753758

754759
fn find_pre_post_state_fn(&fn_ctxt fcx, &_fn f) -> bool {
755760
auto num_local_vars = num_locals(fcx.enclosing);
756-
ret find_pre_post_state_block(fcx,
757-
empty_prestate(num_local_vars), f.body);
761+
auto changed = find_pre_post_state_block(fcx,
762+
empty_prestate(num_local_vars), f.body);
763+
764+
// Treat the tail expression as a return statement
765+
alt (f.body.node.expr) {
766+
case (some(?tailexpr)) {
767+
auto tailann = expr_ann(tailexpr);
768+
auto tailty = expr_ty(fcx.ccx.tcx, tailexpr);
769+
770+
// Since blocks and alts and ifs that don't have results
771+
// implicitly result in nil, we have to be careful to not
772+
// interpret nil-typed block results as the result of a
773+
// function with some other return type
774+
if (!type_is_nil(fcx.ccx.tcx, tailty)
775+
&& !type_is_bot(fcx.ccx.tcx, tailty)) {
776+
777+
set_poststate_ann(fcx.ccx, tailann,
778+
false_postcond(num_local_vars));
779+
alt (fcx.enclosing.cf) {
780+
case (noreturn) {
781+
kill_poststate(fcx, tailann, fcx.id);
782+
}
783+
case (_) { }
784+
}
785+
}
786+
}
787+
case (none) { /* fallthrough */ }
788+
}
789+
790+
ret changed;
758791
}
759792

760793
//
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// xfail-stage0
2+
// error-pattern: return
3+
4+
fn f() -> int {
5+
// Make sure typestate doesn't interpret this alt expression
6+
// as the function result
7+
alt (true) {
8+
case (true) {
9+
}
10+
}
11+
}
12+
13+
fn main() {
14+
}

src/test/run-fail/expr-fn-fail.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// xfail-stage0
2+
// error-pattern:explicit failure
3+
4+
fn f() -> ! { fail }
5+
6+
fn main() {
7+
f();
8+
}

src/test/run-pass/expr-fn.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// xfail-stage0
2+
3+
fn test_int() {
4+
fn f() -> int { 10 }
5+
assert (f() == 10);
6+
}
7+
8+
fn test_vec() {
9+
fn f() -> vec[int] { [10, 11] }
10+
assert (f().(1) == 11);
11+
}
12+
13+
fn test_generic() {
14+
fn f[T](&T t) -> T { t }
15+
assert (f(10) == 10);
16+
}
17+
18+
fn test_alt() {
19+
fn f() -> int {
20+
alt (true) {
21+
case (false) { 10 }
22+
case (true) { 20 }
23+
}
24+
}
25+
assert (f() == 20);
26+
}
27+
28+
fn test_if() {
29+
fn f() -> int { if (true) { 10 } else { 20 } }
30+
assert (f() == 10);
31+
}
32+
33+
fn test_block() {
34+
fn f() -> int {{ 10 }}
35+
assert (f() == 10);
36+
}
37+
38+
fn test_ret() {
39+
fn f() -> int {
40+
ret 10 // no semi
41+
}
42+
assert (f() == 10);
43+
}
44+
45+
// From issue #372
46+
fn test_372() {
47+
fn f() -> int { auto x = { 3 }; x }
48+
assert (f() == 3);
49+
}
50+
51+
fn test_nil() {
52+
()
53+
}
54+
55+
fn main() {
56+
test_int();
57+
test_vec();
58+
test_generic();
59+
test_alt();
60+
test_if();
61+
test_block();
62+
test_ret();
63+
test_372();
64+
test_nil();
65+
}

0 commit comments

Comments
 (0)