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::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 is_required(&self) -> bool {
74 true
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 {
98 source_info,
99 kind: TerminatorKind::Goto { target },
100 attributes: ThinVec::new(),
101 }),
102 is_cleanup,
103 ));
104
105 patch.add_statement(loc, StatementKind::StorageLive(temp));
106 patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place), WithRetag::Yes));
107 patch.patch_terminator(
108 loc.block,
109 TerminatorKind::Drop {
110 place: Place::from(temp),
111 target: storage_dead_block,
112 unwind,
113 replace,
114 drop,
115 },
116 );
117}