diff options
| author | Graydon Hoare <[email protected]> | 2010-11-19 14:59:58 -0800 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2010-11-19 14:59:58 -0800 |
| commit | 44a0c7225d5aa13769c4531b25fd524976c7f7a0 (patch) | |
| tree | 5a7ead9d3317adf09f49d8f565b1c8343fdba147 | |
| parent | Enable more now-passing tests for rustc (including function calls). (diff) | |
| download | rust-44a0c7225d5aa13769c4531b25fd524976c7f7a0.tar.xz rust-44a0c7225d5aa13769c4531b25fd524976c7f7a0.zip | |
Isolate while-header bug to minimal testcase, fix in rustboot, remove workaround in rustc.
| -rw-r--r-- | src/boot/me/semant.ml | 2 | ||||
| -rw-r--r-- | src/boot/me/trans.ml | 78 | ||||
| -rw-r--r-- | src/boot/me/typestate.ml | 23 | ||||
| -rw-r--r-- | src/comp/front/parser.rs | 15 | ||||
| -rw-r--r-- | src/test/run-pass/while-prelude-drop.rs | 22 |
5 files changed, 94 insertions, 46 deletions
diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml index 4f02455a..c4930c12 100644 --- a/src/boot/me/semant.ml +++ b/src/boot/me/semant.ml @@ -132,6 +132,7 @@ type ctxt = (* Typestate-y stuff. *) ctxt_stmt_is_init: (node_id,unit) Hashtbl.t; + ctxt_while_header_slots: (node_id,node_id list) Hashtbl.t; ctxt_post_stmt_slot_drops: (node_id,node_id list) Hashtbl.t; ctxt_post_block_slot_drops: (node_id,node_id list) Hashtbl.t; @@ -239,6 +240,7 @@ let new_ctxt sess abi crate = ctxt_required_syms = crate.Ast.crate_required_syms; ctxt_stmt_is_init = Hashtbl.create 0; + ctxt_while_header_slots = Hashtbl.create 0; ctxt_post_stmt_slot_drops = Hashtbl.create 0; ctxt_post_block_slot_drops = Hashtbl.create 0; diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml index 1fdd40ad..c3d5240b 100644 --- a/src/boot/me/trans.ml +++ b/src/boot/me/trans.ml @@ -2614,27 +2614,24 @@ let trans_visitor | Ast.EXPR_atom a -> trans_atom a + and drop_slot_by_id (depth:int) (slot_id:node_id) : unit = + let slot = get_slot cx slot_id in + let k = Hashtbl.find cx.ctxt_slot_keys slot_id in + iflog (fun _ -> + annotate + (Printf.sprintf + "drop_slot %d = %s " + (int_of_node slot_id) + (Fmt.fmt_to_str Ast.fmt_slot_key k))); + drop_slot_in_current_frame + (cell_of_block_slot + ~access_depth:(Some depth) slot_id) slot + and drop_slots_after_block bid : unit = + let depth = Hashtbl.find cx.ctxt_block_loop_depths bid in match htab_search cx.ctxt_post_block_slot_drops bid with None -> () - | Some slots -> - List.iter - begin - fun slot_id -> - let slot = get_slot cx slot_id in - let k = Hashtbl.find cx.ctxt_slot_keys slot_id in - let depth = Hashtbl.find cx.ctxt_block_loop_depths bid in - iflog (fun _ -> - annotate - (Printf.sprintf - "post-block, drop_slot %d = %s " - (int_of_node slot_id) - (Fmt.fmt_to_str Ast.fmt_slot_key k))); - drop_slot_in_current_frame - (cell_of_block_slot - ~access_depth:(Some depth) slot_id) slot - end - slots + | Some slots -> List.iter (drop_slot_by_id depth) slots and trans_block (block:Ast.block) : unit = flush_emitter_size_cache(); @@ -5260,6 +5257,36 @@ let trans_visitor trans_log_int a | _ -> unimpl (Some id) "logging type" + and trans_while (id:node_id) (sw:Ast.stmt_while) : unit = + let (head_stmts, head_expr) = sw.Ast.while_lval in + let fwd_jmp = mark () in + emit (Il.jmp Il.JMP Il.CodeNone); + let block_begin = mark () in + Stack.push (Stack.create()) simple_break_jumps; + trans_block sw.Ast.while_body; + patch fwd_jmp; + Array.iter trans_stmt head_stmts; + check_interrupt_flag (); + let flag = next_vreg_cell (Il.ValTy Il.Bits8) in + mov flag imm_true; + let true_jmps = trans_cond false head_expr in + mov flag imm_false; + List.iter patch true_jmps; + begin + begin + match htab_search cx.ctxt_while_header_slots id with + None -> () + | Some slots -> + let depth = get_stmt_depth cx id in + List.iter (drop_slot_by_id depth) slots + end; + let back_jmps = + trans_compare_simple Il.JE (Il.Cell flag) imm_true + in + List.iter (fun j -> patch_existing j block_begin) back_jmps; + end; + Stack.iter patch (Stack.pop simple_break_jumps); + and trans_stmt_full (stmt:Ast.stmt) : unit = match stmt.node with @@ -5378,20 +5405,7 @@ let trans_visitor trans_block block | Ast.STMT_while sw -> - let (head_stmts, head_expr) = sw.Ast.while_lval in - let fwd_jmp = mark () in - emit (Il.jmp Il.JMP Il.CodeNone); - let block_begin = mark () in - Stack.push (Stack.create()) simple_break_jumps; - trans_block sw.Ast.while_body; - patch fwd_jmp; - Array.iter trans_stmt head_stmts; - check_interrupt_flag (); - begin - let back_jmps = trans_cond false head_expr in - List.iter (fun j -> patch_existing j block_begin) back_jmps; - end; - Stack.iter patch (Stack.pop simple_break_jumps); + trans_while stmt.id sw | Ast.STMT_if si -> let skip_thn_jmps = trans_cond true si.Ast.if_test in diff --git a/src/boot/me/typestate.ml b/src/boot/me/typestate.ml index 4ca0caf2..ea0204f3 100644 --- a/src/boot/me/typestate.ml +++ b/src/boot/me/typestate.ml @@ -1467,7 +1467,28 @@ let lifecycle_visitor f.Ast.for_each_body.id [ (fst f.Ast.for_each_slot).id ] - | Ast.STMT_while _ -> + | Ast.STMT_while sw -> + (* Collect any header-locals. *) + Array.iter + begin + fun stmt -> + match stmt.node with + Ast.STMT_decl (Ast.DECL_slot (_, slot)) -> + begin + match + htab_search cx.ctxt_while_header_slots s.id + with + None -> + Hashtbl.add cx.ctxt_while_header_slots + s.id [slot.id] + | Some slots -> + Hashtbl.replace cx.ctxt_while_header_slots + s.id (slot.id :: slots) + end + | _ -> () + end + (fst sw.Ast.while_lval); + iflog cx (fun _ -> log cx "entering a loop"); Stack.push (Some (Stack.create ())) loop_blocks; diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 63e43067..2382efc1 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -198,17 +198,6 @@ impure fn parse_arg(parser p) -> ast.arg { ret rec(mode=m, ty=t, ident=i, id=p.next_def_id()); } -// FIXME: workaround for a bug in the typestate walk of -// the while-graph; the while-loop header doesn't drop -// its slots, so "while (p.peek() ...) { ... }" leaks. - -fn peeking_at(parser p, token.token t) -> bool { - if (p.peek() == t) { - ret true; - } - ret false; -} - impure fn parse_seq[T](token.token bra, token.token ket, option.t[token.token] sep, @@ -218,7 +207,7 @@ impure fn parse_seq[T](token.token bra, auto lo = p.get_span(); expect(p, bra); let vec[T] v = vec(); - while (!peeking_at(p, ket)) { + while (p.peek() != ket) { alt(sep) { case (some[token.token](?t)) { if (first) { @@ -936,7 +925,7 @@ impure fn parse_mod_items(parser p, token.token term) -> ast._mod { let vec[@ast.item] items = vec(); let hashmap[ast.ident,uint] index = new_str_hash[uint](); let uint u = 0u; - while (!peeking_at(p, term)) { + while (p.peek() != term) { auto pair = parse_item(p); append[@ast.item](items, pair._1); index.insert(pair._0, u); diff --git a/src/test/run-pass/while-prelude-drop.rs b/src/test/run-pass/while-prelude-drop.rs new file mode 100644 index 00000000..18f259a7 --- /dev/null +++ b/src/test/run-pass/while-prelude-drop.rs @@ -0,0 +1,22 @@ +tag t { + a; + b(str); +} + +fn make(int i) -> t { + if (i > 10) { + ret a; + } + auto s = "hello"; + // Ensure s is non-const. + s += "there"; + ret b(s); +} + +fn main() { + auto i = 0; + // The auto slot for the result of make(i) should not leak. + while (make(i) != a) { + i += 1; + } +}
\ No newline at end of file |