Skip to content

Commit 205cefd

Browse files
committed
In typestate, consider infinite loops w/ conts to be infinite
If a loop { } contains a cont, that doesn't affect whether the entire loop diverges. Only breaks affect that. Fix that in typestate.
1 parent 35400e1 commit 205cefd

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

src/rustc/middle/tstate/states.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,9 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
550550
/* conservative approximation: if a loop contains a break
551551
or cont, we assume nothing about the poststate */
552552
/* which is still unsound -- see [Break-unsound] */
553-
if has_nonlocal_exits(body) {
553+
if may_break(body) {
554+
/* Only do this if there are *breaks* not conts.
555+
An infinite loop with conts is still an infinite loop. */
554556
ret changed | set_poststate_ann(fcx.ccx, e.id, pres);
555557
} else {
556558
ret changed | set_poststate_ann(fcx.ccx, e.id,

src/rustc/util/common.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ fn has_nonlocal_exits(b: ast::blk) -> bool {
8383
ret *has_exits;
8484
}
8585

86+
/* FIXME: copy/paste, yuck */
87+
fn may_break(b: ast::blk) -> bool {
88+
let has_exits = @mutable false;
89+
fn visit_expr(flag: @mutable bool, e: @ast::expr) {
90+
alt e.node {
91+
ast::expr_break { *flag = true; }
92+
_ { }
93+
}
94+
}
95+
let v =
96+
visit::mk_simple_visitor(@{visit_expr: bind visit_expr(has_exits, _)
97+
with *visit::default_simple_visitor()});
98+
visit::visit_block(b, (), v);
99+
ret *has_exits;
100+
}
101+
86102
fn local_rhs_span(l: @ast::local, def: span) -> span {
87103
alt l.node.init { some(i) { ret i.expr.span; } _ { ret def; } }
88104
}

0 commit comments

Comments
 (0)