mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-08 04:56:58 +00:00
Drop slots on block exits even when blocks have no statements. Part way to fixing bind leakage in rustc.
This commit is contained in:
parent
f6e3e6903b
commit
62c224ffe4
@ -462,6 +462,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
|
||||
deep.rs \
|
||||
deref.rs \
|
||||
destructor-ordering.rs \
|
||||
drop-on-empty-block-exit.rs \
|
||||
export-non-interference.rs \
|
||||
exterior.rs \
|
||||
fn-lval.rs \
|
||||
|
@ -1545,6 +1545,7 @@ and fmt_pat (ff:Format.formatter) (pat:pat) : unit =
|
||||
fmt_lval ff ctor;
|
||||
fmt_bracketed_arr_sep "(" ")" "," fmt_pat ff pats
|
||||
| PAT_slot (_, ident) ->
|
||||
fmt ff "?";
|
||||
fmt_ident ff ident
|
||||
| PAT_wild ->
|
||||
fmt ff "_"
|
||||
|
@ -114,6 +114,8 @@ let loop_depth_visitor
|
||||
let visit_block_pre b =
|
||||
if Hashtbl.mem cx.ctxt_block_is_loop_body b.id
|
||||
then push_loop ();
|
||||
let fcx = Stack.top fcxs in
|
||||
htab_put cx.ctxt_block_loop_depths b.id fcx.current_depth;
|
||||
inner.Walk.visit_block_pre b
|
||||
in
|
||||
|
||||
|
@ -131,6 +131,7 @@ type ctxt =
|
||||
(* Typestate-y stuff. *)
|
||||
ctxt_stmt_is_init: (node_id,unit) 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;
|
||||
|
||||
(* Layout-y stuff. *)
|
||||
ctxt_slot_aliased: (node_id,unit) Hashtbl.t;
|
||||
@ -141,6 +142,7 @@ type ctxt =
|
||||
ctxt_call_sizes: (node_id,size) Hashtbl.t;
|
||||
ctxt_block_is_loop_body: (node_id,unit) Hashtbl.t;
|
||||
ctxt_stmt_loop_depths: (node_id,int) Hashtbl.t;
|
||||
ctxt_block_loop_depths: (node_id,int) Hashtbl.t;
|
||||
ctxt_slot_loop_depths: (node_id,int) Hashtbl.t;
|
||||
|
||||
(* Translation-y stuff. *)
|
||||
@ -216,6 +218,7 @@ let new_ctxt sess abi crate =
|
||||
|
||||
ctxt_stmt_is_init = Hashtbl.create 0;
|
||||
ctxt_post_stmt_slot_drops = Hashtbl.create 0;
|
||||
ctxt_post_block_slot_drops = Hashtbl.create 0;
|
||||
|
||||
ctxt_slot_aliased = Hashtbl.create 0;
|
||||
ctxt_slot_is_obj_state = Hashtbl.create 0;
|
||||
@ -227,6 +230,7 @@ let new_ctxt sess abi crate =
|
||||
ctxt_block_is_loop_body = Hashtbl.create 0;
|
||||
ctxt_slot_loop_depths = Hashtbl.create 0;
|
||||
ctxt_stmt_loop_depths = Hashtbl.create 0;
|
||||
ctxt_block_loop_depths = Hashtbl.create 0;
|
||||
|
||||
ctxt_fn_fixups = Hashtbl.create 0;
|
||||
ctxt_block_fixups = Hashtbl.create 0;
|
||||
@ -399,6 +403,10 @@ let get_stmt_depth (cx:ctxt) (id:node_id) : int =
|
||||
Hashtbl.find cx.ctxt_stmt_loop_depths id
|
||||
;;
|
||||
|
||||
let get_block_depth (cx:ctxt) (id:node_id) : int =
|
||||
Hashtbl.find cx.ctxt_block_loop_depths id
|
||||
;;
|
||||
|
||||
let get_slot_depth (cx:ctxt) (id:node_id) : int =
|
||||
Hashtbl.find cx.ctxt_slot_loop_depths id
|
||||
;;
|
||||
|
@ -826,10 +826,51 @@ let trans_visitor
|
||||
out diff current_fp
|
||||
in
|
||||
|
||||
let curr_stmt_depth _ =
|
||||
if (Stack.is_empty curr_stmt)
|
||||
then None
|
||||
else
|
||||
Some
|
||||
(get_stmt_depth cx (Stack.top curr_stmt))
|
||||
in
|
||||
|
||||
let cell_of_block_slot
|
||||
?access_depth:(access_depth=curr_stmt_depth())
|
||||
(slot_id:node_id)
|
||||
: Il.cell =
|
||||
|
||||
let referent_type = slot_id_referent_type slot_id in
|
||||
|
||||
let local_access off =
|
||||
Il.Mem (fp_off_sz off, referent_type)
|
||||
in
|
||||
|
||||
let outer_access off slot_depth depth =
|
||||
let _ = assert (slot_depth < depth) in
|
||||
let _ =
|
||||
iflog
|
||||
begin
|
||||
fun _ ->
|
||||
let k =
|
||||
Hashtbl.find cx.ctxt_slot_keys slot_id
|
||||
in
|
||||
annotate (Printf.sprintf
|
||||
"access outer frame slot #%d = %s"
|
||||
(int_of_node slot_id)
|
||||
(Fmt.fmt_to_str Ast.fmt_slot_key k))
|
||||
end
|
||||
in
|
||||
let diff = depth - slot_depth in
|
||||
let _ = annotate "get outer frame pointer" in
|
||||
let fp = get_nth_outer_frame_ptr diff in
|
||||
let _ = annotate "calculate size" in
|
||||
let p =
|
||||
based_sz (get_ty_params_of_current_frame())
|
||||
(fst (force_to_reg (Il.Cell fp))) off
|
||||
in
|
||||
Il.Mem (p, referent_type)
|
||||
in
|
||||
|
||||
match htab_search cx.ctxt_slot_vregs slot_id with
|
||||
Some vr ->
|
||||
begin
|
||||
@ -865,43 +906,15 @@ let trans_visitor
|
||||
Il.Mem (slot_mem, referent_type)
|
||||
end
|
||||
else
|
||||
if (Stack.is_empty curr_stmt)
|
||||
then
|
||||
Il.Mem (fp_off_sz off, referent_type)
|
||||
else
|
||||
let slot_depth = get_slot_depth cx slot_id in
|
||||
let stmt_depth =
|
||||
get_stmt_depth cx (Stack.top curr_stmt)
|
||||
in
|
||||
if slot_depth <> stmt_depth
|
||||
then
|
||||
let _ = assert (slot_depth < stmt_depth) in
|
||||
let _ =
|
||||
iflog
|
||||
begin
|
||||
fun _ ->
|
||||
let k =
|
||||
Hashtbl.find cx.ctxt_slot_keys slot_id
|
||||
in
|
||||
annotate
|
||||
(Printf.sprintf
|
||||
"access outer frame slot #%d = %s"
|
||||
(int_of_node slot_id)
|
||||
(Fmt.fmt_to_str
|
||||
Ast.fmt_slot_key k))
|
||||
end
|
||||
in
|
||||
let diff = stmt_depth - slot_depth in
|
||||
let _ = annotate "get outer frame pointer" in
|
||||
let fp = get_nth_outer_frame_ptr diff in
|
||||
let _ = annotate "calculate size" in
|
||||
let p =
|
||||
based_sz (get_ty_params_of_current_frame())
|
||||
(fst (force_to_reg (Il.Cell fp))) off
|
||||
in
|
||||
Il.Mem (p, referent_type)
|
||||
else
|
||||
Il.Mem (fp_off_sz off, referent_type)
|
||||
match access_depth with
|
||||
None -> local_access off
|
||||
| Some depth ->
|
||||
let slot_depth = get_slot_depth cx slot_id in
|
||||
if slot_depth <> depth
|
||||
then
|
||||
outer_access off slot_depth depth
|
||||
else
|
||||
local_access off
|
||||
end
|
||||
in
|
||||
|
||||
@ -2434,12 +2447,35 @@ let trans_visitor
|
||||
| Ast.EXPR_atom a ->
|
||||
trans_atom a
|
||||
|
||||
and drop_slots_after_block bid : unit =
|
||||
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
|
||||
|
||||
and trans_block (block:Ast.block) : unit =
|
||||
flush_emitter_size_cache();
|
||||
trace_str cx.ctxt_sess.Session.sess_trace_block
|
||||
"entering block";
|
||||
emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups block.id));
|
||||
Array.iter trans_stmt block.node;
|
||||
drop_slots_after_block block.id;
|
||||
trace_str cx.ctxt_sess.Session.sess_trace_block
|
||||
"exiting block";
|
||||
emit Il.Leave;
|
||||
|
@ -449,9 +449,12 @@ type slots_stack = node_id Stack.t;;
|
||||
type block_slots_stack = slots_stack Stack.t;;
|
||||
type frame_block_slots_stack = block_slots_stack Stack.t;;
|
||||
type loop_block_slots_stack = block_slots_stack option Stack.t;;
|
||||
(* like ret drops slots from all blocks in the frame
|
||||
* break from a simple loo drops slots from all block in a loop *)
|
||||
let (loop_blocks:loop_block_slots_stack) =
|
||||
|
||||
(* Like ret drops slots from all blocks in the frame
|
||||
* break from a simple loop drops slots from all block in a loop
|
||||
*)
|
||||
|
||||
let (loop_blocks:loop_block_slots_stack) =
|
||||
let s = Stack.create() in Stack.push None s; s
|
||||
|
||||
let condition_assigning_visitor
|
||||
@ -583,7 +586,7 @@ let condition_assigning_visitor
|
||||
let precond = slot_inits (lval_slots cx lval) in
|
||||
raise_precondition sid precond;
|
||||
in
|
||||
|
||||
|
||||
let visit_stmt_pre s =
|
||||
begin
|
||||
match s.node with
|
||||
@ -1317,11 +1320,12 @@ let lifecycle_visitor
|
||||
|
||||
|
||||
let visit_block_pre b =
|
||||
|
||||
|
||||
let s = Stack.create() in
|
||||
begin
|
||||
match Stack.top loop_blocks with
|
||||
Some loop -> Stack.push s loop | None -> ()
|
||||
match Stack.top loop_blocks with
|
||||
Some loop -> Stack.push s loop
|
||||
| None -> ()
|
||||
end;
|
||||
Stack.push s (Stack.top frame_blocks);
|
||||
begin
|
||||
@ -1337,7 +1341,7 @@ let lifecycle_visitor
|
||||
inner.Walk.visit_block_pre b
|
||||
in
|
||||
|
||||
let note_drops stmt slots =
|
||||
let note_stmt_drops stmt slots =
|
||||
iflog cx
|
||||
begin
|
||||
fun _ ->
|
||||
@ -1352,6 +1356,21 @@ let lifecycle_visitor
|
||||
htab_put cx.ctxt_post_stmt_slot_drops stmt.id slots
|
||||
in
|
||||
|
||||
let note_block_drops bid slots =
|
||||
iflog cx
|
||||
begin
|
||||
fun _ ->
|
||||
log cx "implicit drop of %d slots after block %d: "
|
||||
(List.length slots)
|
||||
(int_of_node bid);
|
||||
List.iter (fun s -> log cx "drop: %a"
|
||||
Ast.sprintf_slot_key
|
||||
(Hashtbl.find cx.ctxt_slot_keys s))
|
||||
slots
|
||||
end;
|
||||
htab_put cx.ctxt_post_block_slot_drops bid slots
|
||||
in
|
||||
|
||||
let filter_live_block_slots slots =
|
||||
List.filter (fun i -> Hashtbl.mem live_block_slots i) slots
|
||||
in
|
||||
@ -1360,37 +1379,24 @@ let lifecycle_visitor
|
||||
inner.Walk.visit_block_post b;
|
||||
begin
|
||||
match Stack.top loop_blocks with
|
||||
Some loop ->
|
||||
ignore(Stack.pop loop);
|
||||
if Stack.is_empty loop then
|
||||
ignore(Stack.pop loop_blocks);
|
||||
Some loop ->
|
||||
ignore (Stack.pop loop);
|
||||
if Stack.is_empty loop
|
||||
then ignore (Stack.pop loop_blocks);
|
||||
| None -> ()
|
||||
end;
|
||||
let block_slots = Stack.pop (Stack.top frame_blocks) in
|
||||
let stmts = b.node in
|
||||
let len = Array.length stmts in
|
||||
if len > 0
|
||||
then
|
||||
begin
|
||||
let s = stmts.(len-1) in
|
||||
match s.node with
|
||||
Ast.STMT_ret _
|
||||
| Ast.STMT_be _
|
||||
| Ast.STMT_break ->
|
||||
() (* Taken care of in visit_stmt_post below. *)
|
||||
| _ ->
|
||||
(* The blk_slots stack we have has accumulated slots in
|
||||
* declaration order as we walked the block; the top of the
|
||||
* stack is the last-declared slot. We want to generate
|
||||
* slot-drop obligations here for the slots in top-down order
|
||||
* (starting with the last-declared) but only hitting those
|
||||
* slots that actually got initialized (went live) at some
|
||||
* point in the block.
|
||||
*)
|
||||
let slots = stk_elts_from_top block_slots in
|
||||
let live = filter_live_block_slots slots in
|
||||
note_drops s live
|
||||
end;
|
||||
(* The blk_slots stack we have has accumulated slots in
|
||||
* declaration order as we walked the block; the top of the
|
||||
* stack is the last-declared slot. We want to generate
|
||||
* slot-drop obligations here for the slots in top-down order
|
||||
* (starting with the last-declared) but only hitting those
|
||||
* slots that actually got initialized (went live) at some
|
||||
* point in the block.
|
||||
*)
|
||||
let slots = stk_elts_from_top block_slots in
|
||||
let live = filter_live_block_slots slots in
|
||||
note_block_drops b.id live
|
||||
in
|
||||
|
||||
let visit_stmt_pre s =
|
||||
@ -1499,33 +1505,34 @@ let lifecycle_visitor
|
||||
|
||||
let visit_stmt_post s =
|
||||
inner.Walk.visit_stmt_post s;
|
||||
let handle_ret_like_stmt block_stack =
|
||||
|
||||
let handle_outward_jump_stmt block_stack =
|
||||
let blocks = stk_elts_from_top block_stack in
|
||||
let slots = List.concat (List.map stk_elts_from_top blocks) in
|
||||
let live = filter_live_block_slots slots in
|
||||
note_drops s live
|
||||
note_stmt_drops s live
|
||||
in
|
||||
match s.node with
|
||||
Ast.STMT_ret _
|
||||
| Ast.STMT_be _ ->
|
||||
handle_ret_like_stmt (Stack.top frame_blocks)
|
||||
| Ast.STMT_break ->
|
||||
begin
|
||||
match (Stack.top loop_blocks) with
|
||||
Some loop -> handle_ret_like_stmt loop
|
||||
| None ->
|
||||
iflog cx (fun _ ->
|
||||
log cx "break statement outside of a loop");
|
||||
err (Some s.id) "break statement outside of a loop"
|
||||
end
|
||||
| _ -> ()
|
||||
|
||||
match s.node with
|
||||
Ast.STMT_ret _
|
||||
| Ast.STMT_be _ ->
|
||||
handle_outward_jump_stmt (Stack.top frame_blocks)
|
||||
|
||||
| Ast.STMT_break ->
|
||||
begin
|
||||
match (Stack.top loop_blocks) with
|
||||
Some loop -> handle_outward_jump_stmt loop
|
||||
| None ->
|
||||
err (Some s.id) "break statement outside of a loop"
|
||||
end
|
||||
| _ -> ()
|
||||
in
|
||||
|
||||
let enter_frame _ =
|
||||
Stack.push (Stack.create()) frame_blocks;
|
||||
Stack.push None loop_blocks
|
||||
in
|
||||
|
||||
|
||||
let leave_frame _ =
|
||||
ignore (Stack.pop frame_blocks);
|
||||
match Stack.pop loop_blocks with
|
||||
|
11
src/test/run-pass/drop-on-empty-block-exit.rs
Normal file
11
src/test/run-pass/drop-on-empty-block-exit.rs
Normal file
@ -0,0 +1,11 @@
|
||||
tag t {
|
||||
foo(@int);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
auto tt = foo(@10);
|
||||
alt (tt) {
|
||||
case (foo(?z)) {
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user