diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 956a024fa4dc3..ef2e028af100a 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -135,6 +135,7 @@ pub(crate) fn codegen_fn<'tcx>( bcx, block_map, local_map: IndexVec::with_capacity(mir.local_decls.len()), + shared_unreachable: None, caller_location: None, // set by `codegen_fn_prelude` clif_comments, @@ -441,7 +442,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { assert_eq!(targets.iter().count(), 1); let (then_value, then_block) = targets.iter().next().unwrap(); let then_block = fx.get_block(then_block); - let else_block = fx.get_block(targets.otherwise()); + let else_block = fx.get_switch_block(targets.otherwise()); let test_zero = match then_value { 0 => true, 1 => false, @@ -472,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let block = fx.get_block(block); switch.set_entry(value, block); } - let otherwise_block = fx.get_block(targets.otherwise()); + let otherwise_block = fx.get_switch_block(targets.otherwise()); switch.emit(&mut fx.bcx, discr, otherwise_block); } } @@ -561,6 +562,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { } }; } + + if let Some(unreachable) = fx.shared_unreachable { + fx.bcx.switch_to_block(unreachable); + fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); + } } fn codegen_stmt<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 534557fcd41be..6446290151365 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -298,6 +298,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) bcx: FunctionBuilder<'clif>, pub(crate) block_map: IndexVec, pub(crate) local_map: IndexVec>, + pub(crate) shared_unreachable: Option, /// When `#[track_caller]` is used, the implicit caller location is stored in this variable. pub(crate) caller_location: Option>, @@ -375,6 +376,17 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { *self.block_map.get(bb).unwrap() } + pub(crate) fn get_switch_block(&mut self, sa: SwitchAction) -> Block { + match sa { + SwitchAction::Goto(bb) => self.get_block(bb), + SwitchAction::Unreachable => self.unreachable_block(), + } + } + + pub(crate) fn unreachable_block(&mut self) -> Block { + *self.shared_unreachable.get_or_insert_with(|| self.bcx.create_block()) + } + pub(crate) fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { *self.local_map.get(local).unwrap_or_else(|| { panic!("Local {:?} doesn't exist", local); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b0a1dedd646b0..76c318e4787ec 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,7 +5,8 @@ use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{ - self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason, + self, AssertKind, BasicBlock, InlineAsmMacro, SwitchAction, SwitchTargets, + UnwindTerminateReason, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -96,6 +97,17 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } } + fn llbb_with_cleanup_from_switch_action>( + &self, + fx: &mut FunctionCx<'a, 'tcx, Bx>, + target: mir::SwitchAction, + ) -> Bx::BasicBlock { + match target { + mir::SwitchAction::Unreachable => fx.unreachable_block(), + mir::SwitchAction::Goto(bb) => self.llbb_with_cleanup(fx, bb), + } + } + fn llbb_characteristics>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, @@ -368,7 +380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // If our discriminant is a constant we can branch directly if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) { let target = targets.target_for_value(const_discr); - bx.br(helper.llbb_with_cleanup(self, target)); + bx.br(helper.llbb_with_cleanup_from_switch_action(self, target)); return; }; @@ -379,9 +391,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (test_value, target) = target_iter.next().unwrap(); let otherwise = targets.otherwise(); let lltarget = helper.llbb_with_cleanup(self, target); - let llotherwise = helper.llbb_with_cleanup(self, otherwise); + let llotherwise = helper.llbb_with_cleanup_from_switch_action(self, otherwise); let target_cold = self.cold_blocks[target]; - let otherwise_cold = self.cold_blocks[otherwise]; + let otherwise_cold = match otherwise { + SwitchAction::Goto(otherwise) => self.cold_blocks[otherwise], + SwitchAction::Unreachable => true, + }; // If `target_cold == otherwise_cold`, the branches have the same weight // so there is no expectation. If they differ, the `target` branch is expected // when the `otherwise` branch is cold. @@ -406,7 +421,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } else if self.cx.sess().opts.optimize == OptLevel::No && target_iter.len() == 2 - && self.mir[targets.otherwise()].is_empty_unreachable() + && self.mir.basic_blocks.is_empty_unreachable(targets.otherwise()) { // In unoptimized builds, if there are two normal targets and the `otherwise` target is // an unreachable BB, emit `br` instead of `switch`. This leaves behind the unreachable @@ -431,7 +446,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { bx.switch( discr_value, - helper.llbb_with_cleanup(self, targets.otherwise()), + helper.llbb_with_cleanup_from_switch_action(self, targets.otherwise()), target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))), ); } @@ -1648,11 +1663,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn unreachable_block(&mut self) -> Bx::BasicBlock { - self.unreachable_block.unwrap_or_else(|| { + *self.unreachable_block.get_or_insert_with(|| { let llbb = Bx::append_block(self.cx, self.llfn, "unreachable"); let mut bx = Bx::build(self.cx, llbb); bx.unreachable(); - self.unreachable_block = Some(llbb); llbb }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 32e77fe1024da..527497c0c97bb 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -478,12 +478,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &ImmTy::from_uint(const_int, discr.layout), )?; if res.to_scalar().to_bool()? { - target_block = target; + target_block = mir::SwitchAction::Goto(target); break; } } - self.go_to_block(target_block); + match target_block { + mir::SwitchAction::Goto(target) => self.go_to_block(target), + mir::SwitchAction::Unreachable => throw_ub!(Unreachable), + } } Call { diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 3eb563d7d6e57..982f9fc5f9c42 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -9,7 +9,9 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; use crate::mir::traversal::Postorder; -use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK, Terminator, TerminatorKind}; +use crate::mir::{ + BasicBlock, BasicBlockData, START_BLOCK, SwitchAction, Terminator, TerminatorKind, +}; #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlocks<'tcx> { @@ -84,7 +86,9 @@ impl<'tcx> BasicBlocks<'tcx> { for (value, target) in targets.iter() { switch_sources.entry((target, bb)).or_default().push(Some(value)); } - switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); + if let SwitchAction::Goto(otherwise) = targets.otherwise() { + switch_sources.entry((otherwise, bb)).or_default().push(None); + } } } switch_sources @@ -122,6 +126,13 @@ impl<'tcx> BasicBlocks<'tcx> { pub fn invalidate_cfg_cache(&mut self) { self.cache = Cache::default(); } + + pub fn is_empty_unreachable(&self, action: SwitchAction) -> bool { + match action { + SwitchAction::Goto(bb) => self[bb].is_empty_unreachable(), + SwitchAction::Unreachable => true, + } + } } impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 47522f00bb1b3..89a735fc26388 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1015,12 +1015,14 @@ impl<'tcx> TerminatorKind<'tcx> { | Unreachable | CoroutineDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref targets, .. } => targets - .values - .iter() - .map(|&u| Cow::Owned(u.to_string())) - .chain(iter::once("otherwise".into())) - .collect(), + SwitchInt { ref targets, .. } => { + let mut labels: Vec<_> = + targets.values.iter().map(|&u| Cow::Owned(u.to_string())).collect(); + if let SwitchAction::Goto(_) = targets.otherwise() { + labels.push("otherwise".into()); + } + labels + } Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { vec!["return".into(), "unwind".into()] } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index bbbaffc5a35cc..d7b3a6234e194 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -959,21 +959,51 @@ pub struct SwitchTargets { /// are found in the corresponding indices from the `targets` vector. pub(super) values: SmallVec<[Pu128; 1]>, - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. + /// Possible branch sites. + /// + /// If `targets.len() == values.len() + 1`, the last element of this vector + /// is used for the otherwise branch in [`SwitchAction::Goto`]. + /// + /// If `targets.len() == values.len()`, the otherwise branch is + /// [`SwitchAction::Unreachable`]. + /// + /// You must ensure that we're always in at one of those cases. // // This invariant is quite non-obvious and also could be improved. // One way to make this invariant is to have something like this instead: // // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option // exhaustive if None + // otherwise: SwitchAction, // // However we’ve decided to keep this as-is until we figure a case // where some other approach seems to be strictly better than other. pub(super) targets: SmallVec<[BasicBlock; 2]>, } +/// The action to be taken for a particular input to the [`TerminatorKind::SwitchInt`] +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum SwitchAction { + /// Jump to the specified block + Goto(BasicBlock), + /// Triggers undefined behavior + /// + /// This is equivalent to jumping to a block with [`TerminatorKind::Unreachable`], + /// but lets us not have to store such a block in the body. + /// It also makes it easier in analysis to know this action is unreachable + /// without needing to have all the basic blocks around to look at. + Unreachable, +} + +impl SwitchAction { + pub fn into_terminator<'tcx>(self) -> TerminatorKind<'tcx> { + match self { + SwitchAction::Goto(bb) => TerminatorKind::Goto { target: bb }, + SwitchAction::Unreachable => TerminatorKind::Unreachable, + } + } +} + /// Action to be taken when a stack unwind happens. #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 473b817aed076..ea9a63a65ccb5 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -14,10 +14,12 @@ impl SwitchTargets { /// /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to /// `goto otherwise;`. - pub fn new(targets: impl Iterator, otherwise: BasicBlock) -> Self { + pub fn new(targets: impl Iterator, otherwise: SwitchAction) -> Self { let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.map(|(v, t)| (Pu128(v), t)).unzip(); - targets.push(otherwise); + if let SwitchAction::Goto(otherwise) = otherwise { + targets.push(otherwise); + } Self { values, targets } } @@ -39,10 +41,17 @@ impl SwitchTargets { } } - /// Returns the fallback target that is jumped to when none of the values match the operand. + /// Returns the fallback action when none of the values match the operand. #[inline] - pub fn otherwise(&self) -> BasicBlock { - *self.targets.last().unwrap() + pub fn otherwise(&self) -> SwitchAction { + debug_assert!( + self.targets.len() == self.values.len() || self.targets.len() == self.values.len() + 1 + ); + if self.targets.len() > self.values.len() { + SwitchAction::Goto(*self.targets.last().unwrap()) + } else { + SwitchAction::Unreachable + } } /// Returns an iterator over the switch targets. @@ -82,8 +91,9 @@ impl SwitchTargets { /// specific value. This cannot fail, as it'll return the `otherwise` /// branch if there's not a specific match for the value. #[inline] - 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()) + pub fn target_for_value(&self, value: u128) -> SwitchAction { + let specific = self.iter().find_map(|(v, t)| (v == value).then_some(t)); + if let Some(specific) = specific { SwitchAction::Goto(specific) } else { self.otherwise() } } /// Adds a new target to the switch. But You cannot add an already present value. @@ -93,8 +103,12 @@ impl SwitchTargets { if self.values.contains(&value) { bug!("target value {:?} already present", value); } + + // There may or may not be a fallback in `targets`, so make sure to + // insert the new target at the same index as its value. + let insert_point = self.values.len(); self.values.push(value); - self.targets.insert(self.targets.len() - 1, bb); + self.targets.insert(insert_point, bb); } /// Returns true if all targets (including the fallback target) are distinct. @@ -431,7 +445,11 @@ mod helper { #[inline] pub fn successors_for_value(&self, value: u128) -> Successors<'_> { let target = self.target_for_value(value); - (&[]).into_iter().copied().chain(Some(target)) + (&[]).into_iter().copied().chain(if let SwitchAction::Goto(otherwise) = target { + Some(otherwise) + } else { + None + }) } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 3dd5de0223081..95d1c906e5d57 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { targets.push(self.parse_block(arm.body)?); } - Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise)) + Ok(SwitchTargets::new(values.into_iter().zip(targets), SwitchAction::Goto(otherwise))) } fn parse_call(&self, args: &[ExprId]) -> PResult> { diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 0d36b7bb3ee7b..1a834fb11f26f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } }), - otherwise_block, + SwitchAction::Goto(otherwise_block), ); debug!("num_enum_variants: {}", adt_def.variants().len()); let discr_ty = adt_def.repr().discr_type().to_ty(self.tcx); @@ -124,7 +124,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } }), - otherwise_block, + SwitchAction::Goto(otherwise_block), ); let terminator = TerminatorKind::SwitchInt { discr: Operand::Copy(place), diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f8a8467494753..b154e7f9b8ed7 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -591,6 +591,10 @@ where succ: BasicBlock, unwind: Unwind, ) -> BasicBlock { + // FIXME: the arguments here are still using the manual-unreachable; + // consider changing them to allow `SwitchAction::Unreachable` somehow. + debug_assert_eq!(blocks.len(), values.len() + 1); + // If there are multiple variants, then if something // is present within the enum the discriminant, tracked // by the rest path, must be initialized. @@ -609,7 +613,7 @@ where discr: Operand::Move(discr), targets: SwitchTargets::new( values.iter().copied().zip(blocks.iter().copied()), - *blocks.last().unwrap(), + SwitchAction::Goto(*blocks.last().unwrap()), ), }, }), diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 6427fd0fd295b..dd59dc2840b64 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,6 +1,8 @@ use std::ops::RangeInclusive; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; +use rustc_middle::mir::{ + self, BasicBlock, CallReturnPlaces, Location, SwitchAction, TerminatorEdges, +}; use super::visitor::ResultsVisitor; use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget}; @@ -304,12 +306,14 @@ impl Direction for Forward { // Once we get to the final, "otherwise" branch, there is no need to preserve // `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save // a clone of the dataflow state. - let otherwise = targets.otherwise(); - analysis.apply_switch_int_edge_effect(&mut data, exit_state, SwitchIntTarget { - value: None, - target: otherwise, - }); - propagate(otherwise, exit_state); + if let SwitchAction::Goto(otherwise) = targets.otherwise() { + analysis.apply_switch_int_edge_effect( + &mut data, + exit_state, + SwitchIntTarget { value: None, target: otherwise }, + ); + propagate(otherwise, exit_state); + } } else { for target in targets.all_targets() { propagate(*target, exit_state); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index f6536d78761a9..18c335a1e5465 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1039,8 +1039,10 @@ fn insert_switch<'tcx>( ) { let default_block = insert_term_block(body, default); let (assign, discr) = transform.get_discr(body); - let switch_targets = - SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block); + let switch_targets = SwitchTargets::new( + cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), + SwitchAction::Goto(default_block), + ); let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index b2ee50de50a23..32a8fc74f0d8f 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -110,7 +110,9 @@ impl<'tcx> MockBlocks<'tcx> { let otherwise = if branch_index == branches.len() { to_block } else { - let old_otherwise = targets.otherwise(); + let SwitchAction::Goto(old_otherwise) = targets.otherwise() else { + bug!("these tests always have explicit otherwise blocks"); + }; if branch_index > branches.len() { branches.push((branches.len() as u128, old_otherwise)); while branches.len() < branch_index { @@ -122,7 +124,7 @@ impl<'tcx> MockBlocks<'tcx> { old_otherwise } }; - *targets = SwitchTargets::new(branches.into_iter(), otherwise); + *targets = SwitchTargets::new(branches.into_iter(), SwitchAction::Goto(otherwise)); } ref invalid => bug!("Invalid BasicBlock kind or no to_block: {:?}", invalid), } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index cc44114782cf3..ae9b0b4aa3d54 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -523,9 +523,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Bottom => TerminatorEdges::None, FlatSet::Elem(scalar) => { if let Ok(scalar_int) = scalar.try_to_scalar_int() { - TerminatorEdges::Single( - targets.target_for_value(scalar_int.to_bits_unchecked()), - ) + let choice = scalar_int.to_bits_unchecked(); + match targets.target_for_value(choice) { + SwitchAction::Goto(bb) => TerminatorEdges::Single(bb), + SwitchAction::Unreachable => TerminatorEdges::None, + } } else { TerminatorEdges::SwitchInt { discr, targets } } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 91e1395e76415..3d0481643a753 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -173,7 +173,10 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { else { unreachable!() }; - (value, targets.target_for_value(value)) + let SwitchAction::Goto(target) = targets.target_for_value(value) else { + unreachable!() + }; + (value, target) }); // The otherwise either is the same target branch or an unreachable. let eq_targets = SwitchTargets::new(eq_new_targets, parent_targets.otherwise()); @@ -287,7 +290,7 @@ fn evaluate_candidate<'tcx>( // When thie BB has exactly one statement, this statement should be discriminant. let need_hoist_discriminant = bbs[child].statements.len() == 1; let child_place = if need_hoist_discriminant { - if !bbs[targets.otherwise()].is_empty_unreachable() { + if !bbs.is_empty_unreachable(targets.otherwise()) { // Someone could write code like this: // ```rust // let Q = val; @@ -350,13 +353,15 @@ fn evaluate_candidate<'tcx>( }; *child_place }; - let destination = if need_hoist_discriminant || bbs[targets.otherwise()].is_empty_unreachable() - { + let destination = if need_hoist_discriminant || bbs.is_empty_unreachable(targets.otherwise()) { child_targets.otherwise() } else { targets.otherwise() }; + // We only care about optimizing things that go somewhere (maybe?) + let SwitchAction::Goto(destination) = destination else { return None }; + // Verify that the optimization is legal for each branch for (value, child) in targets.iter() { if !verify_candidate_branch( @@ -418,7 +423,7 @@ fn verify_candidate_branch<'tcx>( } } // It must fall through to `destination` if the switch misses. - if destination != targets.otherwise() { + if SwitchAction::Goto(destination) != targets.otherwise() { return false; } // It must have exactly one branch for value `value` and have no more branches. diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index f1705d0c831c2..12041e83cef8a 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -771,9 +771,10 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { && let Some(constant) = value_const.to_bits(value_const.size()).discard_err() { // We managed to evaluate the discriminant, so we know we only need to visit - // one target. - let target = targets.target_for_value(constant); - self.worklist.push(target); + // one target, or none if this value is unreachable. + if let SwitchAction::Goto(target) = targets.target_for_value(constant) { + self.worklist.push(target); + } return; } // We failed to evaluate the discriminant, fallback to visiting all successors. diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 534ba99178017..9192aebeccd0b 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -2,6 +2,7 @@ use std::iter; use rustc_abi::Integer; use rustc_index::IndexSlice; +use rustc_middle::bug; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; @@ -109,7 +110,7 @@ trait SimplifyMatch<'tcx> { tcx: TyCtxt<'tcx>, targets: &SwitchTargets, typing_env: ty::TypingEnv<'tcx>, - bbs: &IndexSlice>, + bbs: &BasicBlocks<'tcx>, discr_ty: Ty<'tcx>, ) -> Option<()>; @@ -166,7 +167,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { tcx: TyCtxt<'tcx>, targets: &SwitchTargets, typing_env: ty::TypingEnv<'tcx>, - bbs: &IndexSlice>, + bbs: &BasicBlocks<'tcx>, _discr_ty: Ty<'tcx>, ) -> Option<()> { let (first, second) = match targets.all_targets() { @@ -228,10 +229,11 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { ) { let ((val, first), second) = match (targets.all_targets(), targets.all_values()) { (&[first, otherwise], &[val]) => ((val, first), otherwise), + (&[first, second], &[val, _]) => ((val, first), second), (&[first, second, otherwise], &[val, _]) if bbs[otherwise].is_empty_unreachable() => { ((val, first), second) } - _ => unreachable!(), + pair => bug!("targets and values are {pair:?}"), }; // We already checked that first and second are different blocks, @@ -379,7 +381,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { tcx: TyCtxt<'tcx>, targets: &SwitchTargets, typing_env: ty::TypingEnv<'tcx>, - bbs: &IndexSlice>, + bbs: &BasicBlocks<'tcx>, discr_ty: Ty<'tcx>, ) -> Option<()> { if targets.iter().len() < 2 || targets.iter().len() > 64 { @@ -389,7 +391,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { if !targets.is_distinct() { return None; } - if !bbs[targets.otherwise()].is_empty_unreachable() { + if !bbs.is_empty_unreachable(targets.otherwise()) { return None; } let mut target_iter = targets.iter(); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 722da3c420dc9..c23e7fdf35878 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -650,7 +650,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { let switch = self.block(vec![], TerminatorKind::Unreachable, false); let unwind = self.clone_fields(dest, src, switch, unwind, args.upvar_tys()); let target = self.block(vec![], TerminatorKind::Return, false); - let unreachable = self.block(vec![], TerminatorKind::Unreachable, false); + let unreachable = SwitchAction::Unreachable; let mut cases = Vec::with_capacity(args.state_tys(coroutine_def_id, self.tcx).count()); for (index, state_tys) in args.state_tys(coroutine_def_id, self.tcx).enumerate() { let variant_index = VariantIdx::new(index); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 4f312ed2aaabc..f23786f469d5c 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -283,9 +283,9 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { pub(super) fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { if let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind { let otherwise = targets.otherwise(); - if targets.iter().any(|t| t.1 == otherwise) { + if targets.iter().any(|t| SwitchAction::Goto(t.1) == otherwise) { *targets = SwitchTargets::new( - targets.iter().filter(|t| t.1 != otherwise), + targets.iter().filter(|t| SwitchAction::Goto(t.1) != otherwise), targets.otherwise(), ); } diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index bea3d0d8557a7..4df3ea90ae1b9 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -45,7 +45,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { let constant = c.const_.try_eval_bits(tcx, typing_env); if let Some(constant) = constant { let target = targets.target_for_value(constant); - TerminatorKind::Goto { target } + target.into_terminator() } else { continue; } diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index b6d8017308662..967d43f5ba9d6 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -3,8 +3,8 @@ use std::iter; use rustc_middle::bug; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::{ - BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, StatementKind, SwitchTargets, - TerminatorKind, + BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, StatementKind, SwitchAction, + SwitchTargets, TerminatorKind, }; use rustc_middle::ty::{Ty, TyCtxt}; use tracing::trace; @@ -125,7 +125,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { e => bug!("expected 2 switch targets, got: {:?}", e), }; - let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise); + let targets = SwitchTargets::new( + iter::once((new_value, bb_cond)), + SwitchAction::Goto(bb_otherwise), + ); let terminator = bb.terminator_mut(); terminator.kind = diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 55dcad0680a96..f8d2d2546b76d 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::{ BasicBlock, BasicBlockData, BasicBlocks, Body, Local, Operand, Rvalue, StatementKind, - TerminatorKind, + SwitchAction, TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -119,13 +119,17 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching { bug!() }; + let SwitchAction::Goto(otherwise_bb) = targets.otherwise() else { + continue; + }; + for (index, (val, _)) in targets.iter().enumerate() { if !allowed_variants.remove(&val) { unreachable_targets.push(index); } } let otherwise_is_empty_unreachable = - body.basic_blocks[targets.otherwise()].is_empty_unreachable(); + body.basic_blocks[otherwise_bb].is_empty_unreachable(); fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool { // After resolving https://github.com/llvm/llvm-project/issues/78578, // We can remove this check. @@ -181,7 +185,7 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching { // Despite the LLVM issue, we hope that small enum can still be transformed. // This is valuable for both `a <= b` and `if let Some/Ok(v)`. && (targets.all_targets().len() <= 3 - || check_successors(&body.basic_blocks, targets.otherwise())); + || check_successors(&body.basic_blocks, otherwise_bb)); let replace_otherwise_to_unreachable = otherwise_is_last_variant || (!otherwise_is_empty_unreachable && allowed_variants.is_empty()); @@ -196,7 +200,7 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching { // We have checked that `allowed_variants` has only one element. #[allow(rustc::potential_query_instability)] let last_variant = *allowed_variants.iter().next().unwrap(); - targets.add_target(last_variant, targets.otherwise()); + targets.add_target(last_variant, otherwise_bb); } unreachable_targets.push(targets.iter().count()); } diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 734703ec78b55..c0a9974ddbc5f 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -110,13 +110,20 @@ fn remove_successors_from_switch<'tcx>( patch.add_statement(location, StatementKind::Intrinsic(Box::new(assume))); }; - let otherwise = targets.otherwise(); - let otherwise_unreachable = is_unreachable(otherwise); + let mut anything_changed = false; + let otherwise = match targets.otherwise() { + SwitchAction::Goto(bb) if is_unreachable(bb) => { + anything_changed = true; + SwitchAction::Unreachable + } + target => target, + }; let reachable_iter = targets.iter().filter(|&(value, bb)| { let is_unreachable = is_unreachable(bb); + anything_changed |= is_unreachable; // We remove this target from the switch, so record the inequality using `Assume`. - if is_unreachable && !otherwise_unreachable { + if is_unreachable && otherwise != SwitchAction::Unreachable { add_assumption(BinOp::Ne, value); } !is_unreachable @@ -124,26 +131,22 @@ fn remove_successors_from_switch<'tcx>( 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 } - } - _ if num_targets == targets.all_targets().len() => { - // Nothing has changed. - return false; - } - _ => TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets }, + let value_count = new_targets.iter().len(); + let terminator = if value_count == 0 { + // No specific values left + otherwise.into_terminator() + } else if value_count == 1 && otherwise == SwitchAction::Unreachable { + // 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 } + } else if !anything_changed { + return false; + } else { + TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets } }; + let fully_unreachable = matches!(terminator, TerminatorKind::Unreachable); patch.patch_terminator(bb, terminator); fully_unreachable } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index a670da94fcc9e..ec4ee45aed38f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -344,10 +344,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, *target, EdgeKind::Normal); } TerminatorKind::SwitchInt { targets, discr: _ } => { - for (_, target) in targets.iter() { + for &target in targets.all_targets() { self.check_edge(location, target, EdgeKind::Normal); } - self.check_edge(location, targets.otherwise(), EdgeKind::Normal); self.value_cache.clear(); self.value_cache.extend(targets.iter().map(|(value, _)| value)); diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index dc63ea1999e5b..d0fba6877107a 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -223,6 +223,8 @@ where ty_consts: IndexMap::default(), mir_consts: IndexMap::default(), layouts: IndexMap::default(), + synthetic_unreachable_block: usize::MAX, + unreachable_block_span: None, })); stable_mir::compiler_interface::run(&tables, || init(&tables, f)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index de933952c6a7b..5f642219800fb 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -14,18 +14,34 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { type T = stable_mir::mir::Body; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + tables.synthetic_unreachable_block = self.basic_blocks.len(); + + let mut smir_blocks: Vec<_> = self + .basic_blocks + .iter() + .map(|block| stable_mir::mir::BasicBlock { + terminator: block.terminator().stable(tables), + statements: block + .statements + .iter() + .map(|statement| statement.stable(tables)) + .collect(), + }) + .collect(); + + assert_eq!(tables.synthetic_unreachable_block, smir_blocks.len()); + if let Some(unreachable_span) = tables.unreachable_block_span.take() { + smir_blocks.push(stable_mir::mir::BasicBlock { + statements: Vec::new(), + terminator: stable_mir::mir::Terminator { + span: unreachable_span, + kind: stable_mir::mir::TerminatorKind::Unreachable, + }, + }); + } + stable_mir::mir::Body::new( - self.basic_blocks - .iter() - .map(|block| stable_mir::mir::BasicBlock { - terminator: block.terminator().stable(tables), - statements: block - .statements - .iter() - .map(|statement| statement.stable(tables)) - .collect(), - }) - .collect(), + smir_blocks, self.local_decls .iter() .map(|decl| stable_mir::mir::LocalDecl { @@ -602,7 +618,16 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { type T = stable_mir::mir::Terminator; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::mir::Terminator; - Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) } + let terminator = Terminator { + kind: self.kind.stable(tables), + span: self.source_info.span.stable(tables), + }; + if tables.unreachable_block_span.is_none() + && terminator.successors().contains(&tables.synthetic_unreachable_block) + { + tables.unreachable_block_span = Some(terminator.span); + } + terminator } } @@ -620,7 +645,10 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { let branches = targets.iter().map(|(val, target)| (val, target.as_usize())); stable_mir::mir::SwitchTargets::new( branches.collect(), - targets.otherwise().as_usize(), + match targets.otherwise() { + mir::SwitchAction::Goto(bb) => bb.as_usize(), + mir::SwitchAction::Unreachable => tables.synthetic_unreachable_block, + }, ) }, }, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c5d33f090a05b..0d6f96621d054 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -37,6 +37,8 @@ pub struct Tables<'tcx> { pub(crate) ty_consts: IndexMap, TyConstId>, pub(crate) mir_consts: IndexMap, MirConstId>, pub(crate) layouts: IndexMap, Layout>, + pub(crate) synthetic_unreachable_block: stable_mir::mir::BasicBlockIdx, + pub(crate) unreachable_block_span: Option, } impl<'tcx> Tables<'tcx> { 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 a1be927e1c04a..955ea956ab0ce 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 @@ -67,7 +67,7 @@ StorageLive(_6); _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + switchInt(move _7) -> [1: bb4, 0: bb6]; } bb4: { @@ -133,9 +133,5 @@ 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 87ab71feb2faa..b16a7f2f62c36 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 @@ -67,7 +67,7 @@ StorageLive(_6); _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + switchInt(move _7) -> [1: bb4, 0: bb6]; } bb4: { @@ -133,9 +133,5 @@ StorageDead(_6); return; } - - bb9: { - unreachable; - } } diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 56d4d50e967e2..91343d7634a8c 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -41,7 +41,7 @@ + StorageLive(_7); + _6 = copy (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); -+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; ++ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8]; } bb1: { @@ -101,10 +101,6 @@ + _1 = CoroutineState::::Complete(copy _5); + discriminant((*_6)) = 1; + goto -> bb2; -+ } -+ -+ bb9: { -+ unreachable; } } diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 751916a00f14d..f51ffd52035db 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -41,7 +41,7 @@ + StorageLive(_7); + _6 = copy (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}); + _7 = discriminant((*_6)); -+ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; ++ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10]; } bb1: { @@ -115,10 +115,6 @@ + _1 = CoroutineState::::Complete(copy _5); + discriminant((*_6)) = 1; + goto -> bb4; -+ } -+ -+ bb11: { -+ 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 28878736ed7cd..2ee02e66c3b4b 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 @@ -26,7 +26,7 @@ + StorageLive(_3); + StorageLive(_5); + _3 = discriminant(_2); -+ switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb2, 1: bb3]; } bb1: { 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 27b6bb6a5bb23..df5eb007874fb 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 @@ -26,7 +26,7 @@ + StorageLive(_3); + StorageLive(_5); + _3 = discriminant(_2); -+ switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb2, 1: bb3]; } bb1: { 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 66ab5e1b96228..83b130d342409 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 @@ -18,16 +18,16 @@ fn unwrap_unchecked(_1: Option) -> T { bb0: { StorageLive(_2); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb2, 1: bb1, otherwise: bb2]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { - _0 = copy ((_1 as Some).0: T); - StorageDead(_2); - return; + unreachable; } bb2: { - unreachable; + _0 = copy ((_1 as Some).0: T); + StorageDead(_2); + return; } } 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 66ab5e1b96228..83b130d342409 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 @@ -18,16 +18,16 @@ fn unwrap_unchecked(_1: Option) -> T { bb0: { StorageLive(_2); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb2, 1: bb1, otherwise: bb2]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { - _0 = copy ((_1 as Some).0: T); - StorageDead(_2); - return; + unreachable; } bb2: { - unreachable; + _0 = copy ((_1 as Some).0: T); + StorageDead(_2); + return; } } diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 5fee9a6733dd0..229cc60f87515 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -25,7 +25,7 @@ StorageLive(_3); StorageLive(_5); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; + switchInt(move _3) -> [0: bb2, 1: bb3]; } bb1: { 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 5876c55c52b94..9ea045508835f 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 @@ -26,7 +26,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(move _3) -> [1: bb2, otherwise: bb6]; } bb2: { @@ -38,7 +38,7 @@ fn num_to_digit(_1: char) -> u32 { bb3: { StorageLive(_5); _5 = discriminant(_4); - switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6]; + switchInt(move _5) -> [0: bb4, 1: bb5]; } bb4: { @@ -49,20 +49,16 @@ fn num_to_digit(_1: char) -> u32 { _0 = move ((_4 as Some).0: u32); StorageDead(_5); StorageDead(_4); - goto -> bb8; + goto -> bb7; } bb6: { - unreachable; - } - - bb7: { StorageDead(_3); _0 = const 0_u32; - goto -> bb8; + goto -> bb7; } - bb8: { + bb7: { return; } } 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 f1185353a43c8..e8ab60c2d6a64 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 @@ -26,7 +26,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(move _3) -> [1: bb2, otherwise: bb6]; } bb2: { @@ -38,7 +38,7 @@ fn num_to_digit(_1: char) -> u32 { bb3: { StorageLive(_5); _5 = discriminant(_4); - switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6]; + switchInt(move _5) -> [0: bb4, 1: bb5]; } bb4: { @@ -49,20 +49,16 @@ fn num_to_digit(_1: char) -> u32 { _0 = move ((_4 as Some).0: u32); StorageDead(_5); StorageDead(_4); - goto -> bb8; + goto -> bb7; } bb6: { - unreachable; - } - - bb7: { StorageDead(_3); _0 = const 0_u32; - goto -> bb8; + goto -> bb7; } - bb8: { + bb7: { return; } } diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index 79599f856115d..3ba9d82f0f7bd 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -50,7 +50,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb1]; + switchInt(move _10) -> [0: bb7, 1: bb6]; } bb1: { diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index 79599f856115d..3ba9d82f0f7bd 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -50,7 +50,7 @@ StorageLive(_11); StorageLive(_12); _10 = discriminant(_4); - switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb1]; + switchInt(move _10) -> [0: bb7, 1: bb6]; } bb1: { diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 743ee8e728bbe..46e240e6a099f 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -49,7 +49,7 @@ fn identity(x: Result) -> Result { // CHECK-LABEL: fn identity( // CHECK: bb0: { // CHECK: [[x:_.*]] = copy _1; - // CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb1]; + // CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6]; // CHECK: bb1: { // CHECK: unreachable; // CHECK: bb2: { diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir index 9f88e1961ec88..6db728f7c016d 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir @@ -31,7 +31,7 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { StorageLive(_3); StorageLive(_4); _2 = discriminant((*_1)); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { @@ -55,8 +55,4 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { StorageDead(_2); return; } - - bb4: { - 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 518fedffc1698..3f37fdd2765ce 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 @@ -13,7 +13,7 @@ fn ub_if_b(_1: Thing) -> Thing { bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb2]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 027c71dfaae46..bcee441524a74 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -48,20 +48,16 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _10) -> [0: bb1, 1: bb2]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2]; } bb1: { - unreachable; - } - - bb2: { _11 = option::unwrap_failed() -> unwind unreachable; } - bb3: { + bb2: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; StorageDead(_10); @@ -75,28 +71,28 @@ _7 = copy _9; StorageLive(_8); - _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb3, unwind unreachable]; + _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageDead(_8); StorageDead(_7); StorageLive(_12); StorageLive(_16); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + switchInt(move _12) -> [0: bb5, 1: bb4]; } - bb5: { + bb4: { StorageLive(_15); _16 = &_13; _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_16); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 88bd4628c297a..b2e5da0565bd5 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -37,9 +37,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; +- switchInt(move _10) -> [0: bb2, 1: bb3]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3]; } bb1: { @@ -55,14 +55,10 @@ } bb2: { - unreachable; - } - - bb3: { _11 = option::unwrap_failed() -> unwind continue; } - bb4: { + bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; StorageDead(_10); @@ -76,12 +72,12 @@ _7 = copy _9; StorageLive(_8); - _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue]; + _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind continue]; } - bb5: { + bb4: { StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index ebf305a6f1b12..af75c3a81af24 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -48,20 +48,16 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _10) -> [0: bb1, 1: bb2]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ switchInt(const 0_isize) -> [0: bb1, 1: bb2]; } bb1: { - unreachable; - } - - bb2: { _11 = option::unwrap_failed() -> unwind unreachable; } - bb3: { + bb2: { - _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::AlignmentEnum) }}; StorageDead(_10); @@ -75,28 +71,28 @@ _7 = copy _9; StorageLive(_8); - _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb3, unwind unreachable]; + _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb3, unwind unreachable]; } - bb4: { + bb3: { StorageDead(_8); StorageDead(_7); StorageLive(_12); StorageLive(_16); _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + switchInt(move _12) -> [0: bb5, 1: bb4]; } - bb5: { + bb4: { StorageLive(_15); _16 = &_13; _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; } - bb6: { + bb5: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); StorageDead(_16); StorageDead(_12); 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 0c52f1e058367..aa782a07b3ef2 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 @@ -37,9 +37,9 @@ + _2 = const Option::::None; StorageLive(_10); - _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; +- switchInt(move _10) -> [0: bb2, 1: bb3]; + _10 = const 0_isize; -+ switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ switchInt(const 0_isize) -> [0: bb2, 1: bb3]; } bb1: { @@ -55,14 +55,10 @@ } bb2: { - unreachable; - } - - bb3: { _11 = option::unwrap_failed() -> unwind continue; } - bb4: { + bb3: { - _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::AlignmentEnum) }}; StorageDead(_10); @@ -76,12 +72,12 @@ _7 = copy _9; StorageLive(_8); - _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; +- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue]; + _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind continue]; } - bb5: { + bb4: { StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 75e8cb1d8618c..bc347dd23a92f 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -43,14 +43,14 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () _6 = &mut (_4.0: impl Iterator); StorageLive(_7); _7 = &mut (_4.1: impl Fn(T) -> Option); - _8 = as Iterator>::find_map:: Option>(move _6, move _7) -> [return: bb3, unwind: bb9]; + _8 = as Iterator>::find_map:: Option>(move _6, move _7) -> [return: bb3, unwind: bb8]; } bb3: { StorageDead(_7); StorageDead(_6); _9 = discriminant(_8); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb8]; + switchInt(move _9) -> [0: bb4, 1: bb6]; } bb4: { @@ -65,7 +65,7 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () bb6: { _10 = move ((_8 as Some).0: U); - _11 = opaque::(move _10) -> [return: bb7, unwind: bb9]; + _11 = opaque::(move _10) -> [return: bb7, unwind: bb8]; } bb7: { @@ -73,15 +73,11 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () goto -> bb2; } - bb8: { - unreachable; + bb8 (cleanup): { + drop(_4) -> [return: bb9, unwind terminate(cleanup)]; } bb9 (cleanup): { - drop(_4) -> [return: bb10, unwind terminate(cleanup)]; - } - - bb10 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index 4977f39ccefe8..f26335d1ad5a7 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -54,7 +54,7 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { StorageLive(_7); StorageLive(_6); _6 = &mut (_4.0: impl Iterator); - _7 = as Iterator>::next(move _6) -> [return: bb3, unwind: bb10]; + _7 = as Iterator>::next(move _6) -> [return: bb3, unwind: bb9]; } bb3: { @@ -63,7 +63,7 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { StorageLive(_9); StorageLive(_10); _9 = discriminant(_7); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb9]; + switchInt(move _9) -> [0: bb4, 1: bb6]; } bb4: { @@ -85,7 +85,7 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { StorageLive(_12); StorageLive(_11); _11 = (copy _10,); - _12 = <&mut impl Fn(T) -> U as FnOnce<(T,)>>::call_once(move _8, move _11) -> [return: bb7, unwind: bb10]; + _12 = <&mut impl Fn(T) -> U as FnOnce<(T,)>>::call_once(move _8, move _11) -> [return: bb7, unwind: bb9]; } bb7: { @@ -97,7 +97,7 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { StorageDead(_7); StorageDead(_8); _14 = move ((_13 as Some).0: U); - _15 = opaque::(move _14) -> [return: bb8, unwind: bb10]; + _15 = opaque::(move _14) -> [return: bb8, unwind: bb9]; } bb8: { @@ -105,15 +105,11 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { goto -> bb2; } - bb9: { - unreachable; + bb9 (cleanup): { + drop(_4) -> [return: bb10, unwind terminate(cleanup)]; } bb10 (cleanup): { - drop(_4) -> [return: bb11, unwind terminate(cleanup)]; - } - - bb11 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir index e537dd6a28ef8..c7202ebd2d4e3 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir @@ -31,12 +31,12 @@ fn vec_move(_1: Vec) -> () { bb2: { StorageLive(_5); _4 = &mut _3; - _5 = as Iterator>::next(move _4) -> [return: bb3, unwind: bb9]; + _5 = as Iterator>::next(move _4) -> [return: bb3, unwind: bb8]; } bb3: { _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb6, otherwise: bb8]; + switchInt(move _6) -> [0: bb4, 1: bb6]; } bb4: { @@ -52,7 +52,7 @@ fn vec_move(_1: Vec) -> () { bb6: { _7 = move ((_5 as Some).0: impl Sized); - _8 = opaque::(move _7) -> [return: bb7, unwind: bb9]; + _8 = opaque::(move _7) -> [return: bb7, unwind: bb8]; } bb7: { @@ -60,15 +60,11 @@ fn vec_move(_1: Vec) -> () { goto -> bb2; } - bb8: { - unreachable; + bb8 (cleanup): { + drop(_3) -> [return: bb9, unwind terminate(cleanup)]; } bb9 (cleanup): { - drop(_3) -> [return: bb10, unwind terminate(cleanup)]; - } - - bb10 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir index 60c0b8afa5343..c872782b90882 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-abort.mir @@ -42,7 +42,7 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb2: { _8 = discriminant(_7); - switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; + switchInt(move _8) -> [0: bb3, 1: bb5]; } bb3: { @@ -70,8 +70,4 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { StorageDead(_7); goto -> bb1; } - - bb7: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir index 7145da58ce18c..3a584c14a7c86 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir @@ -37,12 +37,12 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb1: { StorageLive(_7); _6 = &mut _5; - _7 = as iter::range::RangeInclusiveIteratorImpl>::spec_next(move _6) -> [return: bb2, unwind: bb8]; + _7 = as iter::range::RangeInclusiveIteratorImpl>::spec_next(move _6) -> [return: bb2, unwind: bb7]; } bb2: { _8 = discriminant(_7); - switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; + switchInt(move _8) -> [0: bb3, 1: bb5]; } bb3: { @@ -61,7 +61,7 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { _10 = &_3; StorageLive(_11); _11 = (copy _9,); - _12 = >::call(move _10, move _11) -> [return: bb6, unwind: bb8]; + _12 = >::call(move _10, move _11) -> [return: bb6, unwind: bb7]; } bb6: { @@ -71,15 +71,11 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { goto -> bb1; } - bb7: { - unreachable; + bb7 (cleanup): { + drop(_3) -> [return: bb8, unwind terminate(cleanup)]; } bb8 (cleanup): { - drop(_3) -> [return: bb9, unwind terminate(cleanup)]; - } - - bb9 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir index cbfc58194cc1f..79b62f2f572fa 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir @@ -16,7 +16,7 @@ fn ezmap(_1: Option) -> Option { bb0: { StorageLive(_2); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { @@ -37,10 +37,6 @@ fn ezmap(_1: Option) -> Option { StorageDead(_2); return; } - - bb4: { - unreachable; - } } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index a3308cc5df196..c38d6fc57fafe 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -155,7 +155,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_16); StorageLive(_18); _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb11]; + switchInt(move _18) -> [0: bb6, 1: bb8]; } bb6: { @@ -204,8 +204,4 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_23); goto -> bb4; } - - bb11: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 2a837fabd4c24..6565d2f316881 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -119,12 +119,12 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb4: { StorageLive(_17); _16 = &mut _15; - _17 = > as Iterator>::next(move _16) -> [return: bb5, unwind: bb11]; + _17 = > as Iterator>::next(move _16) -> [return: bb5, unwind: bb10]; } bb5: { _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _18) -> [0: bb6, 1: bb8]; } bb6: { @@ -144,7 +144,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _21 = &_2; StorageLive(_22); _22 = (copy _19, copy _20); - _23 = >::call(move _21, move _22) -> [return: bb9, unwind: bb11]; + _23 = >::call(move _21, move _22) -> [return: bb9, unwind: bb10]; } bb9: { @@ -154,15 +154,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { goto -> bb4; } - bb10: { - unreachable; + bb10 (cleanup): { + drop(_2) -> [return: bb11, unwind terminate(cleanup)]; } bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; - } - - bb12 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 063045caebb5c..f2ea31e7d76bb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -114,7 +114,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _17) -> [0: bb6, 1: bb8]; } bb6: { @@ -142,8 +142,4 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_16); goto -> bb4; } - - bb10: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index d401ed8fcf3ca..6b939ab7cb677 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -109,12 +109,12 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb4: { StorageLive(_16); _15 = &mut _14; - _16 = as Iterator>::next(move _15) -> [return: bb5, unwind: bb11]; + _16 = as Iterator>::next(move _15) -> [return: bb5, unwind: bb10]; } bb5: { _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _17) -> [0: bb6, 1: bb8]; } bb6: { @@ -133,7 +133,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _19 = &_2; StorageLive(_20); _20 = (copy _18,); - _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb11]; + _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb10]; } bb9: { @@ -143,15 +143,11 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { goto -> bb4; } - bb10: { - unreachable; + bb10 (cleanup): { + drop(_2) -> [return: bb11, unwind terminate(cleanup)]; } bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; - } - - bb12 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index deb12c4f1c22f..142d0b9f23608 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -126,7 +126,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { StorageDead(_16); _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _18) -> [0: bb6, 1: bb8]; } bb6: { @@ -154,8 +154,4 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_17); goto -> bb4; } - - bb10: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index acd5323eb7acd..39d15f75ff33b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -120,13 +120,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_17); StorageLive(_16); _16 = &mut (_15.0: std::slice::Iter<'_, T>); - _17 = as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind: bb11]; + _17 = as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind: bb10]; } bb5: { StorageDead(_16); _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + switchInt(move _18) -> [0: bb6, 1: bb8]; } bb6: { @@ -145,7 +145,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _20 = &_2; StorageLive(_21); _21 = (copy _19,); - _22 = >::call(move _20, move _21) -> [return: bb9, unwind: bb11]; + _22 = >::call(move _20, move _21) -> [return: bb9, unwind: bb10]; } bb9: { @@ -155,15 +155,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { goto -> bb4; } - bb10: { - unreachable; + bb10 (cleanup): { + drop(_2) -> [return: bb11, unwind terminate(cleanup)]; } bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; - } - - bb12 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir index baa01e28a9410..59fcdcb92ffad 100644 --- a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir @@ -25,7 +25,7 @@ fn new(_1: Result) -> Result { bb0: { StorageLive(_4); _2 = discriminant(_1); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { @@ -49,8 +49,4 @@ fn new(_1: Result) -> Result { bb3: { return; } - - bb4: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir index ac485f485b1cc..e99275ccb3d7e 100644 --- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir @@ -15,7 +15,7 @@ fn old(_1: Result) -> Result { bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; + switchInt(move _2) -> [0: bb1, 1: bb2]; } bb1: { @@ -33,8 +33,4 @@ fn old(_1: Result) -> Result { bb3: { return; } - - bb4: { - unreachable; - } } diff --git a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff index ce9d812701a8f..4849a4dff74d0 100644 --- a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff @@ -42,21 +42,17 @@ StorageLive(_7); StorageLive(_8); _6 = discriminant(_1); - switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; + switchInt(move _6) -> [0: bb5, 1: bb4]; } bb1: { - unreachable; - } - - bb2: { _5 = copy ((_2 as Continue).0: i32); _0 = Result::::Ok(copy _5); StorageDead(_2); return; } - bb3: { + bb2: { _4 = copy ((_2 as Break).0: std::result::Result); _10 = copy ((_4 as Err).0: i32); _0 = Result::::Err(copy _10); @@ -64,37 +60,37 @@ return; } - bb4: { + bb3: { StorageDead(_8); StorageDead(_7); StorageDead(_6); _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ goto -> bb2; +- switchInt(move _3) -> [0: bb1, 1: bb2]; ++ goto -> bb1; } - bb5: { + bb4: { _8 = copy ((_1 as Err).0: i32); StorageLive(_9); _9 = Result::::Err(copy _8); _2 = ControlFlow::, i32>::Break(move _9); StorageDead(_9); -- goto -> bb4; -+ goto -> bb7; +- goto -> bb3; ++ goto -> bb6; } - bb6: { + bb5: { _7 = copy ((_1 as Ok).0: i32); _2 = ControlFlow::, i32>::Continue(copy _7); - goto -> bb4; + goto -> bb3; + } + -+ bb7: { ++ bb6: { + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + _3 = discriminant(_2); -+ goto -> bb3; ++ goto -> bb2; } } 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 c88c63e0c1334..0541782955f7e 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,50 @@ bb0: { StorageLive(_2); _3 = discriminant(_1); - switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb2, 1: bb1]; } bb1: { - unreachable; - } - - bb2: { _5 = copy ((_1 as Err).0: usize); _2 = ControlFlow::::Break(copy _5); -- goto -> bb4; -+ goto -> bb8; +- goto -> bb3; ++ goto -> bb7; } - bb3: { + bb2: { _4 = copy ((_1 as Ok).0: i32); _2 = ControlFlow::::Continue(copy _4); - goto -> bb4; + goto -> bb3; } - bb4: { + bb3: { _6 = discriminant(_2); -- switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; -+ goto -> bb6; +- switchInt(move _6) -> [0: bb5, 1: bb4]; ++ goto -> bb5; } - bb5: { + bb4: { StorageLive(_8); _8 = copy ((_2 as Break).0: usize); _0 = const Option::::None; StorageDead(_8); - goto -> bb7; + goto -> bb6; } - bb6: { + bb5: { _7 = copy ((_2 as Continue).0: i32); _0 = Option::::Some(copy _7); - goto -> bb7; + goto -> bb6; } - bb7: { + bb6: { StorageDead(_2); return; + } + -+ bb8: { ++ bb7: { + _6 = discriminant(_2); -+ goto -> bb5; ++ goto -> bb4; } }