]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | use rustc_middle::mir::*; |
2 | use rustc_middle::ty::TyCtxt; | |
ff7c6d11 | 3 | |
9fa01778 | 4 | use crate::util; |
c295e0f8 XL |
5 | use crate::MirPass; |
6 | use rustc_middle::mir::patch::MirPatch; | |
ff7c6d11 XL |
7 | |
8 | // This pass moves values being dropped that are within a packed | |
9 | // struct to a separate local before dropping them, to ensure that | |
10 | // they are dropped from an aligned address. | |
11 | // | |
12 | // For example, if we have something like | |
13 | // ```Rust | |
14 | // #[repr(packed)] | |
15 | // struct Foo { | |
16 | // dealign: u8, | |
17 | // data: Vec<u8> | |
18 | // } | |
19 | // | |
20 | // let foo = ...; | |
21 | // ``` | |
22 | // | |
23 | // We want to call `drop_in_place::<Vec<u8>>` on `data` from an aligned | |
24 | // address. This means we can't simply drop `foo.data` directly, because | |
25 | // its address is not aligned. | |
26 | // | |
27 | // Instead, we move `foo.data` to a local and drop that: | |
28 | // ``` | |
29 | // storage.live(drop_temp) | |
30 | // drop_temp = foo.data; | |
31 | // drop(drop_temp) -> next | |
32 | // next: | |
33 | // storage.dead(drop_temp) | |
34 | // ``` | |
35 | // | |
36 | // The storage instructions are required to avoid stack space | |
37 | // blowup. | |
38 | ||
39 | pub struct AddMovesForPackedDrops; | |
40 | ||
e1599b0c | 41 | impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { |
29967ef6 XL |
42 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { |
43 | debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); | |
44 | add_moves_for_packed_drops(tcx, body); | |
ff7c6d11 XL |
45 | } |
46 | } | |
47 | ||
29967ef6 XL |
48 | pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { |
49 | let patch = add_moves_for_packed_drops_patch(tcx, body); | |
dc9dc135 | 50 | patch.apply(body); |
ff7c6d11 XL |
51 | } |
52 | ||
29967ef6 XL |
53 | fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> { |
54 | let def_id = body.source.def_id(); | |
dc9dc135 | 55 | let mut patch = MirPatch::new(body); |
ff7c6d11 XL |
56 | let param_env = tcx.param_env(def_id); |
57 | ||
f2b60f7d | 58 | for (bb, data) in body.basic_blocks.iter_enumerated() { |
ff7c6d11 XL |
59 | let loc = Location { block: bb, statement_index: data.statements.len() }; |
60 | let terminator = data.terminator(); | |
61 | ||
62 | match terminator.kind { | |
f035d41b XL |
63 | TerminatorKind::Drop { place, .. } |
64 | if util::is_disaligned(tcx, body, param_env, place) => | |
ff7c6d11 | 65 | { |
dfeec247 | 66 | add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); |
ff7c6d11 XL |
67 | } |
68 | TerminatorKind::DropAndReplace { .. } => { | |
dfeec247 | 69 | span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops"); |
ff7c6d11 XL |
70 | } |
71 | _ => {} | |
72 | } | |
73 | } | |
74 | ||
75 | patch | |
76 | } | |
77 | ||
dc9dc135 XL |
78 | fn add_move_for_packed_drop<'tcx>( |
79 | tcx: TyCtxt<'tcx>, | |
80 | body: &Body<'tcx>, | |
ff7c6d11 XL |
81 | patch: &mut MirPatch<'tcx>, |
82 | terminator: &Terminator<'tcx>, | |
83 | loc: Location, | |
dc9dc135 XL |
84 | is_cleanup: bool, |
85 | ) { | |
ff7c6d11 | 86 | debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); |
5e7ed085 FG |
87 | let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else { |
88 | unreachable!(); | |
ff7c6d11 XL |
89 | }; |
90 | ||
91 | let source_info = terminator.source_info; | |
f035d41b | 92 | let ty = place.ty(body, tcx).ty; |
ff7c6d11 XL |
93 | let temp = patch.new_temp(ty, terminator.source_info.span); |
94 | ||
95 | let storage_dead_block = patch.new_block(BasicBlockData { | |
dfeec247 XL |
96 | statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], |
97 | terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), | |
98 | is_cleanup, | |
ff7c6d11 XL |
99 | }); |
100 | ||
dfeec247 | 101 | patch.add_statement(loc, StatementKind::StorageLive(temp)); |
f035d41b | 102 | patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); |
dfeec247 XL |
103 | patch.patch_terminator( |
104 | loc.block, | |
f035d41b | 105 | TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, |
dfeec247 | 106 | ); |
ff7c6d11 | 107 | } |