From 1bd004bc32524d80f4a4f69717dc74e6122dd4b4 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 14 Feb 2024 09:19:31 +0800 Subject: [PATCH 1/5] Regenerate `uninhabited_enum_branching.rs` --- ...UninhabitedEnumBranching.panic-abort.diff} | 0 ...UninhabitedEnumBranching.panic-unwind.diff | 119 ++++++++++++++++++ ...UninhabitedEnumBranching.panic-abort.diff} | 0 ...UninhabitedEnumBranching.panic-unwind.diff | 48 +++++++ tests/mir-opt/uninhabited_enum_branching.rs | 2 + ...UninhabitedEnumBranching.panic-abort.diff} | 0 ...UninhabitedEnumBranching.panic-unwind.diff | 57 +++++++++ 7 files changed, 226 insertions(+) rename tests/mir-opt/{uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff => uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff} (100%) create mode 100644 tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff rename tests/mir-opt/{uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff => uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff} (100%) create mode 100644 tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff rename tests/mir-opt/{uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff => uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff} (100%) create mode 100644 tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff similarity index 100% rename from tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff rename to tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-abort.diff diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff new file mode 100644 index 0000000000000..5a3544f85387b --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff @@ -0,0 +1,119 @@ +- // MIR for `byref` before UninhabitedEnumBranching ++ // MIR for `byref` after UninhabitedEnumBranching + + fn byref() -> () { + let mut _0: (); + let _1: Plop; + let mut _2: Test3; + let _3: &str; + let mut _4: &Test3; + let mut _5: isize; + let _6: &str; + let _7: &str; + let _8: &str; + let _9: &str; + let mut _10: isize; + let _11: &str; + let _12: &str; + let _13: &str; + scope 1 { + debug plop => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = Test3::C; + _1 = Plop { xx: const 51_u32, test3: move _2 }; + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = &(_1.1: Test3); + _5 = discriminant((*_4)); +- switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1]; ++ switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb2, otherwise: bb12]; + } + + bb1: { + unreachable; + } + + bb2: { + StorageLive(_8); + _8 = const "D"; + _3 = &(*_8); + StorageDead(_8); + goto -> bb6; + } + + bb3: { + _3 = const "A(Empty)"; + goto -> bb6; + } + + bb4: { + StorageLive(_6); + _6 = const "B(Empty)"; + _3 = &(*_6); + StorageDead(_6); + goto -> bb6; + } + + bb5: { + StorageLive(_7); + _7 = const "C"; + _3 = &(*_7); + StorageDead(_7); + goto -> bb6; + } + + bb6: { + StorageDead(_4); + StorageDead(_3); + StorageLive(_9); + _10 = discriminant((_1.1: Test3)); +- switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1]; ++ switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12]; + } + + bb7: { + StorageLive(_13); + _13 = const "D"; + _9 = &(*_13); + StorageDead(_13); + goto -> bb11; + } + + bb8: { + _9 = const "A(Empty)"; + goto -> bb11; + } + + bb9: { + StorageLive(_11); + _11 = const "B(Empty)"; + _9 = &(*_11); + StorageDead(_11); + goto -> bb11; + } + + bb10: { + StorageLive(_12); + _12 = const "C"; + _9 = &(*_12); + StorageDead(_12); + goto -> bb11; + } + + bb11: { + StorageDead(_9); + _0 = const (); + StorageDead(_1); + return; ++ } ++ ++ bb12: { ++ unreachable; + } + } + diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff similarity index 100% rename from tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff rename to tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-abort.diff diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff new file mode 100644 index 0000000000000..121374553ed87 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `custom_discriminant` before UninhabitedEnumBranching ++ // MIR for `custom_discriminant` after UninhabitedEnumBranching + + fn custom_discriminant() -> () { + 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: bb3, 5: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb5]; + } + + bb1: { + unreachable; + } + + bb2: { + StorageLive(_4); + _4 = const "E"; + _1 = &(*_4); + StorageDead(_4); + goto -> bb4; + } + + bb3: { + _1 = const "D"; + goto -> bb4; + } + + bb4: { + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; ++ } ++ ++ bb5: { ++ unreachable; + } + } + diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs index 08eca57afc630..b955ff69b3d19 100644 --- a/tests/mir-opt/uninhabited_enum_branching.rs +++ b/tests/mir-opt/uninhabited_enum_branching.rs @@ -1,4 +1,6 @@ //@ unit-test: UninhabitedEnumBranching +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + enum Empty {} // test matching an enum with uninhabited variants diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff similarity index 100% rename from tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff rename to tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-abort.diff diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff new file mode 100644 index 0000000000000..6ce61e1528748 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff @@ -0,0 +1,57 @@ +- // MIR for `simple` before UninhabitedEnumBranching ++ // MIR for `simple` after UninhabitedEnumBranching + + fn simple() -> () { + 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: bb3, 1: bb4, 2: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb6, 1: bb6, 2: bb2, otherwise: bb6]; + } + + bb1: { + unreachable; + } + + bb2: { + StorageLive(_5); + _5 = const "C"; + _1 = &(*_5); + StorageDead(_5); + goto -> bb5; + } + + bb3: { + _1 = const "A(Empty)"; + goto -> bb5; + } + + bb4: { + StorageLive(_4); + _4 = const "B(Empty)"; + _1 = &(*_4); + StorageDead(_4); + goto -> bb5; + } + + bb5: { + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; ++ } ++ ++ bb6: { ++ unreachable; + } + } + From f88c0ead466599e2f0bfefd901ea64312017229c Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 14 Feb 2024 12:02:22 +0800 Subject: [PATCH 2/5] Replace the default branch with an unreachable branch If it is the last variant --- compiler/rustc_middle/src/mir/terminator.rs | 11 ++ .../src/uninhabited_enum_branching.rs | 24 +++- .../enum/uninhabited_enum_default_branch.rs | 24 ++++ ...to_exponential_common.GVN.panic-abort.diff | 6 +- ...o_exponential_common.GVN.panic-unwind.diff | 6 +- ....foo.SimplifyLocals-final.panic-abort.diff | 6 +- ...foo.SimplifyLocals-final.panic-unwind.diff | 6 +- ....UninhabitedEnumBranching.panic-abort.diff | 53 ++++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 53 ++++++++ ....UninhabitedEnumBranching.panic-abort.diff | 44 ++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 44 ++++++ ....UninhabitedEnumBranching.panic-abort.diff | 53 ++++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 53 ++++++++ ....UninhabitedEnumBranching.panic-abort.diff | 48 +++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 48 +++++++ ....UninhabitedEnumBranching.panic-abort.diff | 62 +++++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 62 +++++++++ ....UninhabitedEnumBranching.panic-abort.diff | 75 +++++++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 75 +++++++++++ ....UninhabitedEnumBranching.panic-abort.diff | 61 +++++++++ ...UninhabitedEnumBranching.panic-unwind.diff | 65 +++++++++ tests/mir-opt/uninhabited_enum_branching.rs | 127 ++++++++++++++++++ ..._fallthrough.UninhabitedEnumBranching.diff | 2 +- 23 files changed, 997 insertions(+), 11 deletions(-) create mode 100644 tests/codegen/enum/uninhabited_enum_default_branch.rs create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.panic-unwind.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-abort.diff create mode 100644 tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.panic-unwind.diff diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 91b7952bec5e8..4681857dcf38e 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 e68d37f4c701e..d3408d4882fb6 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 0000000000000..5f318f18dec68 --- /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 080478ea88419..bd346af6d16e4 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); _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 ff8933fca8b2c..422cbeaa224ea 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); _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 1566d7197acd8..3108b7d3e13d7 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)); - 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 ba5262b0ee143..3ef3be198ede3 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)); - 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 0000000000000..383fde4d787b9 --- /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 0000000000000..383fde4d787b9 --- /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 0000000000000..3a2dc19db71cd --- /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 0000000000000..3a2dc19db71cd --- /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 0000000000000..5dc1e2b73f6a4 --- /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 0000000000000..5dc1e2b73f6a4 --- /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 0000000000000..1352dda49715b --- /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 0000000000000..1352dda49715b --- /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 0000000000000..40dd961fbac4d --- /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 0000000000000..40dd961fbac4d --- /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 0000000000000..de6944ee423c6 --- /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 0000000000000..ac39f6be6c634 --- /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 0000000000000..aaede2dd92438 --- /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; + let mut _3: isize; + let _4: &str; + let _5: &str; + let _6: &str; + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = Test5::::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 0000000000000..edaaa0db588b0 --- /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; + let mut _3: isize; + let _4: &str; + let _5: &str; + let _6: &str; + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = Test5::::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 b955ff69b3d19..a60ca0288e852 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 { + 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() { + // 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::::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::(); 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 79948139f888d..28a8c251d956a 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: { From b61a3267c82dcdb05f815ee71daa5018c390ad73 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 14 Feb 2024 12:09:28 +0800 Subject: [PATCH 3/5] Get all variants to eliminate the default branching if we cannot get the layout of type --- .../src/uninhabited_enum_branching.rs | 6 +++++ ..._to_digit.PreCodegen.after.panic-abort.mir | 22 ++++++++++--------- ...to_digit.PreCodegen.after.panic-unwind.mir | 22 ++++++++++--------- ....foo.SimplifyLocals-final.panic-abort.diff | 2 +- ...foo.SimplifyLocals-final.panic-unwind.diff | 2 +- ....UninhabitedEnumBranching.panic-abort.diff | 12 +++++----- ....UninhabitedEnumBranching.panic-abort.diff | 9 ++++++-- ...UninhabitedEnumBranching.panic-unwind.diff | 9 ++++++-- tests/mir-opt/uninhabited_enum_branching.rs | 16 +++++++------- 9 files changed, 60 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index d3408d4882fb6..0ab6025973287 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -95,6 +95,12 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { let mut allowed_variants = if let Ok(layout) = layout { variant_discriminants(&layout, discriminant_ty, tcx) + } else if let Some(variant_range) = discriminant_ty.variant_range(tcx) { + variant_range + .map(|variant| { + discriminant_ty.discriminant_for_variant(tcx, variant).unwrap().val + }) + .collect() } else { continue; }; diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir index f7be8b75db7b8..bc12002490a16 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir @@ -33,13 +33,13 @@ fn num_to_digit(_1: char) -> u32 { _3 = &_2; StorageLive(_4); _4 = discriminant(_2); - StorageDead(_3); - StorageDead(_2); - switchInt(move _4) -> [1: bb2, otherwise: bb7]; + switchInt(move _4) -> [1: bb2, 0: bb6, otherwise: bb8]; } bb2: { StorageDead(_4); + StorageDead(_3); + StorageDead(_2); StorageLive(_5); _5 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable]; } @@ -47,7 +47,7 @@ fn num_to_digit(_1: char) -> u32 { bb3: { StorageLive(_6); _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb8]; } bb4: { @@ -58,20 +58,22 @@ fn num_to_digit(_1: char) -> u32 { _0 = move ((_5 as Some).0: u32); StorageDead(_6); StorageDead(_5); - goto -> bb8; + goto -> bb7; } bb6: { - unreachable; + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + _0 = const 0_u32; + goto -> bb7; } bb7: { - StorageDead(_4); - _0 = const 0_u32; - goto -> bb8; + return; } bb8: { - return; + unreachable; } } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir index e76fe992ac7d3..6c7e10a45250a 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir @@ -33,13 +33,13 @@ fn num_to_digit(_1: char) -> u32 { _3 = &_2; StorageLive(_4); _4 = discriminant(_2); - StorageDead(_3); - StorageDead(_2); - switchInt(move _4) -> [1: bb2, otherwise: bb7]; + switchInt(move _4) -> [1: bb2, 0: bb6, otherwise: bb8]; } bb2: { StorageDead(_4); + StorageDead(_3); + StorageDead(_2); StorageLive(_5); _5 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue]; } @@ -47,7 +47,7 @@ fn num_to_digit(_1: char) -> u32 { bb3: { StorageLive(_6); _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb8]; } bb4: { @@ -58,20 +58,22 @@ fn num_to_digit(_1: char) -> u32 { _0 = move ((_5 as Some).0: u32); StorageDead(_6); StorageDead(_5); - goto -> bb8; + goto -> bb7; } bb6: { - unreachable; + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + _0 = const 0_u32; + goto -> bb7; } bb7: { - StorageDead(_4); - _0 = const 0_u32; - goto -> bb8; + return; } bb8: { - return; + 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 3108b7d3e13d7..c520a159f47b2 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 @@ -28,7 +28,7 @@ bb1: { _4 = discriminant((_1.1: std::option::Option)); - switchInt(move _4) -> [0: bb2, otherwise: bb3]; + switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb2: { 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 3ef3be198ede3..686581591fc4e 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 @@ -28,7 +28,7 @@ bb1: { _4 = discriminant((_1.1: std::option::Option)); - switchInt(move _4) -> [0: bb2, otherwise: bb3]; + switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb2: { 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 index de6944ee423c6..ac39f6be6c634 100644 --- 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 @@ -16,15 +16,11 @@ 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]; +- 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: { - switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb2]; - } - - bb2: { StorageLive(_7); _7 = const "A(other)D"; _1 = &(*_7); @@ -32,6 +28,10 @@ goto -> bb7; } + bb2: { + switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb1]; + } + bb3: { _1 = const "A(1)"; goto -> bb7; 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 index aaede2dd92438..8180428a6f459 100644 --- 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 @@ -5,7 +5,7 @@ let mut _0: (); let _1: &str; let mut _2: Test5; - let mut _3: isize; + let mut _3: i8; let _4: &str; let _5: &str; let _6: &str; @@ -15,7 +15,8 @@ StorageLive(_2); _2 = Test5::::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; +- switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, otherwise: bb1]; ++ switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: bb7]; } bb1: { @@ -56,6 +57,10 @@ StorageDead(_1); _0 = const (); return; ++ } ++ ++ bb7: { ++ unreachable; } } 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 index edaaa0db588b0..b13d5816aed9d 100644 --- 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 @@ -5,7 +5,7 @@ let mut _0: (); let _1: &str; let mut _2: Test5; - let mut _3: isize; + let mut _3: i8; let _4: &str; let _5: &str; let _6: &str; @@ -15,7 +15,8 @@ StorageLive(_2); _2 = Test5::::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; +- switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, otherwise: bb1]; ++ switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: bb8]; } bb1: { @@ -60,6 +61,10 @@ bb7 (cleanup): { resume; ++ } ++ ++ bb8: { ++ unreachable; } } diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs index a60ca0288e852..e31bf0227d5a1 100644 --- a/tests/mir-opt/uninhabited_enum_branching.rs +++ b/tests/mir-opt/uninhabited_enum_branching.rs @@ -32,11 +32,12 @@ enum Test4 { D, } +#[repr(i8)] enum Test5 { - A(T), - B(T), - C, - D, + A(T) = -1, + B(T) = 0, + C = 5, + D = 3, } struct Plop { @@ -165,10 +166,9 @@ fn otherwise_t4() { fn otherwise_t5_uninhabited_default() { // 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: } + // CHECK: switchInt(move [[discr]]) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { + // CHECK-NEXT: unreachable; match Test5::::C { Test5::A(_) => "A(T)", Test5::B(_) => "B(T)", From 34f267254f9c7ed62c3a53936872c527de4b4bd6 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 28 Feb 2024 22:35:41 +0800 Subject: [PATCH 4/5] Update MIR with `MirPatch` in `UninhabitedEnumBranching` --- compiler/rustc_middle/src/mir/patch.rs | 27 +++++++- .../src/uninhabited_enum_branching.rs | 67 +++++++++---------- ..._constant.main.GVN.64bit.panic-unwind.diff | 20 +++--- ...e_const_switch.identity.JumpThreading.diff | 28 ++++---- ...onst_switch.too_complex.JumpThreading.diff | 34 +++++----- ...UninhabitedEnumBranching.panic-unwind.diff | 8 +-- ...UninhabitedEnumBranching.panic-unwind.diff | 7 +- tests/mir-opt/uninhabited_enum_branching.rs | 30 ++++----- ...UninhabitedEnumBranching.panic-unwind.diff | 6 +- 9 files changed, 115 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index b81e9fa1aab64..334122970178e 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -11,6 +11,8 @@ pub struct MirPatch<'tcx> { resume_block: Option, // Only for unreachable in cleanup path. unreachable_cleanup_block: Option, + // Only for unreachable not in cleanup path. + unreachable_no_cleanup_block: Option, // Cached block for UnwindTerminate (with reason) terminate_block: Option<(BasicBlock, UnwindTerminateReason)>, body_span: Span, @@ -27,6 +29,7 @@ impl<'tcx> MirPatch<'tcx> { next_local: body.local_decls.len(), resume_block: None, unreachable_cleanup_block: None, + unreachable_no_cleanup_block: None, terminate_block: None, body_span: body.span, }; @@ -43,9 +46,12 @@ impl<'tcx> MirPatch<'tcx> { // Check if we already have an unreachable block if matches!(block.terminator().kind, TerminatorKind::Unreachable) && block.statements.is_empty() - && block.is_cleanup { - result.unreachable_cleanup_block = Some(bb); + if block.is_cleanup { + result.unreachable_cleanup_block = Some(bb); + } else { + result.unreachable_no_cleanup_block = Some(bb); + } continue; } @@ -95,6 +101,23 @@ impl<'tcx> MirPatch<'tcx> { bb } + pub fn unreachable_no_cleanup_block(&mut self) -> BasicBlock { + if let Some(bb) = self.unreachable_no_cleanup_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Unreachable, + }), + is_cleanup: false, + }); + self.unreachable_no_cleanup_block = Some(bb); + bb + } + pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock { if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 0ab6025973287..840a7eda27b67 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -2,8 +2,9 @@ use crate::MirPass; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::{ - BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, Terminator, TerminatorKind, + BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -77,8 +78,8 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("UninhabitedEnumBranching starting for {:?}", body.source); - let mut removable_switchs = Vec::new(); - let mut otherwise_is_last_variant_switchs = Vec::new(); + let mut unreachable_targets = Vec::new(); + let mut patch = MirPatch::new(body); for (bb, bb_data) in body.basic_blocks.iter_enumerated() { trace!("processing block {:?}", bb); @@ -107,49 +108,41 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { trace!("allowed_variants = {:?}", allowed_variants); - let terminator = bb_data.terminator(); - let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() }; + unreachable_targets.clear(); + let TerminatorKind::SwitchInt { targets, discr } = &bb_data.terminator().kind else { + bug!() + }; for (index, (val, _)) in targets.iter().enumerate() { if !allowed_variants.remove(&val) { - removable_switchs.push((bb, index)); + unreachable_targets.push(index); } } - 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)); - } - } + let replace_otherwise_to_unreachable = allowed_variants.len() <= 1 + && !body.basic_blocks[targets.otherwise()].is_empty_unreachable(); - 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 unreachable_targets.is_empty() && !replace_otherwise_to_unreachable { + continue; + } - if removable_switchs.is_empty() { - return; + let unreachable_block = patch.unreachable_no_cleanup_block(); + let mut targets = targets.clone(); + if replace_otherwise_to_unreachable { + let otherwise_is_last_variant = !allowed_variants.is_empty(); + if otherwise_is_last_variant { + #[allow(rustc::potential_query_instability)] + let last_variant = *allowed_variants.iter().next().unwrap(); + targets.add_target(last_variant, targets.otherwise()); + } + unreachable_targets.push(targets.iter().count()); + } + for index in unreachable_targets.iter() { + targets.all_targets_mut()[*index] = unreachable_block; + } + patch.patch_terminator(bb, TerminatorKind::SwitchInt { targets, discr: discr.clone() }); } - let new_block = BasicBlockData::new(Some(Terminator { - source_info: body.basic_blocks[removable_switchs[0].0].terminator().source_info, - kind: TerminatorKind::Unreachable, - })); - let unreachable_block = body.basic_blocks.as_mut().push(new_block); - - for (bb, index) in removable_switchs { - let bb = &mut body.basic_blocks.as_mut()[bb]; - let terminator = bb.terminator_mut(); - let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() }; - targets.all_targets_mut()[index] = unreachable_block; - } + patch.apply(body); } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 6145f92a0754a..37915471bb9e2 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -43,9 +43,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5]; +- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5]; ++ switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; } bb1: { @@ -68,10 +68,14 @@ } bb2: { - _11 = option::unwrap_failed() -> unwind continue; + unreachable; } bb3: { + _11 = option::unwrap_failed() -> unwind continue; + } + + bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); @@ -86,20 +90,16 @@ + _7 = const {ALLOC1: &std::alloc::Global}; StorageLive(_8); - _8 = _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; + _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; } - bb4: { + bb5: { StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } - - bb5: { - unreachable; - } } + + ALLOC0 (size: 16, align: 8) { diff --git a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff index ab3d91ab91887..d0abebff214d3 100644 --- a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff @@ -52,17 +52,21 @@ StorageLive(_9); StorageLive(_10); _8 = discriminant(_1); - switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb6]; + switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb1: { + unreachable; + } + + bb2: { _7 = ((_2 as Continue).0: i32); _0 = Result::::Ok(_7); StorageDead(_2); return; } - bb2: { + bb3: { _5 = ((_2 as Break).0: std::result::Result); StorageLive(_6); _6 = _5; @@ -73,34 +77,30 @@ return; } - bb3: { + bb4: { StorageDead(_10); StorageDead(_9); StorageDead(_8); StorageDead(_3); _4 = discriminant(_2); -- switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb6]; -+ goto -> bb1; +- switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ goto -> bb2; } - bb4: { + bb5: { _10 = ((_1 as Err).0: i32); StorageLive(_11); _11 = Result::::Err(_10); _2 = ControlFlow::, i32>::Break(move _11); StorageDead(_11); -- goto -> bb3; +- goto -> bb4; + goto -> bb7; } - bb5: { + bb6: { _9 = ((_1 as Ok).0: i32); _2 = ControlFlow::, i32>::Continue(_9); - goto -> bb3; - } - - bb6: { - unreachable; + goto -> bb4; + } + + bb7: { @@ -109,7 +109,7 @@ + StorageDead(_8); + StorageDead(_3); + _4 = discriminant(_2); -+ goto -> bb2; ++ goto -> bb3; } } diff --git a/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff index 1ac527e9338a1..f749586299221 100644 --- a/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff @@ -27,54 +27,54 @@ bb0: { StorageLive(_2); _3 = discriminant(_1); - switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb7]; + switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; } bb1: { + unreachable; + } + + bb2: { _5 = ((_1 as Err).0: usize); _2 = ControlFlow::::Break(_5); -- goto -> bb3; +- goto -> bb4; + goto -> bb8; } - bb2: { + bb3: { _4 = ((_1 as Ok).0: i32); _2 = ControlFlow::::Continue(_4); - goto -> bb3; + goto -> bb4; } - bb3: { + bb4: { _6 = discriminant(_2); -- switchInt(move _6) -> [0: bb5, 1: bb4, otherwise: bb7]; -+ goto -> bb5; +- switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; ++ goto -> bb6; } - bb4: { + bb5: { StorageLive(_8); _8 = ((_2 as Break).0: usize); _0 = const Option::::None; StorageDead(_8); - goto -> bb6; + goto -> bb7; } - bb5: { + bb6: { _7 = ((_2 as Continue).0: i32); _0 = Option::::Some(_7); - goto -> bb6; + goto -> bb7; } - bb6: { + bb7: { StorageDead(_2); return; - } - - bb7: { - unreachable; + } + + bb8: { + _6 = discriminant(_2); -+ goto -> bb4; ++ goto -> bb5; } } diff --git a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff index 5a3544f85387b..1b7517c8d0107 100644 --- a/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff @@ -31,7 +31,7 @@ _4 = &(_1.1: Test3); _5 = discriminant((*_4)); - switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1]; -+ switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb2, otherwise: bb12]; ++ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb5, 3: bb2, otherwise: bb1]; } bb1: { @@ -73,7 +73,7 @@ StorageLive(_9); _10 = discriminant((_1.1: Test3)); - switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1]; -+ switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12]; ++ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb10, 3: bb7, otherwise: bb1]; } bb7: { @@ -110,10 +110,6 @@ _0 = const (); StorageDead(_1); return; -+ } -+ -+ bb12: { -+ unreachable; } } diff --git a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff index 121374553ed87..f9a43480917e6 100644 --- a/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.panic-unwind.diff @@ -13,8 +13,7 @@ StorageLive(_2); _2 = Test2::D; _3 = discriminant(_2); -- switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb1]; -+ switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb5]; + switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb1]; } bb1: { @@ -39,10 +38,6 @@ StorageDead(_1); _0 = const (); return; -+ } -+ -+ bb5: { -+ unreachable; } } diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs index e31bf0227d5a1..6de001be9791e 100644 --- a/tests/mir-opt/uninhabited_enum_branching.rs +++ b/tests/mir-opt/uninhabited_enum_branching.rs @@ -63,8 +63,8 @@ fn simple() { fn custom_discriminant() { // CHECK-LABEL: fn custom_discriminant( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb2, otherwise: bb5]; - // CHECK: bb5: { + // CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb2, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test2::D { Test2::D => "D", @@ -76,8 +76,8 @@ fn custom_discriminant() { 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: switchInt(move [[discr]]) -> [0: bb5, 1: bb5, 2: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test1::C { Test1::A(_) => "A(Empty)", @@ -90,8 +90,8 @@ fn otherwise_t1() { fn otherwise_t2() { // CHECK-LABEL: fn otherwise_t2( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [4: bb2, 5: bb1, otherwise: bb4]; - // CHECK: bb4: { + // CHECK: switchInt(move [[discr]]) -> [4: bb2, 5: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test2::D { Test2::D => "D", @@ -120,8 +120,8 @@ fn otherwise_t3() { 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: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test4::C { Test4::A(_) => "A(i32)", @@ -135,8 +135,8 @@ fn otherwise_t4_uninhabited_default() { 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: switchInt(move [[discr]]) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test4::C { Test4::A(1) => "A(1)", @@ -151,8 +151,8 @@ fn otherwise_t4_uninhabited_default_2() { fn otherwise_t4() { // CHECK-LABEL: fn otherwise_t4( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, otherwise: bb1]; - // CHECK: bb1: { + // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, otherwise: [[unreachable:bb.*]]]; + // CHECK: [[unreachable]]: { // CHECK-NOT: unreachable; // CHECK: } match Test4::C { @@ -191,6 +191,9 @@ fn byref() { Test3::D => "D", }; + // CHECK: [[unreachable]]: { + // CHECK-NEXT: unreachable; + // CHECK: [[discr:_.*]] = discriminant( // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable]], 1: [[unreachable]], 2: bb10, 3: bb7, otherwise: [[unreachable]]]; match plop.test3 { @@ -199,9 +202,6 @@ fn byref() { Test3::C => "C", Test3::D => "D", }; - - // CHECK: [[unreachable]]: { - // CHECK-NEXT: unreachable; } fn main() { diff --git a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff index 6ce61e1528748..674d3a25504a9 100644 --- a/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.panic-unwind.diff @@ -15,7 +15,7 @@ _2 = Test1::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb2, otherwise: bb1]; -+ switchInt(move _3) -> [0: bb6, 1: bb6, 2: bb2, otherwise: bb6]; ++ switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1]; } bb1: { @@ -48,10 +48,6 @@ StorageDead(_1); _0 = const (); return; -+ } -+ -+ bb6: { -+ unreachable; } } From 51cb2bc71a6ff4833b2d507a97a90d518ea57d4b Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 28 Feb 2024 22:54:37 +0800 Subject: [PATCH 5/5] Add a workaround for the `TailDuplicator` compile time overhead --- .../rustc_mir_transform/src/uninhabited_enum_branching.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 840a7eda27b67..4a41c2db5a9d3 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -130,7 +130,13 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { let mut targets = targets.clone(); if replace_otherwise_to_unreachable { let otherwise_is_last_variant = !allowed_variants.is_empty(); - if otherwise_is_last_variant { + // After resolving https://github.com/llvm/llvm-project/issues/78578, we can remove the limit on the number of successors. + if otherwise_is_last_variant + && !body.basic_blocks[targets.otherwise()] + .terminator() + .successors() + .any(|bb| body.basic_blocks[bb].terminator().successors().count() >= 8) + { #[allow(rustc::potential_query_instability)] let last_variant = *allowed_variants.iter().next().unwrap(); targets.add_target(last_variant, targets.otherwise());