Skip to content

Commit 3a5c078

Browse files
committed
Extend uninhabited match branch optimization to also work on fallthrough.
The `uninhabited_enum_branch` miropt now also checks whether the fallthrough case is inhabited, and if not will ensure that it points to an unreachable block.
1 parent 30b3f35 commit 3a5c078

File tree

1 file changed

+39
-3
lines changed

1 file changed

+39
-3
lines changed

compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
use crate::MirPass;
44
use rustc_data_structures::stable_set::FxHashSet;
55
use rustc_middle::mir::{
6-
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind,
6+
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator,
7+
TerminatorKind,
78
};
89
use rustc_middle::ty::layout::TyAndLayout;
910
use rustc_middle::ty::{Ty, TyCtxt};
@@ -71,6 +72,28 @@ fn variant_discriminants<'tcx>(
7172
}
7273
}
7374

75+
/// Ensures that the `otherwise` branch leads to an unreachable bb, returning `None` if so and a new
76+
/// bb to use as the new target if not.
77+
fn ensure_otherwise_unreachable<'tcx>(
78+
body: &Body<'tcx>,
79+
targets: &SwitchTargets,
80+
) -> Option<BasicBlockData<'tcx>> {
81+
let otherwise = targets.otherwise();
82+
let bb = &body.basic_blocks()[otherwise];
83+
if bb.terminator().kind == TerminatorKind::Unreachable
84+
&& bb.statements.iter().all(|s| matches!(&s.kind, StatementKind::StorageDead(_)))
85+
{
86+
return None;
87+
}
88+
89+
let mut new_block = BasicBlockData::new(Some(Terminator {
90+
source_info: bb.terminator().source_info,
91+
kind: TerminatorKind::Unreachable,
92+
}));
93+
new_block.is_cleanup = bb.is_cleanup;
94+
Some(new_block)
95+
}
96+
7497
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
7598
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
7699
sess.mir_opt_level() > 0
@@ -99,12 +122,25 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
99122
if let TerminatorKind::SwitchInt { targets, .. } =
100123
&mut body.basic_blocks_mut()[bb].terminator_mut().kind
101124
{
102-
let new_targets = SwitchTargets::new(
125+
let mut new_targets = SwitchTargets::new(
103126
targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
104127
targets.otherwise(),
105128
);
106129

107-
*targets = new_targets;
130+
if new_targets.iter().count() == allowed_variants.len() {
131+
if let Some(updated) = ensure_otherwise_unreachable(body, &new_targets) {
132+
let new_otherwise = body.basic_blocks_mut().push(updated);
133+
*new_targets.all_targets_mut().last_mut().unwrap() = new_otherwise;
134+
}
135+
}
136+
137+
if let TerminatorKind::SwitchInt { targets, .. } =
138+
&mut body.basic_blocks_mut()[bb].terminator_mut().kind
139+
{
140+
*targets = new_targets;
141+
} else {
142+
unreachable!()
143+
}
108144
} else {
109145
unreachable!()
110146
}

0 commit comments

Comments
 (0)