rustc_mir_transform/
add_moves_for_packed_drops.rs1use rustc_middle::mir::*;
2use rustc_middle::ty::{self, TyCtxt};
3use tracing::debug;
4
5use crate::patch::MirPatch;
6use crate::{PassPolicy, util};
7
8pub(super) struct AddMovesForPackedDrops;
39
40impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
41 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
42 debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
43 let mut patch = MirPatch::new(body);
44 let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
47
48 for (bb, data) in body.basic_blocks.iter_enumerated() {
49 let loc = Location { block: bb, statement_index: data.statements.len() };
50 let terminator = data.terminator();
51
52 match terminator.kind {
53 TerminatorKind::Drop { place, .. }
54 if util::place_unalignment(tcx, body, typing_env, place).is_some() =>
55 {
56 add_move_for_packed_drop(
57 tcx,
58 body,
59 &mut patch,
60 terminator,
61 loc,
62 data.is_cleanup,
63 );
64 }
65 _ => {}
66 }
67 }
68
69 patch.apply(body);
70 }
71
72 fn policy(&self, _ctx: &crate::PassCtx<'_>) -> PassPolicy {
73 PassPolicy::Required
75 }
76}
77
78fn add_move_for_packed_drop<'tcx>(
79 tcx: TyCtxt<'tcx>,
80 body: &Body<'tcx>,
81 patch: &mut MirPatch<'tcx>,
82 terminator: &Terminator<'tcx>,
83 loc: Location,
84 is_cleanup: bool,
85) {
86 debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
87 let TerminatorKind::Drop { ref place, target, unwind, replace, drop } = terminator.kind else {
88 unreachable!();
89 };
90
91 let source_info = terminator.source_info;
92 let ty = place.ty(body, tcx).ty;
93 let temp = patch.new_temp(ty, source_info.span);
94
95 let storage_dead_block = patch.new_block(BasicBlockData::new_stmts(
96 vec![Statement::new(source_info, StatementKind::StorageDead(temp))],
97 Some(Terminator { source_info, kind: TerminatorKind::goto(target) }),
98 is_cleanup,
99 ));
100
101 patch.add_statement(loc, StatementKind::StorageLive(temp));
102 patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place), WithRetag::Yes));
103 patch.patch_terminator(
104 loc.block,
105 TerminatorKind::Drop {
106 place: Place::from(temp),
107 target: storage_dead_block,
108 unwind,
109 replace,
110 drop,
111 },
112 );
113}