about summary refs log tree commit diff
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
parentd8b7b5be7d4738dae63fbc35ed4b44ef97cf7ca2 (diff)
downloadrust-08ae8380ce75b4a19c4a7bfa33eac8776daef532.tar.gz
rust-08ae8380ce75b4a19c4a7bfa33eac8776daef532.zip
Replace the default branch with an unreachable branch If it is the last variant
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs11
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs24
-rw-r--r--tests/codegen/enum/uninhabited_enum_default_branch.rs24
-rw-r--r--tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff6
-rw-r--r--tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff6
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff53
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff53
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff44
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff44
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff53
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff53
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff48
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff48
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff62
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff62
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff75
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff75
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff61
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff65
-rw-r--r--tests/mir-opt/uninhabited_enum_branching.rs127
-rw-r--r--tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff2
23 files changed, 997 insertions, 11 deletions
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 6c92dfa3cd8..ae3daa77b1c 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -74,6 +74,17 @@ impl SwitchTargets {
     pub fn target_for_value(&self, value: u128) -> BasicBlock {
         self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
     }
+
+    /// Adds a new target to the switch. But You cannot add an already present value.
+    #[inline]
+    pub fn add_target(&mut self, value: u128, bb: BasicBlock) {
+        let value = Pu128(value);
+        if self.values.contains(&value) {
+            bug!("target value {:?} already present", value);
+        }
+        self.values.push(value);
+        self.targets.insert(self.targets.len() - 1, bb);
+    }
 }
 
 pub struct SwitchTargetsIter<'a> {
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;
         }
diff --git a/tests/codegen/enum/uninhabited_enum_default_branch.rs b/tests/codegen/enum/uninhabited_enum_default_branch.rs
new file mode 100644
index 00000000000..5f318f18dec
--- /dev/null
+++ b/tests/codegen/enum/uninhabited_enum_default_branch.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Int(u32);
+
+const A: Int = Int(201);
+const B: Int = Int(270);
+const C: Int = Int(153);
+
+// CHECK-LABEL: @foo(
+// CHECK-SAME: [[TMP0:%.*]])
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], -201
+// CHECK-NEXT:    icmp ult i32 [[TMP1]], 70
+// CHECK-NEXT:    icmp eq i32 [[TMP0]], 153
+// CHECK-NEXT:    [[SPEC_SELECT:%.*]] = or i1
+// CHECK-NEXT:    ret i1 [[SPEC_SELECT]]
+#[no_mangle]
+pub fn foo(x: Int) -> bool {
+    (x >= A && x <= B)
+        || x == C
+}
diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff
index 080478ea884..bd346af6d16 100644
--- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff
+++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff
@@ -69,7 +69,7 @@
           StorageLive(_6);
           _6 = ((*_1).4: std::option::Option<usize>);
           _7 = discriminant(_6);
-          switchInt(move _7) -> [1: bb4, otherwise: bb6];
+          switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9];
       }
   
       bb4: {
@@ -135,5 +135,9 @@
           StorageDead(_6);
           return;
       }
+  
+      bb9: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff
index ff8933fca8b..422cbeaa224 100644
--- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff
+++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff
@@ -69,7 +69,7 @@
           StorageLive(_6);
           _6 = ((*_1).4: std::option::Option<usize>);
           _7 = discriminant(_6);
-          switchInt(move _7) -> [1: bb4, otherwise: bb6];
+          switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9];
       }
   
       bb4: {
@@ -135,5 +135,9 @@
           StorageDead(_6);
           return;
       }
+  
+      bb9: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff
index 1566d7197ac..3108b7d3e13 100644
--- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff
+++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff
@@ -23,7 +23,7 @@
           StorageDead(_3);
           StorageDead(_2);
           _5 = discriminant((_1.0: std::option::Option<u8>));
-          switchInt(move _5) -> [1: bb1, otherwise: bb3];
+          switchInt(move _5) -> [1: bb1, 0: bb3, otherwise: bb5];
       }
   
       bb1: {
@@ -46,5 +46,9 @@
           StorageDead(_1);
           return;
       }
+  
+      bb5: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
index ba5262b0ee1..3ef3be198ed 100644
--- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
+++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
@@ -23,7 +23,7 @@
           StorageDead(_3);
           StorageDead(_2);
           _5 = discriminant((_1.0: std::option::Option<u8>));
-          switchInt(move _5) -> [1: bb1, otherwise: bb3];
+          switchInt(move _5) -> [1: bb1, 0: bb3, otherwise: bb5];
       }
   
       bb1: {
@@ -46,5 +46,9 @@
           StorageDead(_1);
           return;
       }
+  
+      bb5: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..383fde4d787
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,53 @@
+- // MIR for `otherwise_t1` before UninhabitedEnumBranching
++ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+  
+  fn otherwise_t1() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test1;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test1::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(Empty)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(Empty)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb5: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..383fde4d787
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,53 @@
+- // MIR for `otherwise_t1` before UninhabitedEnumBranching
++ // MIR for `otherwise_t1` after UninhabitedEnumBranching
+  
+  fn otherwise_t1() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test1;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test1::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(Empty)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(Empty)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb5: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..3a2dc19db71
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,44 @@
+- // MIR for `otherwise_t2` before UninhabitedEnumBranching
++ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+  
+  fn otherwise_t2() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test2;
+      let mut _3: isize;
+      let _4: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test2::D;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [4: bb2, otherwise: bb1];
++         switchInt(move _3) -> [4: bb2, 5: bb1, otherwise: bb4];
+      }
+  
+      bb1: {
+          StorageLive(_4);
+          _4 = const "E";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb3;
+      }
+  
+      bb2: {
+          _1 = const "D";
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb4: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..3a2dc19db71
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,44 @@
+- // MIR for `otherwise_t2` before UninhabitedEnumBranching
++ // MIR for `otherwise_t2` after UninhabitedEnumBranching
+  
+  fn otherwise_t2() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test2;
+      let mut _3: isize;
+      let _4: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test2::D;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [4: bb2, otherwise: bb1];
++         switchInt(move _3) -> [4: bb2, 5: bb1, otherwise: bb4];
+      }
+  
+      bb1: {
+          StorageLive(_4);
+          _4 = const "E";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb3;
+      }
+  
+      bb2: {
+          _1 = const "D";
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb4: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..5dc1e2b73f6
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,53 @@
+- // MIR for `otherwise_t3` before UninhabitedEnumBranching
++ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+  
+  fn otherwise_t3() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test3;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test3::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(Empty)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(Empty)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb5: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..5dc1e2b73f6
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,53 @@
+- // MIR for `otherwise_t3` before UninhabitedEnumBranching
++ // MIR for `otherwise_t3` after UninhabitedEnumBranching
+  
+  fn otherwise_t3() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test3;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test3::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(Empty)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(Empty)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb5: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..1352dda4971
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,48 @@
+- // MIR for `otherwise_t4` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+  
+  fn otherwise_t4() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+          switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "CD";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(i32)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(i32)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..1352dda4971
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,48 @@
+- // MIR for `otherwise_t4` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4` after UninhabitedEnumBranching
+  
+  fn otherwise_t4() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+          switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const "CD";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _1 = const "A(i32)";
+          goto -> bb4;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(i32)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb4;
+      }
+  
+      bb4: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..40dd961fbac
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,62 @@
+- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+  
+  fn otherwise_t4_uninhabited_default() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
++         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = const "D";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _1 = const "A(i32)";
+          goto -> bb5;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(i32)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb5;
+      }
+  
+      bb4: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb5;
+      }
+  
+      bb5: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb6: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..40dd961fbac
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,62 @@
+- // MIR for `otherwise_t4_uninhabited_default` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4_uninhabited_default` after UninhabitedEnumBranching
+  
+  fn otherwise_t4_uninhabited_default() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
++         switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = const "D";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _1 = const "A(i32)";
+          goto -> bb5;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(i32)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb5;
+      }
+  
+      bb4: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb5;
+      }
+  
+      bb5: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb6: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..de6944ee423
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,75 @@
+- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+  
+  fn otherwise_t4_uninhabited_default_2() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+      let _7: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb1, 1: bb5, 2: bb6, otherwise: bb2];
++         switchInt(move _3) -> [0: bb1, 1: bb5, 2: bb6, 3: bb2, otherwise: bb8];
+      }
+  
+      bb1: {
+          switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb2];
+      }
+  
+      bb2: {
+          StorageLive(_7);
+          _7 = const "A(other)D";
+          _1 = &(*_7);
+          StorageDead(_7);
+          goto -> bb7;
+      }
+  
+      bb3: {
+          _1 = const "A(1)";
+          goto -> bb7;
+      }
+  
+      bb4: {
+          StorageLive(_4);
+          _4 = const "A(2)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb7;
+      }
+  
+      bb5: {
+          StorageLive(_5);
+          _5 = const "B(i32)";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb7;
+      }
+  
+      bb6: {
+          StorageLive(_6);
+          _6 = const "C";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb8: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..ac39f6be6c6
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,75 @@
+- // MIR for `otherwise_t4_uninhabited_default_2` before UninhabitedEnumBranching
++ // MIR for `otherwise_t4_uninhabited_default_2` after UninhabitedEnumBranching
+  
+  fn otherwise_t4_uninhabited_default_2() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test4;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+      let _7: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test4::C;
+          _3 = discriminant(_2);
+-         switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, otherwise: bb1];
++         switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: bb8];
+      }
+  
+      bb1: {
+          StorageLive(_7);
+          _7 = const "A(other)D";
+          _1 = &(*_7);
+          StorageDead(_7);
+          goto -> bb7;
+      }
+  
+      bb2: {
+          switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb1];
+      }
+  
+      bb3: {
+          _1 = const "A(1)";
+          goto -> bb7;
+      }
+  
+      bb4: {
+          StorageLive(_4);
+          _4 = const "A(2)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb7;
+      }
+  
+      bb5: {
+          StorageLive(_5);
+          _5 = const "B(i32)";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb7;
+      }
+  
+      bb6: {
+          StorageLive(_6);
+          _6 = const "C";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb7;
+      }
+  
+      bb7: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
++     }
++ 
++     bb8: {
++         unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
new file mode 100644
index 00000000000..aaede2dd924
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff
@@ -0,0 +1,61 @@
+- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
++ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+  
+  fn otherwise_t5_uninhabited_default() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test5<T>;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test5::<T>::C;
+          _3 = discriminant(_2);
+          switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = const "D";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _1 = const "A(T)";
+          goto -> bb5;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(T)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb5;
+      }
+  
+      bb4: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb5;
+      }
+  
+      bb5: {
+          drop(_2) -> [return: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
new file mode 100644
index 00000000000..edaaa0db588
--- /dev/null
+++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff
@@ -0,0 +1,65 @@
+- // MIR for `otherwise_t5_uninhabited_default` before UninhabitedEnumBranching
++ // MIR for `otherwise_t5_uninhabited_default` after UninhabitedEnumBranching
+  
+  fn otherwise_t5_uninhabited_default() -> () {
+      let mut _0: ();
+      let _1: &str;
+      let mut _2: Test5<T>;
+      let mut _3: isize;
+      let _4: &str;
+      let _5: &str;
+      let _6: &str;
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = Test5::<T>::C;
+          _3 = discriminant(_2);
+          switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageLive(_6);
+          _6 = const "D";
+          _1 = &(*_6);
+          StorageDead(_6);
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _1 = const "A(T)";
+          goto -> bb5;
+      }
+  
+      bb3: {
+          StorageLive(_4);
+          _4 = const "B(T)";
+          _1 = &(*_4);
+          StorageDead(_4);
+          goto -> bb5;
+      }
+  
+      bb4: {
+          StorageLive(_5);
+          _5 = const "C";
+          _1 = &(*_5);
+          StorageDead(_5);
+          goto -> bb5;
+      }
+  
+      bb5: {
+          drop(_2) -> [return: bb6, unwind: bb7];
+      }
+  
+      bb6: {
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  
+      bb7 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs
index b955ff69b3d..a60ca0288e8 100644
--- a/tests/mir-opt/uninhabited_enum_branching.rs
+++ b/tests/mir-opt/uninhabited_enum_branching.rs
@@ -25,6 +25,20 @@ enum Test3 {
     D,
 }
 
+enum Test4 {
+    A(i32),
+    B(i32),
+    C,
+    D,
+}
+
+enum Test5<T> {
+    A(T),
+    B(T),
+    C,
+    D,
+}
+
 struct Plop {
     xx: u32,
     test3: Test3,
@@ -57,6 +71,112 @@ fn custom_discriminant() {
     };
 }
 
+// EMIT_MIR uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.diff
+fn otherwise_t1() {
+    // CHECK-LABEL: fn otherwise_t1(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
+    // CHECK: bb5: {
+    // CHECK-NEXT: unreachable;
+    match Test1::C {
+        Test1::A(_) => "A(Empty)",
+        Test1::B(_) => "B(Empty)",
+        _ => "C",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.diff
+fn otherwise_t2() {
+    // CHECK-LABEL: fn otherwise_t2(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [4: bb2, 5: bb1, otherwise: bb4];
+    // CHECK: bb4: {
+    // CHECK-NEXT: unreachable;
+    match Test2::D {
+        Test2::D => "D",
+        _ => "E",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.diff
+fn otherwise_t3() {
+    // CHECK-LABEL: fn otherwise_t3(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb5, 1: bb5, otherwise: bb1];
+    // CHECK: bb1: {
+    // CHECK-NOT: unreachable;
+    // CHECK: }
+    // CHECK: bb5: {
+    // CHECK-NEXT: unreachable;
+    match Test3::C {
+        Test3::A(_) => "A(Empty)",
+        Test3::B(_) => "B(Empty)",
+        _ => "C",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.diff
+fn otherwise_t4_uninhabited_default() {
+    // CHECK-LABEL: fn otherwise_t4_uninhabited_default(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6];
+    // CHECK: bb6: {
+    // CHECK-NEXT: unreachable;
+    match Test4::C {
+        Test4::A(_) => "A(i32)",
+        Test4::B(_) => "B(i32)",
+        Test4::C => "C",
+        _ => "D",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.diff
+fn otherwise_t4_uninhabited_default_2() {
+    // CHECK-LABEL: fn otherwise_t4_uninhabited_default_2(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: bb8];
+    // CHECK: bb8: {
+    // CHECK-NEXT: unreachable;
+    match Test4::C {
+        Test4::A(1) => "A(1)",
+        Test4::A(2) => "A(2)",
+        Test4::B(_) => "B(i32)",
+        Test4::C => "C",
+        _ => "A(other)D",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.diff
+fn otherwise_t4() {
+    // CHECK-LABEL: fn otherwise_t4(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, otherwise: bb1];
+    // CHECK: bb1: {
+    // CHECK-NOT: unreachable;
+    // CHECK: }
+    match Test4::C {
+        Test4::A(_) => "A(i32)",
+        Test4::B(_) => "B(i32)",
+        _ => "CD",
+    };
+}
+
+// EMIT_MIR uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.diff
+fn otherwise_t5_uninhabited_default<T>() {
+    // CHECK-LABEL: fn otherwise_t5_uninhabited_default(
+    // CHECK: [[discr:_.*]] = discriminant(
+    // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
+    // CHECK: bb1: {
+    // CHECK-NOT: unreachable;
+    // CHECK: }
+    match Test5::<T>::C {
+        Test5::A(_) => "A(T)",
+        Test5::B(_) => "B(T)",
+        Test5::C => "C",
+        _ => "D",
+    };
+}
+
 // EMIT_MIR uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff
 fn byref() {
     // CHECK-LABEL: fn byref(
@@ -87,5 +207,12 @@ fn byref() {
 fn main() {
     simple();
     custom_discriminant();
+    otherwise_t1();
+    otherwise_t2();
+    otherwise_t3();
+    otherwise_t4_uninhabited_default();
+    otherwise_t4_uninhabited_default_2();
+    otherwise_t4();
+    otherwise_t5_uninhabited_default::<i32>();
     byref();
 }
diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
index 79948139f88..28a8c251d95 100644
--- a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
+++ b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
@@ -9,7 +9,7 @@
       bb0: {
           _2 = discriminant(_1);
 -         switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
-+         switchInt(move _2) -> [0: bb5, 1: bb3, otherwise: bb1];
++         switchInt(move _2) -> [0: bb5, 1: bb3, 2: bb1, otherwise: bb5];
       }
   
       bb1: {