|
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