about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-01-20 17:23:56 -0800
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-01-20 17:26:31 -0800
commite36df0f6c87278345d4bb98292bff661291b65f2 (patch)
tree7693c76c56ca21f530ed647402ae79ff00666abc /src/comp
parent00a4aee2ede16541b0af34093d2fbcc4ba7cd6f2 (diff)
downloadrust-e36df0f6c87278345d4bb98292bff661291b65f2.tar.gz
rust-e36df0f6c87278345d4bb98292bff661291b65f2.zip
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
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/tstate/states.rs22
1 files changed, 18 insertions, 4 deletions
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index 0c1fbbf8e58..ae621b8f31f 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -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]) ->
    {changed: bool, post: poststate} {
     let changed = false;
@@ -189,6 +205,7 @@ fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id,
     alt cf {
       noreturn {
         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, 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!
         woo! */
         let post = false_postcond(num_constrs);
-        alt fcx.enclosing.cf {
-          noreturn { kill_poststate_(fcx, fcx.enclosing.i_return, post); }
-          _ { }
-        }
+        handle_fail(fcx, pres, post);
         ret set_prestate_ann(fcx.ccx, e.id, pres) |
                 set_poststate_ann(fcx.ccx, e.id, post) |
                 option::maybe(false, maybe_fail_val, {|fail_val|