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
This commit is contained in:
parent
00a4aee2ed
commit
e36df0f6c8
3 changed files with 25 additions and 4 deletions
|
@ -48,6 +48,22 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_fail(fcx: fn_ctxt, pres:prestate, post:poststate) {
|
||||||
|
// Remember what the old value of the "I return" trit was, so that
|
||||||
|
// we can avoid changing that (if it was true, there was a return
|
||||||
|
// that dominates this fail and the fail is unreachable)
|
||||||
|
if !promises(fcx, pres, fcx.enclosing.i_return)
|
||||||
|
// (only if we're in a diverging function -- you can fail when
|
||||||
|
// you're supposed to return, but not vice versa).
|
||||||
|
&& fcx.enclosing.cf == noreturn {
|
||||||
|
kill_poststate_(fcx, fcx.enclosing.i_return, post);
|
||||||
|
} else {
|
||||||
|
// This code is unreachable (it's dominated by a return),
|
||||||
|
// so doesn't diverge.
|
||||||
|
kill_poststate_(fcx, fcx.enclosing.i_diverge, post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) ->
|
fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) ->
|
||||||
{changed: bool, post: poststate} {
|
{changed: bool, post: poststate} {
|
||||||
let changed = false;
|
let changed = false;
|
||||||
|
@ -189,6 +205,7 @@ fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id,
|
||||||
alt cf {
|
alt cf {
|
||||||
noreturn {
|
noreturn {
|
||||||
let post = false_postcond(num_constraints(fcx.enclosing));
|
let post = false_postcond(num_constraints(fcx.enclosing));
|
||||||
|
handle_fail(fcx, pres, post);
|
||||||
changed |= set_poststate_ann(fcx.ccx, id, post);
|
changed |= set_poststate_ann(fcx.ccx, id, post);
|
||||||
}
|
}
|
||||||
_ { changed |= set_poststate_ann(fcx.ccx, id, rs.post); }
|
_ { 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 {
|
||||||
/* if execution continues after fail, then everything is true!
|
/* if execution continues after fail, then everything is true!
|
||||||
woo! */
|
woo! */
|
||||||
let post = false_postcond(num_constrs);
|
let post = false_postcond(num_constrs);
|
||||||
alt fcx.enclosing.cf {
|
handle_fail(fcx, pres, post);
|
||||||
noreturn { kill_poststate_(fcx, fcx.enclosing.i_return, post); }
|
|
||||||
_ { }
|
|
||||||
}
|
|
||||||
ret set_prestate_ann(fcx.ccx, e.id, pres) |
|
ret set_prestate_ann(fcx.ccx, e.id, pres) |
|
||||||
set_poststate_ann(fcx.ccx, e.id, post) |
|
set_poststate_ann(fcx.ccx, e.id, post) |
|
||||||
option::maybe(false, maybe_fail_val, {|fail_val|
|
option::maybe(false, maybe_fail_val, {|fail_val|
|
||||||
|
|
4
src/test/compile-fail/issue-897-2.rs
Normal file
4
src/test/compile-fail/issue-897-2.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// error-pattern: In non-returning function f, some control paths may return
|
||||||
|
fn g() -> ! { fail; }
|
||||||
|
fn f() -> ! { ret 42; g(); }
|
||||||
|
fn main() { }
|
3
src/test/compile-fail/issue-897.rs
Normal file
3
src/test/compile-fail/issue-897.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// error-pattern: In non-returning function f, some control paths may return
|
||||||
|
fn f() -> ! { ret 42; fail; }
|
||||||
|
fn main() { }
|
Loading…
Add table
Add a link
Reference in a new issue