1 use rustc::hir::def_id::DefId;
5 use crate::transform::{MirPass, MirSource};
6 use crate::util::patch::MirPatch;
9 // This pass moves values being dropped that are within a packed
10 // struct to a separate local before dropping them, to ensure that
11 // they are dropped from an aligned address.
13 // For example, if we have something like
24 // We want to call `drop_in_place::<Vec<u8>>` on `data` from an aligned
25 // address. This means we can't simply drop `foo.data` directly, because
26 // its address is not aligned.
28 // Instead, we move `foo.data` to a local and drop that:
30 // storage.live(drop_temp)
31 // drop_temp = foo.data;
32 // drop(drop_temp) -> next
34 // storage.dead(drop_temp)
37 // The storage instructions are required to avoid stack space
40 pub struct AddMovesForPackedDrops;
42 impl MirPass for AddMovesForPackedDrops {
43 fn run_pass<'a, 'tcx>(&self,
44 tcx: TyCtxt<'a, 'tcx, 'tcx>,
48 debug!("add_moves_for_packed_drops({:?} @ {:?})", src, mir.span);
49 add_moves_for_packed_drops(tcx, mir, src.def_id());
53 pub fn add_moves_for_packed_drops<'a, 'tcx>(
54 tcx: TyCtxt<'a, 'tcx, 'tcx>,
58 let patch = add_moves_for_packed_drops_patch(tcx, mir, def_id);
62 fn add_moves_for_packed_drops_patch<'a, 'tcx>(
63 tcx: TyCtxt<'a, 'tcx, 'tcx>,
68 let mut patch = MirPatch::new(mir);
69 let param_env = tcx.param_env(def_id);
71 for (bb, data) in mir.basic_blocks().iter_enumerated() {
72 let loc = Location { block: bb, statement_index: data.statements.len() };
73 let terminator = data.terminator();
75 match terminator.kind {
76 TerminatorKind::Drop { ref location, .. }
77 if util::is_disaligned(tcx, mir, param_env, location) =>
79 add_move_for_packed_drop(tcx, mir, &mut patch, terminator,
80 loc, data.is_cleanup);
82 TerminatorKind::DropAndReplace { .. } => {
83 span_bug!(terminator.source_info.span,
84 "replace in AddMovesForPackedDrops");
93 fn add_move_for_packed_drop<'a, 'tcx>(
94 tcx: TyCtxt<'a, 'tcx, 'tcx>,
96 patch: &mut MirPatch<'tcx>,
97 terminator: &Terminator<'tcx>,
101 debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
102 let (location, target, unwind) = match terminator.kind {
103 TerminatorKind::Drop { ref location, target, unwind } =>
104 (location, target, unwind),
108 let source_info = terminator.source_info;
109 let ty = location.ty(mir, tcx).to_ty(tcx);
110 let temp = patch.new_temp(ty, terminator.source_info.span);
112 let storage_dead_block = patch.new_block(BasicBlockData {
113 statements: vec![Statement {
114 source_info, kind: StatementKind::StorageDead(temp)
116 terminator: Some(Terminator {
117 source_info, kind: TerminatorKind::Goto { target }
123 loc, StatementKind::StorageLive(temp));
124 patch.add_assign(loc, Place::Base(PlaceBase::Local(temp)),
125 Rvalue::Use(Operand::Move(location.clone())));
126 patch.patch_terminator(loc.block, TerminatorKind::Drop {
127 location: Place::Base(PlaceBase::Local(temp)),
128 target: storage_dead_block,