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::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::is_disaligned(tcx, body, typing_env, place) =>
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 is_required(&self) -> bool {
73 true
74 }
75}
76
77fn add_move_for_packed_drop<'tcx>(
78 tcx: TyCtxt<'tcx>,
79 body: &Body<'tcx>,
80 patch: &mut MirPatch<'tcx>,
81 terminator: &Terminator<'tcx>,
82 loc: Location,
83 is_cleanup: bool,
84) {
85 debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
86 let TerminatorKind::Drop { ref place, target, unwind, replace, drop, async_fut } =
87 terminator.kind
88 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 {
97 statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }],
98 terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
99 is_cleanup,
100 });
101
102 patch.add_statement(loc, StatementKind::StorageLive(temp));
103 patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
104 patch.patch_terminator(
105 loc.block,
106 TerminatorKind::Drop {
107 place: Place::from(temp),
108 target: storage_dead_block,
109 unwind,
110 replace,
111 drop,
112 async_fut,
113 },
114 );
115}