Skip to content

Commit e36df0f

Browse files
committed
Handle fail after return correctly in typestate
Previously, typestate would conclude that this function was correctly diverging: fn f() -> ! { ret; fail; } even though it always returns to the caller. It wasn't handling the i_diverge and i_return bits correctly in the fail case. Fixed it. Closes #897
1 parent 00a4aee commit e36df0f

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

src/comp/middle/tstate/states.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
4848
}
4949
}
5050

51+
fn handle_fail(fcx: fn_ctxt, pres:prestate, post:poststate) {
52+
// Remember what the old value of the "I return" trit was, so that
53+
// we can avoid changing that (if it was true, there was a return
54+
// that dominates this fail and the fail is unreachable)
55+
if !promises(fcx, pres, fcx.enclosing.i_return)
56+
// (only if we're in a diverging function -- you can fail when
57+
// you're supposed to return, but not vice versa).
58+
&& fcx.enclosing.cf == noreturn {
59+
kill_poststate_(fcx, fcx.enclosing.i_return, post);
60+
} else {
61+
// This code is unreachable (it's dominated by a return),
62+
// so doesn't diverge.
63+
kill_poststate_(fcx, fcx.enclosing.i_diverge, post);
64+
}
65+
}
66+
5167
fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) ->
5268
{changed: bool, post: poststate} {
5369
let changed = false;
@@ -189,6 +205,7 @@ fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id,
189205
alt cf {
190206
noreturn {
191207
let post = false_postcond(num_constraints(fcx.enclosing));
208+
handle_fail(fcx, pres, post);
192209
changed |= set_poststate_ann(fcx.ccx, id, post);
193210
}
194211
_ { changed |= set_poststate_ann(fcx.ccx, id, rs.post); }
@@ -584,10 +601,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
584601
/* if execution continues after fail, then everything is true!
585602
woo! */
586603
let post = false_postcond(num_constrs);
587-
alt fcx.enclosing.cf {
588-
noreturn { kill_poststate_(fcx, fcx.enclosing.i_return, post); }
589-
_ { }
590-
}
604+
handle_fail(fcx, pres, post);
591605
ret set_prestate_ann(fcx.ccx, e.id, pres) |
592606
set_poststate_ann(fcx.ccx, e.id, post) |
593607
option::maybe(false, maybe_fail_val, {|fail_val|

src/test/compile-fail/issue-897-2.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// error-pattern: In non-returning function f, some control paths may return
2+
fn g() -> ! { fail; }
3+
fn f() -> ! { ret 42; g(); }
4+
fn main() { }

src/test/compile-fail/issue-897.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// error-pattern: In non-returning function f, some control paths may return
2+
fn f() -> ! { ret 42; fail; }
3+
fn main() { }

0 commit comments

Comments
 (0)