Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 48 additions & 33 deletions compiler/rustc_mir_transform/src/elaborate_drop.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{fmt, iter, mem};

use itertools::Itertools;
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{CoroutineDesugaring, CoroutineKind};
Expand Down Expand Up @@ -798,6 +799,7 @@ where

(tcx.mk_place_field(base_place, field_idx, field_ty), subpath)
})
.filter(|path| self.should_retain_for_ladder(path))
.collect()
}

Expand Down Expand Up @@ -875,6 +877,19 @@ where
)
}

/// Whether this drop is useful. This is purely an optimization to avoid generating useless blocks.
fn should_retain_for_ladder(&self, (place, subpath): &(Place<'tcx>, Option<D::Path>)) -> bool {
if !self.place_ty(*place).needs_drop(self.tcx(), self.elaborator.typing_env()) {
return false;
}
if let Some(subpath) = subpath
&& let DropStyle::Dead = self.elaborator.drop_style(*subpath, DropFlagMode::Deep)
{
return false;
}
true
}

/// Creates a full drop ladder, consisting of 2 connected half-drop-ladders
///
/// For example, with 3 fields, the drop ladder is
Expand Down Expand Up @@ -915,7 +930,7 @@ where
#[instrument(level = "debug", skip(self), ret)]
fn drop_ladder(
&mut self,
fields: Vec<(Place<'tcx>, Option<D::Path>)>,
mut fields: Vec<(Place<'tcx>, Option<D::Path>)>,
succ: BasicBlock,
unwind: Unwind,
dropline: Option<BasicBlock>,
Expand All @@ -925,10 +940,7 @@ where
"Dropline is set for cleanup drop ladder"
);

let mut fields = fields;
fields.retain(|&(place, _)| {
self.place_ty(place).needs_drop(self.tcx(), self.elaborator.typing_env())
});
fields.retain(|path| self.should_retain_for_ladder(path));

debug!("drop_ladder - fields needing drop: {:?}", fields);

Expand Down Expand Up @@ -1149,15 +1161,21 @@ where
if !have_otherwise {
values.pop();
} else if !have_otherwise_with_drop_glue {
normal_blocks.push(self.goto_block(succ, unwind));
normal_blocks.push(succ);
if let Unwind::To(unwind) = unwind {
unwind_blocks.push(self.goto_block(unwind, Unwind::InCleanup));
unwind_blocks.push(unwind);
}
if let Some(dropline) = dropline {
dropline_blocks.push(dropline);
}
} else {
normal_blocks.push(self.drop_block(succ, unwind));
if let Unwind::To(unwind) = unwind {
unwind_blocks.push(self.drop_block(unwind, Unwind::InCleanup));
}
if let Some(dropline) = dropline {
dropline_blocks.push(self.drop_block(dropline, unwind));
}
}

(
Expand All @@ -1179,27 +1197,29 @@ where
succ: BasicBlock,
unwind: Unwind,
) -> BasicBlock {
// If there are multiple variants, then if something
// is present within the enum the discriminant, tracked
// by the rest path, must be initialized.
//
// Additionally, we do not want to switch on the
// discriminant after it is free-ed, because that
// way lies only trouble.
let discr_ty = adt.repr().discr_type().to_ty(self.tcx());
let discr = Place::from(self.new_temp(discr_ty));
let discr_rv = Rvalue::Discriminant(self.place);
let switch_block = self.new_block_with_statements(
unwind,
vec![self.assign(discr, discr_rv)],
TerminatorKind::SwitchInt {
discr: Operand::Move(discr),
targets: SwitchTargets::new(
values.iter().copied().zip(blocks.iter().copied()),
*blocks.last().unwrap(),
),
},
);
let switch_block = blocks.iter().copied().all_equal_value().unwrap_or_else(|_| {
// If there are multiple variants, then if something
// is present within the enum the discriminant, tracked
// by the rest path, must be initialized.
//
// Additionally, we do not want to switch on the
// discriminant after it is free-ed, because that
// way lies only trouble.
let discr_ty = adt.repr().discr_type().to_ty(self.tcx());
let discr = Place::from(self.new_temp(discr_ty));
let discr_rv = Rvalue::Discriminant(self.place);
self.new_block_with_statements(
unwind,
vec![self.assign(discr, discr_rv)],
TerminatorKind::SwitchInt {
discr: Operand::Move(discr),
targets: SwitchTargets::new(
values.iter().copied().zip(blocks.iter().copied()),
*blocks.last().unwrap(),
),
},
)
});
self.drop_flag_test_block(switch_block, succ, unwind)
}

Expand Down Expand Up @@ -1580,11 +1600,6 @@ where
}
}

fn goto_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let block = TerminatorKind::Goto { target };
self.new_block(unwind, block)
}

/// Returns the block to jump to in order to test the drop flag and execute the drop.
///
/// Depending on the required `DropStyle`, this might be a generated block with an `if`
Expand Down
Loading
Loading