Skip to content

Commit b34cb1b

Browse files
committed
Fix a bunch of typestate bugs in handling if and while statement wirings.
1 parent 4a7aa75 commit b34cb1b

File tree

5 files changed

+51
-19
lines changed

5 files changed

+51
-19
lines changed

src/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
555555
vec-lib.rs \
556556
vec-slice.rs \
557557
vec.rs \
558+
while-flow-graph.rs \
558559
writealias.rs \
559560
yield.rs \
560561
yield2.rs \

src/boot/me/resolve.ml

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ let stmt_collecting_visitor
4848
: Walk.visitor =
4949
let block_ids = Stack.create () in
5050
let visit_block_pre (b:Ast.block) =
51+
htab_put cx.ctxt_all_blocks b.id b.node;
5152
Stack.push b.id block_ids;
5253
inner.Walk.visit_block_pre b
5354
in

src/boot/me/semant.ml

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type ctxt =
9898
ctxt_all_cast_types: (node_id,Ast.ty) Hashtbl.t;
9999
ctxt_all_type_items: (node_id,Ast.ty) Hashtbl.t;
100100
ctxt_all_stmts: (node_id,Ast.stmt) Hashtbl.t;
101+
ctxt_all_blocks: (node_id,Ast.block') Hashtbl.t;
101102
ctxt_item_files: (node_id,filename) Hashtbl.t;
102103
ctxt_all_lvals: (node_id,Ast.lval) Hashtbl.t;
103104
ctxt_call_lval_params: (node_id,Ast.ty array) Hashtbl.t;
@@ -183,6 +184,7 @@ let new_ctxt sess abi crate =
183184
ctxt_all_cast_types = Hashtbl.create 0;
184185
ctxt_all_type_items = Hashtbl.create 0;
185186
ctxt_all_stmts = Hashtbl.create 0;
187+
ctxt_all_blocks = Hashtbl.create 0;
186188
ctxt_item_files = crate.Ast.crate_files;
187189
ctxt_all_lvals = Hashtbl.create 0;
188190
ctxt_all_defns = Hashtbl.create 0;

src/boot/me/typestate.ml

+43-19
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,8 @@ let condition_assigning_visitor
697697
| Ast.STMT_while sw ->
698698
let (_, expr) = sw.Ast.while_lval in
699699
let precond = slot_inits (expr_slots cx expr) in
700-
raise_pre_post_cond s.id precond
700+
raise_precondition sw.Ast.while_body.id precond;
701+
raise_postcondition sw.Ast.while_body.id precond
701702

702703
| Ast.STMT_alt_tag at ->
703704
let precond = slot_inits (lval_slots cx at.Ast.alt_tag_lval) in
@@ -947,16 +948,17 @@ let graph_special_block_structure_building_visitor
947948
let ts = tables () in
948949
let graph = ts.ts_graph in
949950
let cond_id = s.id in
951+
let succ = Hashtbl.find graph cond_id in
950952
let then_id = sif.Ast.if_then.id in
951953
let then_end_id = last_id_or_block_id sif.Ast.if_then in
952954
let show_node = show_node cx graph in
955+
let succ = List.filter (fun x -> not (x = then_id)) succ in
953956
show_node "initial cond" cond_id;
954957
show_node "initial then" then_id;
955958
show_node "initial then_end" then_end_id;
956959
begin
957960
match sif.Ast.if_else with
958961
None ->
959-
let succ = Hashtbl.find graph then_end_id in
960962
Hashtbl.replace graph cond_id (then_id :: succ);
961963
(* Kill residual messed-up block wiring.*)
962964
remove_flow_edges graph then_end_id [then_id];
@@ -966,8 +968,10 @@ let graph_special_block_structure_building_visitor
966968

967969
| Some e ->
968970
let else_id = e.id in
971+
let succ =
972+
List.filter (fun x -> not (x = else_id)) succ
973+
in
969974
let else_end_id = last_id_or_block_id e in
970-
let succ = Hashtbl.find graph else_end_id in
971975
show_node "initial else" else_id;
972976
show_node "initial else_end" else_end_id;
973977
Hashtbl.replace graph cond_id [then_id; else_id];
@@ -1049,19 +1053,23 @@ let graph_special_block_structure_building_visitor
10491053
;;
10501054

10511055
let find_roots
1056+
(cx:ctxt)
10521057
(graph:(node_id, (node_id list)) Hashtbl.t)
10531058
: (node_id,unit) Hashtbl.t =
10541059
let roots = Hashtbl.create 0 in
10551060
Hashtbl.iter (fun src _ -> Hashtbl.replace roots src ()) graph;
10561061
Hashtbl.iter (fun _ dsts ->
10571062
List.iter (fun d -> Hashtbl.remove roots d) dsts) graph;
1063+
iflog cx
1064+
(fun _ -> Hashtbl.iter
1065+
(fun k _ -> log cx "root: %d" (int_of_node k)) roots);
10581066
roots
10591067
;;
10601068

10611069
let run_dataflow (cx:ctxt) (ts:typestate_tables) : unit =
10621070
let graph = ts.ts_graph in
10631071
let idref = ts.ts_maxid in
1064-
let roots = find_roots graph in
1072+
let roots = find_roots cx graph in
10651073
let nodes = Queue.create () in
10661074

10671075
let progress = ref true in
@@ -1138,9 +1146,17 @@ let run_dataflow (cx:ctxt) (ts:typestate_tables) : unit =
11381146
begin
11391147
fun _ ->
11401148
log cx "stmt %d: '%s'" (int_of_node node)
1141-
(match htab_search cx.ctxt_all_stmts node with
1142-
None -> "??"
1143-
| Some stmt -> Fmt.fmt_to_str Ast.fmt_stmt stmt);
1149+
begin
1150+
match htab_search cx.ctxt_all_stmts node with
1151+
None ->
1152+
begin
1153+
match htab_search cx.ctxt_all_blocks node with
1154+
None -> "??"
1155+
| Some b ->
1156+
Fmt.fmt_to_str Ast.fmt_block b
1157+
end
1158+
| Some stmt -> Fmt.fmt_to_str Ast.fmt_stmt stmt
1159+
end;
11441160
log cx "stmt %d:" (int_of_node node);
11451161

11461162
log cx " prestate %s" (fmt_constr_bitv prestate);
@@ -1227,27 +1243,35 @@ let typestate_verify_visitor
12271243

12281244
let tables _ = Stack.top tables_stack in
12291245

1230-
let visit_stmt_pre s =
1246+
let check_states id =
12311247
let ts = tables () in
1232-
let prestate = Hashtbl.find ts.ts_prestates s.id in
1233-
let precond = Hashtbl.find ts.ts_preconditions s.id in
1248+
let prestate = Hashtbl.find ts.ts_prestates id in
1249+
let precond = Hashtbl.find ts.ts_preconditions id in
12341250
List.iter
12351251
(fun i ->
12361252
if not (Bits.get prestate i)
12371253
then
12381254
let ckey = Hashtbl.find ts.ts_constrs (Constr i) in
12391255
let constr_str = fmt_constr_key cx ckey in
1240-
err (Some s.id)
1241-
"Unsatisfied precondition constraint %s at stmt %d: %s"
1242-
constr_str
1243-
(int_of_node s.id)
1244-
(Fmt.fmt_to_str Ast.fmt_stmt
1245-
(Hashtbl.find cx.ctxt_all_stmts s.id)))
1246-
(Bits.to_list precond);
1247-
inner.Walk.visit_stmt_pre s
1256+
err (Some id)
1257+
"Unsatisfied precondition constraint %s"
1258+
constr_str)
1259+
(Bits.to_list precond)
1260+
in
1261+
1262+
let visit_stmt_pre s =
1263+
check_states s.id;
1264+
inner.Walk.visit_stmt_pre s
1265+
in
1266+
1267+
let visit_block_pre b =
1268+
check_states b.id;
1269+
inner.Walk.visit_block_pre b
12481270
in
1271+
12491272
{ inner with
1250-
Walk.visit_stmt_pre = visit_stmt_pre }
1273+
Walk.visit_stmt_pre = visit_stmt_pre;
1274+
Walk.visit_block_pre = visit_block_pre }
12511275
;;
12521276

12531277
let lifecycle_visitor

src/test/run-pass/while-flow-graph.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
let int x = 10;
3+
while (x == 10 && x == 11) { auto y = 0xf00; }
4+
}

0 commit comments

Comments
 (0)