From 94d4dcdbf0121a2b885b2cc45a1b387baf0c7b26 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 Feb 2012 14:47:36 +0100 Subject: [PATCH] Fix bug in handling of block functions in last-use analysis It would fail to start out with a fresh scope when going over a loop or block function for the second time, and thus not recognize last uses of locals defined inside the block. Closes #1818 --- src/comp/middle/last_use.rs | 8 ++++++-- src/test/run-pass/last-use-in-block.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/last-use-in-block.rs diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs index f3b2e83a211..111cbde0fa3 100644 --- a/src/comp/middle/last_use.rs +++ b/src/comp/middle/last_use.rs @@ -137,7 +137,6 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt) { // n.b.: safe to ignore copies, as if they are unused // then they are ignored, otherwise they will show up // as freevars in the body. - vec::iter(cap_clause.moves) {|ci| clear_def_if_path(cx, cx.def_map.get(ci.id), true); } @@ -203,13 +202,18 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, fn visit_block(tp: block_type, cx: ctx, visit: fn()) { let local = @{type: tp, mutable second: false, mutable exits: []}; cx.blocks = cons(local, @cx.blocks); + let start_current = cx.current; visit(); local.second = true; + local.exits = []; + cx.current = start_current; visit(); let cx_blocks = cx.blocks; check is_not_empty(cx_blocks); cx.blocks = tail(cx_blocks); - cx.current = join_branches(local.exits); + let branches = if tp == func { local.exits + [cx.current] } + else { local.exits }; + cx.current = join_branches(branches); } fn add_block_exit(cx: ctx, tp: block_type) -> bool { diff --git a/src/test/run-pass/last-use-in-block.rs b/src/test/run-pass/last-use-in-block.rs new file mode 100644 index 00000000000..d0593853e1d --- /dev/null +++ b/src/test/run-pass/last-use-in-block.rs @@ -0,0 +1,16 @@ +// Issue #1818 + +fn loop(s: str, f: fn(str) -> T) -> T { + while false { + let r = f(s); + ret r; + } + fail; +} + +fn apply(s: str, f: fn(str) -> T) -> T { + fn g(s: str, f: fn(str) -> T) -> T {f(s)} + g(s) {|v| let r = f(v); r } +} + +fn main() {}