about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorDianQK <dianqk@dianqk.net>2024-02-14 12:02:22 +0800
committerDianQK <dianqk@dianqk.net>2024-03-07 22:58:51 +0800
commit08ae8380ce75b4a19c4a7bfa33eac8776daef532 (patch)
treed99aa37997c1e213eccb92f77144bc49130241f5 /compiler/rustc_mir_transform/src
parentd8b7b5be7d4738dae63fbc35ed4b44ef97cf7ca2 (diff)
downloadrust-08ae8380ce75b4a19c4a7bfa33eac8776daef532.tar.gz
rust-08ae8380ce75b4a19c4a7bfa33eac8776daef532.zip
Replace the default branch with an unreachable branch If it is the last variant
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs24
1 files changed, 18 insertions, 6 deletions
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index e68d37f4c70..d3408d4882f 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -78,6 +78,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
         trace!("UninhabitedEnumBranching starting for {:?}", body.source);
 
         let mut removable_switchs = Vec::new();
+        let mut otherwise_is_last_variant_switchs = Vec::new();
 
         for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
             trace!("processing block {:?}", bb);
@@ -92,7 +93,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
                 tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty),
             );
 
-            let allowed_variants = if let Ok(layout) = layout {
+            let mut allowed_variants = if let Ok(layout) = layout {
                 variant_discriminants(&layout, discriminant_ty, tcx)
             } else {
                 continue;
@@ -103,20 +104,31 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
             let terminator = bb_data.terminator();
             let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() };
 
-            let mut reachable_count = 0;
             for (index, (val, _)) in targets.iter().enumerate() {
-                if allowed_variants.contains(&val) {
-                    reachable_count += 1;
-                } else {
+                if !allowed_variants.remove(&val) {
                     removable_switchs.push((bb, index));
                 }
             }
 
-            if reachable_count == allowed_variants.len() {
+            if allowed_variants.is_empty() {
                 removable_switchs.push((bb, targets.iter().count()));
+            } else if allowed_variants.len() == 1
+                && !body.basic_blocks[targets.otherwise()].is_empty_unreachable()
+            {
+                #[allow(rustc::potential_query_instability)]
+                let last_variant = *allowed_variants.iter().next().unwrap();
+                otherwise_is_last_variant_switchs.push((bb, last_variant));
             }
         }
 
+        for (bb, last_variant) in otherwise_is_last_variant_switchs {
+            let bb_data = &mut body.basic_blocks.as_mut()[bb];
+            let terminator = bb_data.terminator_mut();
+            let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() };
+            targets.add_target(last_variant, targets.otherwise());
+            removable_switchs.push((bb, targets.iter().count()));
+        }
+
         if removable_switchs.is_empty() {
             return;
         }