]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / compiler / rustc_mir_transform / src / add_moves_for_packed_drops.rs
CommitLineData
ba9703b0
XL
1use rustc_middle::mir::*;
2use rustc_middle::ty::TyCtxt;
ff7c6d11 3
9fa01778 4use crate::util;
c295e0f8
XL
5use crate::MirPass;
6use 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
39pub struct AddMovesForPackedDrops;
40
e1599b0c 41impl<'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
48pub 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
53fn 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
78fn 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}