|
3 | 3 | use crate::MirPass;
|
4 | 4 | use rustc_data_structures::stable_set::FxHashSet;
|
5 | 5 | use rustc_middle::mir::{
|
6 |
| - BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind, |
| 6 | + BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator, |
| 7 | + TerminatorKind, |
7 | 8 | };
|
8 | 9 | use rustc_middle::ty::layout::TyAndLayout;
|
9 | 10 | use rustc_middle::ty::{Ty, TyCtxt};
|
@@ -71,6 +72,28 @@ fn variant_discriminants<'tcx>(
|
71 | 72 | }
|
72 | 73 | }
|
73 | 74 |
|
| 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 | + |
74 | 97 | impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
|
75 | 98 | fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
76 | 99 | sess.mir_opt_level() > 0
|
@@ -99,12 +122,25 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
|
99 | 122 | if let TerminatorKind::SwitchInt { targets, .. } =
|
100 | 123 | &mut body.basic_blocks_mut()[bb].terminator_mut().kind
|
101 | 124 | {
|
102 |
| - let new_targets = SwitchTargets::new( |
| 125 | + let mut new_targets = SwitchTargets::new( |
103 | 126 | targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
|
104 | 127 | targets.otherwise(),
|
105 | 128 | );
|
106 | 129 |
|
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 | + } |
108 | 144 | } else {
|
109 | 145 | unreachable!()
|
110 | 146 | }
|
|
0 commit comments