diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index dc35381fe22bf..bf5f0ca7cbd23 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -568,10 +568,11 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[ &check_alignment::CheckAlignment, &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &unreachable_prop::UnreachablePropagation, + &inline::Inline, + // Substitutions during inlining may introduce switch on enums with uninhabited branches. &uninhabited_enum_branching::UninhabitedEnumBranching, + &unreachable_prop::UnreachablePropagation, &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching), - &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index b508cd1c9cc53..1f0e605c3b858 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -16,8 +16,25 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyConstCondition on {:?}", body.source); let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - for block in body.basic_blocks_mut() { + 'blocks: for block in body.basic_blocks_mut() { + for stmt in block.statements.iter_mut() { + if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind + && let NonDivergingIntrinsic::Assume(discr) = intrinsic + && let Operand::Constant(ref c) = discr + && let Some(constant) = c.const_.try_eval_bool(tcx, param_env) + { + if constant { + stmt.make_nop(); + } else { + block.statements.clear(); + block.terminator_mut().kind = TerminatorKind::Unreachable; + continue 'blocks; + } + } + } + let terminator = block.terminator_mut(); terminator.kind = match terminator.kind { TerminatorKind::SwitchInt { diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index cb028a92d49b2..98f67e18a8d0e 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -3,8 +3,7 @@ use crate::MirPass; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{ - BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator, - TerminatorKind, + BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -30,17 +29,20 @@ fn get_switched_on_type<'tcx>( let terminator = block_data.terminator(); // Only bother checking blocks which terminate by switching on a local. - if let Some(local) = get_discriminant_local(&terminator.kind) - && let [.., stmt_before_term] = &block_data.statements[..] - && let StatementKind::Assign(box (l, Rvalue::Discriminant(place))) = stmt_before_term.kind + let local = get_discriminant_local(&terminator.kind)?; + + let stmt_before_term = block_data.statements.last()?; + + if let StatementKind::Assign(box (l, Rvalue::Discriminant(place))) = stmt_before_term.kind && l.as_local() == Some(local) - && let ty = place.ty(body, tcx).ty - && ty.is_enum() { - Some(ty) - } else { - None + let ty = place.ty(body, tcx).ty; + if ty.is_enum() { + return Some(ty); + } } + + None } fn variant_discriminants<'tcx>( @@ -67,28 +69,6 @@ fn variant_discriminants<'tcx>( } } -/// Ensures that the `otherwise` branch leads to an unreachable bb, returning `None` if so and a new -/// bb to use as the new target if not. -fn ensure_otherwise_unreachable<'tcx>( - body: &Body<'tcx>, - targets: &SwitchTargets, -) -> Option> { - let otherwise = targets.otherwise(); - let bb = &body.basic_blocks[otherwise]; - if bb.terminator().kind == TerminatorKind::Unreachable - && bb.statements.iter().all(|s| matches!(&s.kind, StatementKind::StorageDead(_))) - { - return None; - } - - let mut new_block = BasicBlockData::new(Some(Terminator { - source_info: bb.terminator().source_info, - kind: TerminatorKind::Unreachable, - })); - new_block.is_cleanup = bb.is_cleanup; - Some(new_block) -} - impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.mir_opt_level() > 0 @@ -97,13 +77,16 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("UninhabitedEnumBranching starting for {:?}", body.source); - for bb in body.basic_blocks.indices() { + let mut removable_switchs = Vec::new(); + + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { trace!("processing block {:?}", bb); - let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks[bb], tcx, body) - else { + if bb_data.is_cleanup { continue; - }; + } + + let Some(discriminant_ty) = get_switched_on_type(&bb_data, tcx, body) else { continue }; let layout = tcx.layout_of( tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty), @@ -117,31 +100,38 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { trace!("allowed_variants = {:?}", allowed_variants); - if let TerminatorKind::SwitchInt { targets, .. } = - &mut body.basic_blocks_mut()[bb].terminator_mut().kind - { - let mut new_targets = SwitchTargets::new( - targets.iter().filter(|(val, _)| allowed_variants.contains(val)), - targets.otherwise(), - ); - - if new_targets.iter().count() == allowed_variants.len() { - if let Some(updated) = ensure_otherwise_unreachable(body, &new_targets) { - let new_otherwise = body.basic_blocks_mut().push(updated); - *new_targets.all_targets_mut().last_mut().unwrap() = new_otherwise; - } - } + let terminator = bb_data.terminator(); + let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() }; - if let TerminatorKind::SwitchInt { targets, .. } = - &mut body.basic_blocks_mut()[bb].terminator_mut().kind - { - *targets = new_targets; + let mut reachable_count = 0; + for (index, (val, _)) in targets.iter().enumerate() { + if allowed_variants.contains(&val) { + reachable_count += 1; } else { - unreachable!() + removable_switchs.push((bb, index)); } - } else { - unreachable!() } + + if reachable_count == allowed_variants.len() { + removable_switchs.push((bb, targets.iter().count())); + } + } + + if removable_switchs.is_empty() { + return; + } + + 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; } } } diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index ea7aafd866b15..919e8d6a2340f 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -2,11 +2,13 @@ //! when all of their successors are unreachable. This is achieved through a //! post-order traversal of the blocks. -use crate::simplify; use crate::MirPass; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_target::abi::Size; pub struct UnreachablePropagation; @@ -21,106 +23,133 @@ impl MirPass<'_> for UnreachablePropagation { } fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut patch = MirPatch::new(body); let mut unreachable_blocks = FxHashSet::default(); - let mut replacements = FxHashMap::default(); for (bb, bb_data) in traversal::postorder(body) { let terminator = bb_data.terminator(); - if terminator.kind == TerminatorKind::Unreachable { - unreachable_blocks.insert(bb); - } else { - let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ); - let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable); - - if let Some(terminator_kind) = terminator_kind_opt { - if terminator_kind == TerminatorKind::Unreachable { - unreachable_blocks.insert(bb); - } - replacements.insert(bb, terminator_kind); + let is_unreachable = match &terminator.kind { + TerminatorKind::Unreachable => true, + // This will unconditionally run into an unreachable and is therefore unreachable as well. + TerminatorKind::Goto { target } if unreachable_blocks.contains(target) => { + patch.patch_terminator(bb, TerminatorKind::Unreachable); + true + } + // Try to remove unreachable targets from the switch. + TerminatorKind::SwitchInt { .. } => { + remove_successors_from_switch(tcx, bb, &unreachable_blocks, body, &mut patch) } + _ => false, + }; + if is_unreachable { + unreachable_blocks.insert(bb); } } + if !tcx + .consider_optimizing(|| format!("UnreachablePropagation {:?} ", body.source.def_id())) + { + return; + } + + patch.apply(body); + // We do want do keep some unreachable blocks, but make them empty. for bb in unreachable_blocks { - if !tcx.consider_optimizing(|| { - format!("UnreachablePropagation {:?} ", body.source.def_id()) - }) { - break; - } - body.basic_blocks_mut()[bb].statements.clear(); } + } +} - let replaced = !replacements.is_empty(); +/// Return whether the current terminator is fully unreachable. +fn remove_successors_from_switch<'tcx>( + tcx: TyCtxt<'tcx>, + bb: BasicBlock, + unreachable_blocks: &FxHashSet, + body: &Body<'tcx>, + patch: &mut MirPatch<'tcx>, +) -> bool { + let terminator = body.basic_blocks[bb].terminator(); + let TerminatorKind::SwitchInt { discr, targets } = &terminator.kind else { bug!() }; + let source_info = terminator.source_info; + let location = body.terminator_loc(bb); + + let is_unreachable = |bb| unreachable_blocks.contains(&bb); + + // If there are multiple targets, we want to keep information about reachability for codegen. + // For example (see tests/codegen/match-optimizes-away.rs) + // + // pub enum Two { A, B } + // pub fn identity(x: Two) -> Two { + // match x { + // Two::A => Two::A, + // Two::B => Two::B, + // } + // } + // + // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or LLVM to + // turn it into just `x` later. Without the unreachable, such a transformation would be illegal. + // + // In order to preserve this information, we record reachable and unreachable targets as + // `Assume` statements in MIR. + + let discr_ty = discr.ty(body, tcx); + let discr_size = Size::from_bits(match discr_ty.kind() { + ty::Uint(uint) => uint.normalize(tcx.sess.target.pointer_width).bit_width().unwrap(), + ty::Int(int) => int.normalize(tcx.sess.target.pointer_width).bit_width().unwrap(), + ty::Char => 32, + ty::Bool => 1, + other => bug!("unhandled type: {:?}", other), + }); + + let mut add_assumption = |binop, value| { + let local = patch.new_temp(tcx.types.bool, source_info.span); + let value = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::from_scalar(tcx, Scalar::from_uint(value, discr_size), discr_ty), + })); + let cmp = Rvalue::BinaryOp(binop, Box::new((discr.to_copy(), value))); + patch.add_assign(location, local.into(), cmp); + + let assume = NonDivergingIntrinsic::Assume(Operand::Move(local.into())); + patch.add_statement(location, StatementKind::Intrinsic(Box::new(assume))); + }; - for (bb, terminator_kind) in replacements { - if !tcx.consider_optimizing(|| { - format!("UnreachablePropagation {:?} ", body.source.def_id()) - }) { - break; - } + let otherwise = targets.otherwise(); + let otherwise_unreachable = is_unreachable(otherwise); - body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind; + let reachable_iter = targets.iter().filter(|&(value, bb)| { + let is_unreachable = is_unreachable(bb); + // We remove this target from the switch, so record the inequality using `Assume`. + if is_unreachable && !otherwise_unreachable { + add_assumption(BinOp::Ne, value); } - - if replaced { - simplify::remove_dead_blocks(body); + !is_unreachable + }); + + let new_targets = SwitchTargets::new(reachable_iter, otherwise); + + let num_targets = new_targets.all_targets().len(); + let fully_unreachable = num_targets == 1 && otherwise_unreachable; + + let terminator = match (num_targets, otherwise_unreachable) { + // If all targets are unreachable, we can be unreachable as well. + (1, true) => TerminatorKind::Unreachable, + (1, false) => TerminatorKind::Goto { target: otherwise }, + (2, true) => { + // All targets are unreachable except one. Record the equality, and make it a goto. + let (value, target) = new_targets.iter().next().unwrap(); + add_assumption(BinOp::Eq, value); + TerminatorKind::Goto { target } } - } -} - -fn remove_successors<'tcx, F>( - terminator_kind: &TerminatorKind<'tcx>, - is_unreachable: F, -) -> Option> -where - F: Fn(BasicBlock) -> bool, -{ - let terminator = match terminator_kind { - // This will unconditionally run into an unreachable and is therefore unreachable as well. - TerminatorKind::Goto { target } if is_unreachable(*target) => TerminatorKind::Unreachable, - TerminatorKind::SwitchInt { targets, discr } => { - let otherwise = targets.otherwise(); - - // If all targets are unreachable, we can be unreachable as well. - if targets.all_targets().iter().all(|bb| is_unreachable(*bb)) { - TerminatorKind::Unreachable - } else if is_unreachable(otherwise) { - // If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise) - // unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with - // the otherwise, keeping its unreachable. - // This looses information about reachability causing worse codegen. - // For example (see tests/codegen/match-optimizes-away.rs) - // - // pub enum Two { A, B } - // pub fn identity(x: Two) -> Two { - // match x { - // Two::A => Two::A, - // Two::B => Two::B, - // } - // } - // - // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or LLVM to - // turn it into just `x` later. Without the unreachable, such a transformation would be illegal. - // If the otherwise branch is unreachable, we can delete all other unreachable targets, as they will - // still point to the unreachable and therefore not lose reachability information. - let reachable_iter = targets.iter().filter(|(_, bb)| !is_unreachable(*bb)); - - let new_targets = SwitchTargets::new(reachable_iter, otherwise); - - // No unreachable branches were removed. - if new_targets.all_targets().len() == targets.all_targets().len() { - return None; - } - - TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets } - } else { - // If the otherwise branch is reachable, we don't want to delete any unreachable branches. - return None; - } + _ if num_targets == targets.all_targets().len() => { + // Nothing has changed. + return false; } - _ => return None, + _ => TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets }, }; - Some(terminator) + + patch.patch_terminator(bb, terminator); + fully_unreachable } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 018b6c1ee958c..2a36ad9230e4b 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -9,6 +9,7 @@ + debug self => _2; + let mut _3: &std::option::Option; + let mut _4: isize; ++ let mut _5: bool; + scope 2 { + debug val => _0; + } @@ -29,18 +30,17 @@ StorageLive(_2); _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageLive(_3); + StorageLive(_4); ++ StorageLive(_5); + _4 = discriminant(_2); -+ switchInt(move _4) -> [1: bb2, otherwise: bb1]; - } - - bb1: { -+ unreachable; -+ } -+ -+ bb2: { ++ _5 = Eq(_4, const 1_isize); ++ assume(move _5); + _0 = move ((_2 as Some).0: T); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); StorageDead(_2); diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index 47845758a3f61..14c8c671d3fe2 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -9,6 +9,7 @@ + debug self => _2; + let mut _3: &std::option::Option; + let mut _4: isize; ++ let mut _5: bool; + scope 2 { + debug val => _0; + } @@ -29,26 +30,25 @@ StorageLive(_2); _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2]; +- } +- +- bb1: { + StorageLive(_3); + StorageLive(_4); ++ StorageLive(_5); + _4 = discriminant(_2); -+ switchInt(move _4) -> [1: bb2, otherwise: bb1]; - } - - bb1: { -- StorageDead(_2); -- return; -+ unreachable; - } - -- bb2 (cleanup): { -- resume; -+ bb2: { ++ _5 = Eq(_4, const 1_isize); ++ assume(move _5); + _0 = move ((_2 as Some).0: T); ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); -+ StorageDead(_2); -+ return; + StorageDead(_2); + return; +- } +- +- bb2 (cleanup): { +- resume; } } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir index 392f085bd4d1d..aeb93bd334fe6 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir @@ -6,7 +6,8 @@ fn unwrap_unchecked(_1: Option) -> T { scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { debug self => _1; let mut _2: isize; - let mut _3: &std::option::Option; + let mut _3: bool; + let mut _4: &std::option::Option; scope 2 { debug val => _0; } @@ -19,25 +20,21 @@ fn unwrap_unchecked(_1: Option) -> T { } } scope 4 (inlined Option::::is_some) { - debug self => _3; + debug self => _4; } } bb0: { - StorageLive(_3); + StorageLive(_4); StorageLive(_2); + StorageLive(_3); _2 = discriminant(_1); - switchInt(move _2) -> [1: bb1, otherwise: bb2]; - } - - bb1: { + _3 = Eq(_2, const 1_isize); + assume(move _3); _0 = move ((_1 as Some).0: T); - StorageDead(_2); StorageDead(_3); + StorageDead(_2); + StorageDead(_4); return; } - - bb2: { - unreachable; - } } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir index 392f085bd4d1d..aeb93bd334fe6 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir @@ -6,7 +6,8 @@ fn unwrap_unchecked(_1: Option) -> T { scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { debug self => _1; let mut _2: isize; - let mut _3: &std::option::Option; + let mut _3: bool; + let mut _4: &std::option::Option; scope 2 { debug val => _0; } @@ -19,25 +20,21 @@ fn unwrap_unchecked(_1: Option) -> T { } } scope 4 (inlined Option::::is_some) { - debug self => _3; + debug self => _4; } } bb0: { - StorageLive(_3); + StorageLive(_4); StorageLive(_2); + StorageLive(_3); _2 = discriminant(_1); - switchInt(move _2) -> [1: bb1, otherwise: bb2]; - } - - bb1: { + _3 = Eq(_2, const 1_isize); + assume(move _3); _0 = move ((_1 as Some).0: T); - StorageDead(_2); StorageDead(_3); + StorageDead(_2); + StorageDead(_4); return; } - - bb2: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir index 65d71199aaeb0..0114309dbb58e 100644 --- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir @@ -4,6 +4,7 @@ fn ub_if_b(_1: Thing) -> Thing { debug t => _1; let mut _0: Thing; let mut _2: isize; + let mut _3: bool; scope 1 (inlined unreachable_unchecked) { scope 2 { scope 3 (inlined unreachable_unchecked::runtime) { @@ -13,15 +14,9 @@ fn ub_if_b(_1: Thing) -> Thing { bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb1, otherwise: bb2]; - } - - bb1: { + _3 = Eq(_2, const 0_isize); + assume(move _3); _0 = move _1; return; } - - bb2: { - unreachable; - } } diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index 491db551a7d2b..fe4b33001fc4c 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -52,7 +52,7 @@ StorageLive(_10); StorageLive(_11); _9 = discriminant(_1); - switchInt(move _9) -> [0: bb7, 1: bb5, otherwise: bb6]; + switchInt(move _9) -> [0: bb6, 1: bb5, otherwise: bb3]; } bb1: { @@ -92,10 +92,6 @@ } bb6: { - unreachable; - } - - bb7: { _10 = ((_1 as Ok).0: i32); _3 = ControlFlow::, i32>::Continue(move _10); goto -> bb1; diff --git a/tests/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff similarity index 78% rename from tests/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff rename to tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff index 12ce6505af948..7919450cdc52a 100644 --- a/tests/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff +++ b/tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff @@ -1,12 +1,12 @@ -- // MIR for `main` before UninhabitedEnumBranching -+ // MIR for `main` after UninhabitedEnumBranching +- // MIR for `byref` before UninhabitedEnumBranching ++ // MIR for `byref` after UninhabitedEnumBranching - fn main() -> () { + fn byref() -> () { let mut _0: (); let _1: Plop; - let mut _2: Test1; + let mut _2: Test3; let _3: &str; - let mut _4: &Test1; + let mut _4: &Test3; let mut _5: isize; let _6: &str; let _7: &str; @@ -23,15 +23,15 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = Test1::C; - _1 = Plop { xx: const 51_u32, test1: move _2 }; + _2 = Test3::C; + _1 = Plop { xx: const 51_u32, test3: move _2 }; StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = &(_1.1: Test1); + _4 = &(_1.1: Test3); _5 = discriminant((*_4)); - switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb1, otherwise: bb2]; -+ switchInt(move _5) -> [2: bb5, 3: bb1, otherwise: bb2]; ++ switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb1, otherwise: bb12]; } bb1: { @@ -71,9 +71,9 @@ StorageDead(_4); StorageDead(_3); StorageLive(_9); - _10 = discriminant((_1.1: Test1)); + _10 = discriminant((_1.1: Test3)); - switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb2]; -+ switchInt(move _10) -> [2: bb10, 3: bb7, otherwise: bb2]; ++ switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12]; } bb7: { @@ -110,6 +110,10 @@ _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.diff new file mode 100644 index 0000000000000..5e15298a78c12 --- /dev/null +++ b/tests/mir-opt/uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.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: bb1, otherwise: bb2]; ++ switchInt(move _3) -> [4: bb3, 5: bb1, otherwise: bb5]; + } + + bb1: { + StorageLive(_4); + _4 = const "E"; + _1 = &(*_4); + StorageDead(_4); + goto -> bb4; + } + + bb2: { + unreachable; + } + + 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.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/tests/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir deleted file mode 100644 index 474f43104bb43..0000000000000 --- a/tests/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir +++ /dev/null @@ -1,60 +0,0 @@ -// MIR for `main` after SimplifyCfg-after-uninhabited-enum-branching - -fn main() -> () { - let mut _0: (); - let _1: &str; - let mut _2: Test1; - let mut _3: isize; - let _4: &str; - let _5: &str; - let _6: &str; - let mut _7: Test2; - let mut _8: isize; - let _9: &str; - - bb0: { - StorageLive(_1); - StorageLive(_2); - _2 = Test1::C; - _3 = discriminant(_2); - switchInt(move _3) -> [2: bb1, otherwise: bb2]; - } - - bb1: { - StorageLive(_5); - _5 = const "C"; - _1 = &(*_5); - StorageDead(_5); - StorageDead(_2); - StorageDead(_1); - StorageLive(_6); - StorageLive(_7); - _7 = Test2::D; - _8 = discriminant(_7); - switchInt(move _8) -> [4: bb4, 5: bb3, otherwise: bb2]; - } - - bb2: { - unreachable; - } - - bb3: { - StorageLive(_9); - _9 = const "E"; - _6 = &(*_9); - StorageDead(_9); - goto -> bb5; - } - - bb4: { - _6 = const "D"; - goto -> bb5; - } - - bb5: { - StorageDead(_7); - StorageDead(_6); - _0 = const (); - return; - } -} diff --git a/tests/mir-opt/uninhabited_enum_branching.rs b/tests/mir-opt/uninhabited_enum_branching.rs index 96ae84eca5093..60389117b1614 100644 --- a/tests/mir-opt/uninhabited_enum_branching.rs +++ b/tests/mir-opt/uninhabited_enum_branching.rs @@ -1,11 +1,11 @@ -// skip-filecheck -enum Empty { } +// unit-test: UninhabitedEnumBranching +enum Empty {} // test matching an enum with uninhabited variants enum Test1 { A(Empty), B(Empty), - C + C, } // test an enum where the discriminants don't match the variant indexes @@ -15,17 +15,75 @@ enum Test2 { E = 5, } -// EMIT_MIR uninhabited_enum_branching.main.UninhabitedEnumBranching.diff -// EMIT_MIR uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir -fn main() { +// test matching an enum with uninhabited variants and multiple inhabited +enum Test3 { + A(Empty), + B(Empty), + C, + D, +} + +struct Plop { + xx: u32, + test3: Test3, +} + +// EMIT_MIR uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff +fn simple() { + // CHECK-LABEL: fn simple( + // CHECK: [[discr:_.*]] = discriminant( + // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb1, otherwise: [[unreachable]]]; + // CHECK: [[unreachable]]: { + // CHECK-NEXT: unreachable; match Test1::C { Test1::A(_) => "A(Empty)", Test1::B(_) => "B(Empty)", Test1::C => "C", }; +} +// EMIT_MIR uninhabited_enum_branching.custom_discriminant.UninhabitedEnumBranching.diff +fn custom_discriminant() { + // CHECK-LABEL: fn custom_discriminant( + // CHECK: [[discr:_.*]] = discriminant( + // CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb1, otherwise: bb5]; + // CHECK: bb5: { + // CHECK-NEXT: unreachable; match Test2::D { Test2::D => "D", Test2::E => "E", }; } + +// EMIT_MIR uninhabited_enum_branching.byref.UninhabitedEnumBranching.diff +fn byref() { + // CHECK-LABEL: fn byref( + let plop = Plop { xx: 51, test3: Test3::C }; + + // CHECK: [[ref_discr:_.*]] = discriminant((* + // CHECK: switchInt(move [[ref_discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb5, 3: bb1, otherwise: [[unreachable]]]; + match &plop.test3 { + Test3::A(_) => "A(Empty)", + Test3::B(_) => "B(Empty)", + Test3::C => "C", + Test3::D => "D", + }; + + // CHECK: [[discr:_.*]] = discriminant( + // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable]], 1: [[unreachable]], 2: bb10, 3: bb7, otherwise: [[unreachable]]]; + match plop.test3 { + Test3::A(_) => "A(Empty)", + Test3::B(_) => "B(Empty)", + Test3::C => "C", + Test3::D => "D", + }; + + // CHECK: [[unreachable]]: { + // CHECK-NEXT: unreachable; +} + +fn main() { + simple(); + custom_discriminant(); + byref(); +} diff --git a/tests/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff similarity index 54% rename from tests/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff rename to tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff index 9db95abec34c8..410db79802edc 100644 --- a/tests/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff +++ b/tests/mir-opt/uninhabited_enum_branching.simple.UninhabitedEnumBranching.diff @@ -1,17 +1,13 @@ -- // MIR for `main` before UninhabitedEnumBranching -+ // MIR for `main` after UninhabitedEnumBranching +- // MIR for `simple` before UninhabitedEnumBranching ++ // MIR for `simple` after UninhabitedEnumBranching - fn main() -> () { + fn simple() -> () { let mut _0: (); let _1: &str; let mut _2: Test1; let mut _3: isize; let _4: &str; let _5: &str; - let _6: &str; - let mut _7: Test2; - let mut _8: isize; - let _9: &str; bb0: { StorageLive(_1); @@ -19,7 +15,7 @@ _2 = Test1::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb1, otherwise: bb2]; -+ switchInt(move _3) -> [2: bb1, otherwise: bb2]; ++ switchInt(move _3) -> [0: bb6, 1: bb6, 2: bb1, otherwise: bb6]; } bb1: { @@ -50,31 +46,12 @@ bb5: { StorageDead(_2); StorageDead(_1); - StorageLive(_6); - StorageLive(_7); - _7 = Test2::D; - _8 = discriminant(_7); - switchInt(move _8) -> [4: bb7, 5: bb6, otherwise: bb2]; - } - - bb6: { - StorageLive(_9); - _9 = const "E"; - _6 = &(*_9); - StorageDead(_9); - goto -> bb8; - } - - bb7: { - _6 = const "D"; - goto -> bb8; - } - - bb8: { - StorageDead(_7); - StorageDead(_6); _0 = const (); return; ++ } ++ ++ bb6: { ++ unreachable; } } diff --git a/tests/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/tests/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir deleted file mode 100644 index 9c0c5d18917ae..0000000000000 --- a/tests/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir +++ /dev/null @@ -1,85 +0,0 @@ -// MIR for `main` after SimplifyCfg-after-uninhabited-enum-branching - -fn main() -> () { - let mut _0: (); - let _1: Plop; - let mut _2: Test1; - let _3: &str; - let mut _4: &Test1; - 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 = Test1::C; - _1 = Plop { xx: const 51_u32, test1: move _2 }; - StorageDead(_2); - StorageLive(_3); - StorageLive(_4); - _4 = &(_1.1: Test1); - _5 = discriminant((*_4)); - switchInt(move _5) -> [2: bb3, 3: bb1, otherwise: bb2]; - } - - bb1: { - StorageLive(_8); - _8 = const "D"; - _3 = &(*_8); - StorageDead(_8); - goto -> bb4; - } - - bb2: { - unreachable; - } - - bb3: { - StorageLive(_7); - _7 = const "C"; - _3 = &(*_7); - StorageDead(_7); - goto -> bb4; - } - - bb4: { - StorageDead(_4); - StorageDead(_3); - StorageLive(_9); - _10 = discriminant((_1.1: Test1)); - switchInt(move _10) -> [2: bb6, 3: bb5, otherwise: bb2]; - } - - bb5: { - StorageLive(_13); - _13 = const "D"; - _9 = &(*_13); - StorageDead(_13); - goto -> bb7; - } - - bb6: { - StorageLive(_12); - _12 = const "C"; - _9 = &(*_12); - StorageDead(_12); - goto -> bb7; - } - - bb7: { - StorageDead(_9); - _0 = const (); - StorageDead(_1); - return; - } -} diff --git a/tests/mir-opt/uninhabited_enum_branching2.rs b/tests/mir-opt/uninhabited_enum_branching2.rs deleted file mode 100644 index 751f2ae01f8ba..0000000000000 --- a/tests/mir-opt/uninhabited_enum_branching2.rs +++ /dev/null @@ -1,35 +0,0 @@ -// skip-filecheck -enum Empty { } - -// test matching an enum with uninhabited variants -enum Test1 { - A(Empty), - B(Empty), - C, - D, -} - -struct Plop { - xx: u32, - test1: Test1, -} - -// EMIT_MIR uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff -// EMIT_MIR uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir -fn main() { - let plop = Plop { xx: 51, test1: Test1::C }; - - match &plop.test1 { - Test1::A(_) => "A(Empty)", - Test1::B(_) => "B(Empty)", - Test1::C => "C", - Test1::D => "D", - }; - - match plop.test1 { - Test1::A(_) => "A(Empty)", - Test1::B(_) => "B(Empty)", - Test1::C => "C", - Test1::D => "D", - }; -} 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 498e1e20f8a79..79948139f888d 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) -> [1: bb3, otherwise: bb1]; ++ switchInt(move _2) -> [0: bb5, 1: bb3, otherwise: bb1]; } bb1: { @@ -29,6 +29,10 @@ bb4: { return; ++ } ++ ++ bb5: { ++ unreachable; } } diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff new file mode 100644 index 0000000000000..f6e594ffac765 --- /dev/null +++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff @@ -0,0 +1,45 @@ +- // MIR for `as_match` before UnreachablePropagation ++ // MIR for `as_match` after UnreachablePropagation + + fn as_match() -> () { + let mut _0: (); + let mut _1: std::option::Option; + let mut _2: isize; + let _3: Empty; + let mut _4: !; ++ let mut _5: bool; + scope 1 { + debug _x => _3; + } + + bb0: { + StorageLive(_1); + _1 = empty() -> [return: bb1, unwind unreachable]; + } + + bb1: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3]; ++ _5 = Eq(_2, const 0_isize); ++ assume(move _5); ++ goto -> bb4; + } + + bb2: { +- StorageLive(_3); +- _3 = move ((_1 as Some).0: Empty); +- StorageLive(_4); + unreachable; + } + + bb3: { + unreachable; + } + + bb4: { + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff new file mode 100644 index 0000000000000..2813d64672e6a --- /dev/null +++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff @@ -0,0 +1,45 @@ +- // MIR for `as_match` before UnreachablePropagation ++ // MIR for `as_match` after UnreachablePropagation + + fn as_match() -> () { + let mut _0: (); + let mut _1: std::option::Option; + let mut _2: isize; + let _3: Empty; + let mut _4: !; ++ let mut _5: bool; + scope 1 { + debug _x => _3; + } + + bb0: { + StorageLive(_1); + _1 = empty() -> [return: bb1, unwind continue]; + } + + bb1: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3]; ++ _5 = Eq(_2, const 0_isize); ++ assume(move _5); ++ goto -> bb4; + } + + bb2: { +- StorageLive(_3); +- _3 = move ((_1 as Some).0: Empty); +- StorageLive(_4); + unreachable; + } + + bb3: { + unreachable; + } + + bb4: { + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-abort.diff b/tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-abort.diff similarity index 74% rename from tests/mir-opt/unreachable.main.UnreachablePropagation.panic-abort.diff rename to tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-abort.diff index eb5a0c39b0b2f..61959732720e0 100644 --- a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-abort.diff +++ b/tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-abort.diff @@ -1,13 +1,14 @@ -- // MIR for `main` before UnreachablePropagation -+ // MIR for `main` after UnreachablePropagation +- // MIR for `if_let` before UnreachablePropagation ++ // MIR for `if_let` after UnreachablePropagation - fn main() -> () { + fn if_let() -> () { let mut _0: (); let mut _1: std::option::Option; let mut _2: isize; let _5: (); let mut _6: bool; let mut _7: !; ++ let mut _8: bool; scope 1 { debug _x => _3; let _3: Empty; @@ -25,7 +26,9 @@ bb1: { _2 = discriminant(_1); - switchInt(move _2) -> [1: bb2, otherwise: bb6]; -+ switchInt(move _2) -> [1: bb2, otherwise: bb3]; ++ _8 = Ne(_2, const 1_isize); ++ assume(move _8); ++ goto -> bb6; } bb2: { @@ -36,29 +39,31 @@ - StorageLive(_6); - _6 = const true; - switchInt(move _6) -> [0: bb4, otherwise: bb3]; -- } -- -- bb3: { ++ unreachable; + } + + bb3: { - _4 = const 21_i32; - _5 = const (); - goto -> bb5; -- } -- -- bb4: { ++ unreachable; + } + + bb4: { - _4 = const 42_i32; - _5 = const (); - goto -> bb5; -- } -- -- bb5: { ++ unreachable; + } + + bb5: { - StorageDead(_6); - StorageDead(_5); - StorageLive(_7); unreachable; } -- bb6: { -+ bb3: { + bb6: { _0 = const (); StorageDead(_1); return; diff --git a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-unwind.diff similarity index 74% rename from tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff rename to tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-unwind.diff index 906dce9819fdc..476e2f5599449 100644 --- a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff +++ b/tests/mir-opt/unreachable.if_let.UnreachablePropagation.panic-unwind.diff @@ -1,13 +1,14 @@ -- // MIR for `main` before UnreachablePropagation -+ // MIR for `main` after UnreachablePropagation +- // MIR for `if_let` before UnreachablePropagation ++ // MIR for `if_let` after UnreachablePropagation - fn main() -> () { + fn if_let() -> () { let mut _0: (); let mut _1: std::option::Option; let mut _2: isize; let _5: (); let mut _6: bool; let mut _7: !; ++ let mut _8: bool; scope 1 { debug _x => _3; let _3: Empty; @@ -25,7 +26,9 @@ bb1: { _2 = discriminant(_1); - switchInt(move _2) -> [1: bb2, otherwise: bb6]; -+ switchInt(move _2) -> [1: bb2, otherwise: bb3]; ++ _8 = Ne(_2, const 1_isize); ++ assume(move _8); ++ goto -> bb6; } bb2: { @@ -36,29 +39,31 @@ - StorageLive(_6); - _6 = const true; - switchInt(move _6) -> [0: bb4, otherwise: bb3]; -- } -- -- bb3: { ++ unreachable; + } + + bb3: { - _4 = const 21_i32; - _5 = const (); - goto -> bb5; -- } -- -- bb4: { ++ unreachable; + } + + bb4: { - _4 = const 42_i32; - _5 = const (); - goto -> bb5; -- } -- -- bb5: { ++ unreachable; + } + + bb5: { - StorageDead(_6); - StorageDead(_5); - StorageLive(_7); unreachable; } -- bb6: { -+ bb3: { + bb6: { _0 = const (); StorageDead(_1); return; diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs index 5c0df09b752ea..5b96681d9df58 100644 --- a/tests/mir-opt/unreachable.rs +++ b/tests/mir-opt/unreachable.rs @@ -1,13 +1,31 @@ -// skip-filecheck +// unit-test: UnreachablePropagation // EMIT_MIR_FOR_EACH_PANIC_STRATEGY + enum Empty {} fn empty() -> Option { None } -// EMIT_MIR unreachable.main.UnreachablePropagation.diff -fn main() { +// EMIT_MIR unreachable.if_let.UnreachablePropagation.diff +fn if_let() { + // CHECK-LABEL: fn if_let( + // CHECK: bb0: { + // CHECK: {{_.*}} = empty() + // CHECK: bb1: { + // CHECK: [[ne:_.*]] = Ne({{.*}}, const 1_isize); + // CHECK-NEXT: assume(move [[ne]]); + // CHECK-NEXT: goto -> bb6; + // CHECK: bb2: { + // CHECK-NEXT: unreachable; + // CHECK: bb3: { + // CHECK-NEXT: unreachable; + // CHECK: bb4: { + // CHECK-NEXT: unreachable; + // CHECK: bb5: { + // CHECK-NEXT: unreachable; + // CHECK: bb6: { + // CHECK: return; if let Some(_x) = empty() { let mut _y; @@ -20,3 +38,29 @@ fn main() { match _x { } } } + +// EMIT_MIR unreachable.as_match.UnreachablePropagation.diff +fn as_match() { + // CHECK-LABEL: fn as_match( + // CHECK: bb0: { + // CHECK: {{_.*}} = empty() + // CHECK: bb1: { + // CHECK: [[eq:_.*]] = Eq({{.*}}, const 0_isize); + // CHECK-NEXT: assume(move [[eq]]); + // CHECK-NEXT: goto -> bb4; + // CHECK: bb2: { + // CHECK-NEXT: unreachable; + // CHECK: bb3: { + // CHECK-NEXT: unreachable; + // CHECK: bb4: { + // CHECK: return; + match empty() { + None => {} + Some(_x) => match _x {} + } +} + +fn main() { + if_let(); + as_match(); +} diff --git a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-abort.diff b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-abort.diff index 713757ce6e080..11d7924e7360e 100644 --- a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-abort.diff +++ b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-abort.diff @@ -9,6 +9,7 @@ let _5: (); let mut _6: bool; let mut _7: !; ++ let mut _8: bool; scope 1 { debug x => _1; scope 2 { @@ -35,7 +36,10 @@ StorageLive(_5); StorageLive(_6); _6 = _1; - switchInt(move _6) -> [0: bb4, otherwise: bb3]; +- switchInt(move _6) -> [0: bb4, otherwise: bb3]; ++ _8 = Ne(_6, const false); ++ assume(move _8); ++ goto -> bb3; } bb3: { diff --git a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff index a0479fb91304b..df6f5609fbfa9 100644 --- a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff +++ b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff @@ -9,6 +9,7 @@ let _5: (); let mut _6: bool; let mut _7: !; ++ let mut _8: bool; scope 1 { debug x => _1; scope 2 { @@ -35,7 +36,10 @@ StorageLive(_5); StorageLive(_6); _6 = _1; - switchInt(move _6) -> [0: bb4, otherwise: bb3]; +- switchInt(move _6) -> [0: bb4, otherwise: bb3]; ++ _8 = Ne(_6, const false); ++ assume(move _8); ++ goto -> bb3; } bb3: { diff --git a/tests/mir-opt/unreachable_diverging.rs b/tests/mir-opt/unreachable_diverging.rs index 3713bcaea1694..b1df6f85262de 100644 --- a/tests/mir-opt/unreachable_diverging.rs +++ b/tests/mir-opt/unreachable_diverging.rs @@ -1,5 +1,6 @@ -// skip-filecheck +// unit-test: UnreachablePropagation // EMIT_MIR_FOR_EACH_PANIC_STRATEGY + pub enum Empty {} fn empty() -> Option { @@ -12,6 +13,23 @@ fn loop_forever() { // EMIT_MIR unreachable_diverging.main.UnreachablePropagation.diff fn main() { + // CHECK-LABEL: fn main( + // CHECK: bb0: { + // CHECK: {{_.*}} = empty() + // CHECK: bb1: { + // CHECK: switchInt({{.*}}) -> [1: bb2, otherwise: bb6]; + // CHECK: bb2: { + // CHECK: [[ne:_.*]] = Ne({{.*}}, const false); + // CHECK: assume(move [[ne]]); + // CHECK: goto -> bb3; + // CHECK: bb3: { + // CHECK: {{_.*}} = loop_forever() + // CHECK: bb4: { + // CHECK: unreachable; + // CHECK: bb5: { + // CHECK: unreachable; + // CHECK: bb6: { + // CHECK: return; let x = true; if let Some(bomb) = empty() { if x {