diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index fdbbf468ecea2..ed29c2d30273f 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..e4723e8d74af4 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,8 +93,14 @@ 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 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; }; @@ -103,20 +110,29 @@ 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 { + #[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/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 04728e2e00dcc..727e9536e64ab 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1525,13 +1525,12 @@ You can add that mapping by changing MIR_OPT_BLESS_TARGET_MAPPING in src/bootstr }); for target in targets { - run(target); - let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget { compiler: self.compiler, base: target, }); run(panic_abort_target); + run(target); } } else { run(self.target); 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..0fada2e788643 --- /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: [[OR_COND:%.*]] = icmp ult i32 [[TMP1]], 70 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], 153 +// CHECK-NEXT: [[SPEC_SELECT:%.*]] = or i1 [[OR_COND]], [[TMP2]] +// 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/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..ea400ac9b2998 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 @@ -3,7 +3,8 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; let mut _0: u32; - let mut _5: std::option::Option; + let mut _5: bool; + let mut _6: std::option::Option; scope 1 (inlined char::methods::::is_digit) { debug self => _1; debug radix => const 8_u32; @@ -15,15 +16,16 @@ fn num_to_digit(_1: char) -> u32 { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - debug self => _5; - let mut _6: isize; - let mut _7: !; + debug self => _6; + let mut _7: isize; + let mut _8: !; scope 4 { debug val => _0; } } bb0: { + StorageLive(_5); StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(_1, const 8_u32) -> [return: bb1, unwind unreachable]; @@ -33,45 +35,59 @@ 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: bb3, otherwise: bb11]; } bb2: { - StorageDead(_4); - StorageLive(_5); - _5 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable]; + _5 = const true; + goto -> bb4; } bb3: { - StorageLive(_6); - _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; + _5 = const false; + goto -> bb4; } bb4: { - _7 = option::unwrap_failed() -> unwind unreachable; + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + switchInt(move _5) -> [0: bb5, otherwise: bb6]; } bb5: { - _0 = move ((_5 as Some).0: u32); - StorageDead(_6); - StorageDead(_5); - goto -> bb8; + _0 = const 0_u32; + goto -> bb10; } bb6: { - unreachable; + StorageLive(_6); + _6 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_4); - _0 = const 0_u32; - goto -> bb8; + StorageLive(_7); + _7 = discriminant(_6); + switchInt(move _7) -> [0: bb8, 1: bb9, otherwise: bb11]; } bb8: { + _8 = option::unwrap_failed() -> unwind unreachable; + } + + bb9: { + _0 = move ((_6 as Some).0: u32); + StorageDead(_7); + StorageDead(_6); + goto -> bb10; + } + + bb10: { + StorageDead(_5); return; } + + bb11: { + 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..ca7dd89e5589a 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 @@ -3,7 +3,8 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; let mut _0: u32; - let mut _5: std::option::Option; + let mut _5: bool; + let mut _6: std::option::Option; scope 1 (inlined char::methods::::is_digit) { debug self => _1; debug radix => const 8_u32; @@ -15,15 +16,16 @@ fn num_to_digit(_1: char) -> u32 { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - debug self => _5; - let mut _6: isize; - let mut _7: !; + debug self => _6; + let mut _7: isize; + let mut _8: !; scope 4 { debug val => _0; } } bb0: { + StorageLive(_5); StorageLive(_3); StorageLive(_2); _2 = char::methods::::to_digit(_1, const 8_u32) -> [return: bb1, unwind continue]; @@ -33,45 +35,59 @@ 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: bb3, otherwise: bb11]; } bb2: { - StorageDead(_4); - StorageLive(_5); - _5 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue]; + _5 = const true; + goto -> bb4; } bb3: { - StorageLive(_6); - _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; + _5 = const false; + goto -> bb4; } bb4: { - _7 = option::unwrap_failed() -> unwind continue; + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + switchInt(move _5) -> [0: bb5, otherwise: bb6]; } bb5: { - _0 = move ((_5 as Some).0: u32); - StorageDead(_6); - StorageDead(_5); - goto -> bb8; + _0 = const 0_u32; + goto -> bb10; } bb6: { - unreachable; + StorageLive(_6); + _6 = char::methods::::to_digit(move _1, const 8_u32) -> [return: bb7, unwind continue]; } bb7: { - StorageDead(_4); - _0 = const 0_u32; - goto -> bb8; + StorageLive(_7); + _7 = discriminant(_6); + switchInt(move _7) -> [0: bb8, 1: bb9, otherwise: bb11]; } bb8: { + _8 = option::unwrap_failed() -> unwind continue; + } + + bb9: { + _0 = move ((_6 as Some).0: u32); + StorageDead(_7); + StorageDead(_6); + goto -> bb10; + } + + bb10: { + StorageDead(_5); return; } + + bb11: { + unreachable; + } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir index cf7feef00514a..f1d0da28b4ef1 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir @@ -4,66 +4,12 @@ fn step_forward(_1: u32, _2: usize) -> u32 { debug x => _1; debug n => _2; let mut _0: u32; - scope 1 (inlined ::forward) { - debug start => _1; - debug n => _2; - let _3: std::option::Option; - let mut _4: &std::option::Option; - let mut _7: bool; - let mut _8: u32; - scope 2 { - } - scope 3 (inlined Option::::is_none) { - debug self => _4; - let mut _6: bool; - scope 4 (inlined Option::::is_some) { - debug self => _4; - let mut _5: isize; - } - } - scope 5 (inlined core::num::::wrapping_add) { - debug self => _1; - debug rhs => _8; - } - } bb0: { - StorageLive(_7); - StorageLive(_4); - StorageLive(_3); - _3 = ::forward_checked(_1, _2) -> [return: bb1, unwind continue]; + _0 = ::forward(move _1, move _2) -> [return: bb1, unwind continue]; } bb1: { - _4 = &_3; - StorageLive(_6); - StorageLive(_5); - _5 = discriminant(_3); - _6 = Eq(_5, const 1_isize); - StorageDead(_5); - _7 = Not(move _6); - StorageDead(_6); - switchInt(move _7) -> [0: bb2, otherwise: bb3]; - } - - bb2: { - StorageDead(_3); - StorageDead(_4); - goto -> bb4; - } - - bb3: { - StorageDead(_3); - StorageDead(_4); - assert(!const true, "attempt to compute `{} + {}`, which would overflow", const _, const 1_u32) -> [success: bb4, unwind continue]; - } - - bb4: { - StorageDead(_7); - StorageLive(_8); - _8 = _2 as u32 (IntToInt); - _0 = Add(_1, _8); - StorageDead(_8); return; } } 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..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 @@ -23,12 +23,12 @@ 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: { _4 = discriminant((_1.1: std::option::Option)); - switchInt(move _4) -> [0: bb2, otherwise: bb3]; + switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb2: { @@ -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..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 @@ -23,12 +23,12 @@ 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: { _4 = discriminant((_1.1: std::option::Option)); - switchInt(move _4) -> [0: bb2, otherwise: bb3]; + switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb5]; } bb2: { @@ -46,5 +46,9 @@ StorageDead(_1); return; } + + bb5: { + unreachable; + } } diff --git a/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..383fde4d787b9 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t1.UninhabitedEnumBranching.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.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..3a2dc19db71cd --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t2.UninhabitedEnumBranching.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.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..5dc1e2b73f6a4 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t3.UninhabitedEnumBranching.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.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..1352dda49715b --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4.UninhabitedEnumBranching.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.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..40dd961fbac4d --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default.UninhabitedEnumBranching.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.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..de6944ee423c6 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t4_uninhabited_default_2.UninhabitedEnumBranching.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_t5_uninhabited_default.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.diff new file mode 100644 index 0000000000000..b13d5816aed9d --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.otherwise_t5_uninhabited_default.UninhabitedEnumBranching.diff @@ -0,0 +1,70 @@ +- // 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: i8; + let _4: &str; + let _5: &str; + let _6: &str; + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = Test5::::C; + _3 = discriminant(_2); +- 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: { + 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; ++ } ++ ++ bb8: { ++ unreachable; + } + } + diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs index 60389117b1614..353a1c9fcb4f6 100644 --- a/tests/mir-opt/uninhabited_enum_branching.rs +++ b/tests/mir-opt/uninhabited_enum_branching.rs @@ -23,6 +23,21 @@ enum Test3 { D, } +enum Test4 { + A(i32), + B(i32), + C, + D, +} + +#[repr(i8)] +enum Test5 { + A(T) = -1, + B(T) = 0, + C = 5, + D = 3, +} + struct Plop { xx: u32, test3: Test3, @@ -55,6 +70,111 @@ 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: bb1, 1: bb5, 2: bb6, 3: bb2, 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]]) -> [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)", + Test5::C => "C", + _ => "D", + }; +} + // EMIT_MIR uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff fn byref() { // CHECK-LABEL: fn byref( @@ -85,5 +205,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: {