Skip to content

Commit 44a0c72

Browse files
committed
Isolate while-header bug to minimal testcase, fix in rustboot, remove workaround in rustc.
1 parent d311719 commit 44a0c72

File tree

5 files changed

+94
-46
lines changed

5 files changed

+94
-46
lines changed

src/boot/me/semant.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ type ctxt =
132132

133133
(* Typestate-y stuff. *)
134134
ctxt_stmt_is_init: (node_id,unit) Hashtbl.t;
135+
ctxt_while_header_slots: (node_id,node_id list) Hashtbl.t;
135136
ctxt_post_stmt_slot_drops: (node_id,node_id list) Hashtbl.t;
136137
ctxt_post_block_slot_drops: (node_id,node_id list) Hashtbl.t;
137138

@@ -239,6 +240,7 @@ let new_ctxt sess abi crate =
239240
ctxt_required_syms = crate.Ast.crate_required_syms;
240241

241242
ctxt_stmt_is_init = Hashtbl.create 0;
243+
ctxt_while_header_slots = Hashtbl.create 0;
242244
ctxt_post_stmt_slot_drops = Hashtbl.create 0;
243245
ctxt_post_block_slot_drops = Hashtbl.create 0;
244246

src/boot/me/trans.ml

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,27 +2614,24 @@ let trans_visitor
26142614
| Ast.EXPR_atom a ->
26152615
trans_atom a
26162616

2617+
and drop_slot_by_id (depth:int) (slot_id:node_id) : unit =
2618+
let slot = get_slot cx slot_id in
2619+
let k = Hashtbl.find cx.ctxt_slot_keys slot_id in
2620+
iflog (fun _ ->
2621+
annotate
2622+
(Printf.sprintf
2623+
"drop_slot %d = %s "
2624+
(int_of_node slot_id)
2625+
(Fmt.fmt_to_str Ast.fmt_slot_key k)));
2626+
drop_slot_in_current_frame
2627+
(cell_of_block_slot
2628+
~access_depth:(Some depth) slot_id) slot
2629+
26172630
and drop_slots_after_block bid : unit =
2631+
let depth = Hashtbl.find cx.ctxt_block_loop_depths bid in
26182632
match htab_search cx.ctxt_post_block_slot_drops bid with
26192633
None -> ()
2620-
| Some slots ->
2621-
List.iter
2622-
begin
2623-
fun slot_id ->
2624-
let slot = get_slot cx slot_id in
2625-
let k = Hashtbl.find cx.ctxt_slot_keys slot_id in
2626-
let depth = Hashtbl.find cx.ctxt_block_loop_depths bid in
2627-
iflog (fun _ ->
2628-
annotate
2629-
(Printf.sprintf
2630-
"post-block, drop_slot %d = %s "
2631-
(int_of_node slot_id)
2632-
(Fmt.fmt_to_str Ast.fmt_slot_key k)));
2633-
drop_slot_in_current_frame
2634-
(cell_of_block_slot
2635-
~access_depth:(Some depth) slot_id) slot
2636-
end
2637-
slots
2634+
| Some slots -> List.iter (drop_slot_by_id depth) slots
26382635

26392636
and trans_block (block:Ast.block) : unit =
26402637
flush_emitter_size_cache();
@@ -5260,6 +5257,36 @@ let trans_visitor
52605257
trans_log_int a
52615258
| _ -> unimpl (Some id) "logging type"
52625259

5260+
and trans_while (id:node_id) (sw:Ast.stmt_while) : unit =
5261+
let (head_stmts, head_expr) = sw.Ast.while_lval in
5262+
let fwd_jmp = mark () in
5263+
emit (Il.jmp Il.JMP Il.CodeNone);
5264+
let block_begin = mark () in
5265+
Stack.push (Stack.create()) simple_break_jumps;
5266+
trans_block sw.Ast.while_body;
5267+
patch fwd_jmp;
5268+
Array.iter trans_stmt head_stmts;
5269+
check_interrupt_flag ();
5270+
let flag = next_vreg_cell (Il.ValTy Il.Bits8) in
5271+
mov flag imm_true;
5272+
let true_jmps = trans_cond false head_expr in
5273+
mov flag imm_false;
5274+
List.iter patch true_jmps;
5275+
begin
5276+
begin
5277+
match htab_search cx.ctxt_while_header_slots id with
5278+
None -> ()
5279+
| Some slots ->
5280+
let depth = get_stmt_depth cx id in
5281+
List.iter (drop_slot_by_id depth) slots
5282+
end;
5283+
let back_jmps =
5284+
trans_compare_simple Il.JE (Il.Cell flag) imm_true
5285+
in
5286+
List.iter (fun j -> patch_existing j block_begin) back_jmps;
5287+
end;
5288+
Stack.iter patch (Stack.pop simple_break_jumps);
5289+
52635290

52645291
and trans_stmt_full (stmt:Ast.stmt) : unit =
52655292
match stmt.node with
@@ -5378,20 +5405,7 @@ let trans_visitor
53785405
trans_block block
53795406

53805407
| Ast.STMT_while sw ->
5381-
let (head_stmts, head_expr) = sw.Ast.while_lval in
5382-
let fwd_jmp = mark () in
5383-
emit (Il.jmp Il.JMP Il.CodeNone);
5384-
let block_begin = mark () in
5385-
Stack.push (Stack.create()) simple_break_jumps;
5386-
trans_block sw.Ast.while_body;
5387-
patch fwd_jmp;
5388-
Array.iter trans_stmt head_stmts;
5389-
check_interrupt_flag ();
5390-
begin
5391-
let back_jmps = trans_cond false head_expr in
5392-
List.iter (fun j -> patch_existing j block_begin) back_jmps;
5393-
end;
5394-
Stack.iter patch (Stack.pop simple_break_jumps);
5408+
trans_while stmt.id sw
53955409

53965410
| Ast.STMT_if si ->
53975411
let skip_thn_jmps = trans_cond true si.Ast.if_test in

src/boot/me/typestate.ml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,28 @@ let lifecycle_visitor
14671467
f.Ast.for_each_body.id
14681468
[ (fst f.Ast.for_each_slot).id ]
14691469

1470-
| Ast.STMT_while _ ->
1470+
| Ast.STMT_while sw ->
1471+
(* Collect any header-locals. *)
1472+
Array.iter
1473+
begin
1474+
fun stmt ->
1475+
match stmt.node with
1476+
Ast.STMT_decl (Ast.DECL_slot (_, slot)) ->
1477+
begin
1478+
match
1479+
htab_search cx.ctxt_while_header_slots s.id
1480+
with
1481+
None ->
1482+
Hashtbl.add cx.ctxt_while_header_slots
1483+
s.id [slot.id]
1484+
| Some slots ->
1485+
Hashtbl.replace cx.ctxt_while_header_slots
1486+
s.id (slot.id :: slots)
1487+
end
1488+
| _ -> ()
1489+
end
1490+
(fst sw.Ast.while_lval);
1491+
14711492
iflog cx (fun _ -> log cx "entering a loop");
14721493
Stack.push (Some (Stack.create ())) loop_blocks;
14731494

src/comp/front/parser.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,6 @@ impure fn parse_arg(parser p) -> ast.arg {
198198
ret rec(mode=m, ty=t, ident=i, id=p.next_def_id());
199199
}
200200

201-
// FIXME: workaround for a bug in the typestate walk of
202-
// the while-graph; the while-loop header doesn't drop
203-
// its slots, so "while (p.peek() ...) { ... }" leaks.
204-
205-
fn peeking_at(parser p, token.token t) -> bool {
206-
if (p.peek() == t) {
207-
ret true;
208-
}
209-
ret false;
210-
}
211-
212201
impure fn parse_seq[T](token.token bra,
213202
token.token ket,
214203
option.t[token.token] sep,
@@ -218,7 +207,7 @@ impure fn parse_seq[T](token.token bra,
218207
auto lo = p.get_span();
219208
expect(p, bra);
220209
let vec[T] v = vec();
221-
while (!peeking_at(p, ket)) {
210+
while (p.peek() != ket) {
222211
alt(sep) {
223212
case (some[token.token](?t)) {
224213
if (first) {
@@ -936,7 +925,7 @@ impure fn parse_mod_items(parser p, token.token term) -> ast._mod {
936925
let vec[@ast.item] items = vec();
937926
let hashmap[ast.ident,uint] index = new_str_hash[uint]();
938927
let uint u = 0u;
939-
while (!peeking_at(p, term)) {
928+
while (p.peek() != term) {
940929
auto pair = parse_item(p);
941930
append[@ast.item](items, pair._1);
942931
index.insert(pair._0, u);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
tag t {
2+
a;
3+
b(str);
4+
}
5+
6+
fn make(int i) -> t {
7+
if (i > 10) {
8+
ret a;
9+
}
10+
auto s = "hello";
11+
// Ensure s is non-const.
12+
s += "there";
13+
ret b(s);
14+
}
15+
16+
fn main() {
17+
auto i = 0;
18+
// The auto slot for the result of make(i) should not leak.
19+
while (make(i) != a) {
20+
i += 1;
21+
}
22+
}

0 commit comments

Comments
 (0)