about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-06-20 18:50:44 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-06-20 18:53:38 -0700
commitf331cd9324e4c4246fb3f332720a444042267e69 (patch)
treea1d3b6f5484553ec79acffefbfbcbbd97df56476
parent613deb03127d0930e4624d0c0a8744c849093019 (diff)
downloadrust-f331cd9324e4c4246fb3f332720a444042267e69.tar.gz
rust-f331cd9324e4c4246fb3f332720a444042267e69.zip
Don't consider loops to be breaking if they contain inner loops that break
Closes #2642
-rw-r--r--src/rustc/util/common.rs26
-rw-r--r--src/test/run-pass/issue-2642.rs6
2 files changed, 23 insertions, 9 deletions
diff --git a/src/rustc/util/common.rs b/src/rustc/util/common.rs
index ec599e72c4c..e12aa98b67a 100644
--- a/src/rustc/util/common.rs
+++ b/src/rustc/util/common.rs
@@ -34,25 +34,33 @@ fn field_exprs(fields: [ast::field]) -> [@ast::expr] {
 }
 
 // Takes a predicate p, returns true iff p is true for any subexpressions
-// of b
-fn block_expr_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
+// of b -- skipping any inner loops (loop, while, loop_body)
+fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
     let rs = @mut false;
-    let visit_expr = {|flag: @mut bool, e: @ast::expr| *flag |= p(e.node)};
-    let v =
-        visit::mk_simple_visitor(@{visit_expr: {|a|visit_expr(rs, a)}
-                                      with *visit::default_simple_visitor()});
-    visit::visit_block(b, (), v);
+    let visit_expr = {|e: @ast::expr, &&flag: @mut bool,
+                       v: visit::vt<@mut bool>|
+        *flag |= p(e.node);
+        alt e.node {
+          // Skip inner loops, since a break in the inner loop isn't a
+          // break inside the outer loop
+          ast::expr_loop(*) | ast::expr_while(*) | ast::expr_loop_body(*) {}
+          _ { visit::visit_expr(e, flag, v); }
+        }
+    };
+    let v = visit::mk_vt(@{visit_expr: visit_expr
+                           with *visit::default_visitor()});
+    visit::visit_block(b, rs, v);
     ret *rs;
 }
 
 fn has_nonlocal_exits(b: ast::blk) -> bool {
-    block_expr_query(b) {|e| alt e {
+    loop_query(b) {|e| alt e {
       ast::expr_break | ast::expr_cont { true }
       _ { false }}}
 }
 
 fn may_break(b: ast::blk) -> bool {
-    block_expr_query(b) {|e| alt e {
+    loop_query(b) {|e| alt e {
       ast::expr_break { true }
       _ { false }}}
 }
diff --git a/src/test/run-pass/issue-2642.rs b/src/test/run-pass/issue-2642.rs
new file mode 100644
index 00000000000..63e1fda60a8
--- /dev/null
+++ b/src/test/run-pass/issue-2642.rs
@@ -0,0 +1,6 @@
+fn f() {
+   let _x: uint = loop { loop { break; } };
+}
+
+fn main() {
+}