|
2 | 2 |
|
3 | 3 | use crate::MirPass;
|
4 | 4 | use rustc_data_structures::fx::FxHashSet;
|
| 5 | +use rustc_middle::mir::patch::MirPatch; |
5 | 6 | use rustc_middle::mir::{
|
6 |
| - BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, Terminator, TerminatorKind, |
| 7 | + BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind, |
7 | 8 | };
|
8 | 9 | use rustc_middle::ty::layout::TyAndLayout;
|
9 | 10 | use rustc_middle::ty::{Ty, TyCtxt};
|
@@ -77,8 +78,8 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
|
77 | 78 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
78 | 79 | trace!("UninhabitedEnumBranching starting for {:?}", body.source);
|
79 | 80 |
|
80 |
| - let mut removable_switchs = Vec::new(); |
81 |
| - let mut otherwise_is_last_variant_switchs = Vec::new(); |
| 81 | + let mut unreachable_targets = Vec::new(); |
| 82 | + let mut patch = MirPatch::new(body); |
82 | 83 |
|
83 | 84 | for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
84 | 85 | trace!("processing block {:?}", bb);
|
@@ -107,49 +108,41 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
|
107 | 108 |
|
108 | 109 | trace!("allowed_variants = {:?}", allowed_variants);
|
109 | 110 |
|
110 |
| - let terminator = bb_data.terminator(); |
111 |
| - let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() }; |
| 111 | + unreachable_targets.clear(); |
| 112 | + let TerminatorKind::SwitchInt { targets, discr } = &bb_data.terminator().kind else { |
| 113 | + bug!() |
| 114 | + }; |
112 | 115 |
|
113 | 116 | for (index, (val, _)) in targets.iter().enumerate() {
|
114 | 117 | if !allowed_variants.remove(&val) {
|
115 |
| - removable_switchs.push((bb, index)); |
| 118 | + unreachable_targets.push(index); |
116 | 119 | }
|
117 | 120 | }
|
118 | 121 |
|
119 |
| - if allowed_variants.is_empty() { |
120 |
| - removable_switchs.push((bb, targets.iter().count())); |
121 |
| - } else if allowed_variants.len() == 1 |
122 |
| - && !body.basic_blocks[targets.otherwise()].is_empty_unreachable() |
123 |
| - { |
124 |
| - #[allow(rustc::potential_query_instability)] |
125 |
| - let last_variant = *allowed_variants.iter().next().unwrap(); |
126 |
| - otherwise_is_last_variant_switchs.push((bb, last_variant)); |
127 |
| - } |
128 |
| - } |
| 122 | + let replace_otherwise_to_unreachable = allowed_variants.len() <= 1 |
| 123 | + && !body.basic_blocks[targets.otherwise()].is_empty_unreachable(); |
129 | 124 |
|
130 |
| - for (bb, last_variant) in otherwise_is_last_variant_switchs { |
131 |
| - let bb_data = &mut body.basic_blocks.as_mut()[bb]; |
132 |
| - let terminator = bb_data.terminator_mut(); |
133 |
| - let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() }; |
134 |
| - targets.add_target(last_variant, targets.otherwise()); |
135 |
| - removable_switchs.push((bb, targets.iter().count())); |
136 |
| - } |
| 125 | + if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable { |
| 126 | + continue; |
| 127 | + } |
137 | 128 |
|
138 |
| - if removable_switchs.is_empty() { |
139 |
| - return; |
| 129 | + let unreachable_block = patch.unreachable_no_cleanup_block(); |
| 130 | + let mut targets = targets.clone(); |
| 131 | + if replace_otherwise_to_unreachable { |
| 132 | + let otherwise_is_last_variant = !allowed_variants.is_empty(); |
| 133 | + if otherwise_is_last_variant { |
| 134 | + #[allow(rustc::potential_query_instability)] |
| 135 | + let last_variant = *allowed_variants.iter().next().unwrap(); |
| 136 | + targets.add_target(last_variant, targets.otherwise()); |
| 137 | + } |
| 138 | + unreachable_targets.push(targets.iter().count()); |
| 139 | + } |
| 140 | + for index in unreachable_targets.iter() { |
| 141 | + targets.all_targets_mut()[*index] = unreachable_block; |
| 142 | + } |
| 143 | + patch.patch_terminator(bb, TerminatorKind::SwitchInt { targets, discr: discr.clone() }); |
140 | 144 | }
|
141 | 145 |
|
142 |
| - let new_block = BasicBlockData::new(Some(Terminator { |
143 |
| - source_info: body.basic_blocks[removable_switchs[0].0].terminator().source_info, |
144 |
| - kind: TerminatorKind::Unreachable, |
145 |
| - })); |
146 |
| - let unreachable_block = body.basic_blocks.as_mut().push(new_block); |
147 |
| - |
148 |
| - for (bb, index) in removable_switchs { |
149 |
| - let bb = &mut body.basic_blocks.as_mut()[bb]; |
150 |
| - let terminator = bb.terminator_mut(); |
151 |
| - let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() }; |
152 |
| - targets.all_targets_mut()[index] = unreachable_block; |
153 |
| - } |
| 146 | + patch.apply(body); |
154 | 147 | }
|
155 | 148 | }
|
0 commit comments