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