Remove dead unwinds before drop elaboration
As a part of drop elaboration, we identify dead unwinds, i.e., unwind edges on a drop terminators which are known to be unreachable, because there is no need to drop anything. Previously, the data flow framework was informed about the dead unwinds, and it assumed those edges are absent from MIR. Unfortunately, the data flow framework wasn't consistent in maintaining this assumption. In particular, if a block was reachable only through a dead unwind edge, its state was propagated to other blocks still. This became an issue in the context of change removes DropAndReplace terminator, since it introduces initialization into cleanup blocks. To avoid this issue, remove unreachable unwind edges before the drop elaboration, and elaborate only blocks that remain reachable.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use std::ops::RangeInclusive;
|
||||
@@ -54,7 +53,6 @@ pub trait Direction {
|
||||
analysis: &A,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &mir::Body<'tcx>,
|
||||
dead_unwinds: Option<&BitSet<BasicBlock>>,
|
||||
exit_state: &mut A::Domain,
|
||||
block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
|
||||
propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
@@ -221,7 +219,6 @@ impl Direction for Backward {
|
||||
analysis: &A,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
body: &mir::Body<'tcx>,
|
||||
dead_unwinds: Option<&BitSet<BasicBlock>>,
|
||||
exit_state: &mut A::Domain,
|
||||
(bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
@@ -278,20 +275,6 @@ impl Direction for Backward {
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore dead unwinds.
|
||||
mir::TerminatorKind::Call { cleanup: Some(unwind), .. }
|
||||
| mir::TerminatorKind::Assert { cleanup: Some(unwind), .. }
|
||||
| mir::TerminatorKind::Drop { unwind: Some(unwind), .. }
|
||||
| mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. }
|
||||
| mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. }
|
||||
| mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
|
||||
if unwind == bb =>
|
||||
{
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(pred)) {
|
||||
propagate(pred, exit_state);
|
||||
}
|
||||
}
|
||||
|
||||
_ => propagate(pred, exit_state),
|
||||
}
|
||||
}
|
||||
@@ -304,7 +287,6 @@ struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> {
|
||||
exit_state: &'a mut D,
|
||||
bb: BasicBlock,
|
||||
propagate: &'a mut F,
|
||||
|
||||
effects_applied: bool,
|
||||
}
|
||||
|
||||
@@ -484,7 +466,6 @@ impl Direction for Forward {
|
||||
analysis: &A,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
_body: &mir::Body<'tcx>,
|
||||
dead_unwinds: Option<&BitSet<BasicBlock>>,
|
||||
exit_state: &mut A::Domain,
|
||||
(bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
|
||||
mut propagate: impl FnMut(BasicBlock, &A::Domain),
|
||||
@@ -502,9 +483,7 @@ impl Direction for Forward {
|
||||
| DropAndReplace { target, unwind, value: _, place: _ }
|
||||
| FalseUnwind { real_target: target, unwind } => {
|
||||
if let Some(unwind) = unwind {
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
|
||||
propagate(target, exit_state);
|
||||
@@ -534,9 +513,7 @@ impl Direction for Forward {
|
||||
fn_span: _,
|
||||
} => {
|
||||
if let Some(unwind) = cleanup {
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
|
||||
if let Some(target) = target {
|
||||
@@ -560,9 +537,7 @@ impl Direction for Forward {
|
||||
cleanup,
|
||||
} => {
|
||||
if let Some(unwind) = cleanup {
|
||||
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
|
||||
if let Some(target) = destination {
|
||||
|
||||
Reference in New Issue
Block a user