Change:
<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --I tried this code: I expected to see this happen: no branch instructions emitted, makes an assumption that is , so should be inlined and optimized as a panic. Instead, this happened: there is a discriminant check still emitted. <!-- Provide the most recent version this worked on, for example: It most recently worked on: --It most recently worked on: nightly-2023-03-26 <!-- Provide the version you are using that has the regression. --See godbolt: Regression occurred in (cc searched nightlies: from nightly-2023-03-01 to nightly-2023-04-01 regressed nightly: nightly-2023-03-27 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.6</summaryHost triple: aarch64-unknown-linux-gnu Reproduce with: </details<details</summary(if you want to test on replace with ) </details<details</summary</details originally noticed the problem and opened , then suggested that this is a compiler issue, then that this is a regression, then bisected and opened this issue.
The end of this regression window is over 2 weeks from now. Why? Godbolt usually has pretty old nightlies. If I add : you can see we have duplicate switch targets, which means that either this commit is broken or godbolt doesn't have it:
godbolt seems to have ?
Because I knew that reproduces the regression, and wanted to cut some time bisecting. For reference I can reproduce the same issue with . <details<summary+nightly-2023-04-19 --emit=mir</summary</details
To be clear, separate from this issue I believe that this MIR: is a bug. I do not know what impact resolving that would have on this issue. But the helper that combines switch targets was (notionally) supposed to prevent this.
Yeah, I'm pretty sure that is the root cause.
WG-prioritization assigning priority (). label -I-prioritize +P-medium

Discussion:
//! Performs various peephole optimizations. <ins> use crate::simplify::combine_duplicate_switch_targets; </ins> use crate::MirPass; use rustc_hir::Mutability; <del> use rustc_middle::mir::{ BinOp, Body, CastKind, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, UnOp, }; </del> <ins> use rustc_middle::mir::*; </ins> use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};

&mut block.terminator.as_mut().unwrap(), &mut block.statements, ); <del> ctx.combine_duplicate_switch_targets(&mut block.terminator.as_mut().unwrap()); </del> <ins> combine_duplicate_switch_targets(block.terminator.as_mut().unwrap()); </ins> } } }

terminator.kind = TerminatorKind::Goto { target: destination_block }; } <del> fn combine_duplicate_switch_targets(&self, terminator: &mut Terminator<'tcx>) { let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { return }; let otherwise = targets.otherwise(); if targets.iter().any(|t| t.1 == otherwise) { *targets = SwitchTargets::new( targets.iter().filter(|t| t.1 != otherwise), targets.otherwise(), ); } } </del> fn combine_intrinsic_assert( &self, terminator: &mut Terminator<'tcx>,

} } <ins> pub fn combine_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) { *targets = SwitchTargets::new( targets.iter().filter(|t| t.1 != otherwise), targets.otherwise(), ); } } } </ins> pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { struct OptApplier<'tcx> { tcx: TyCtxt<'tcx>,

} } <ins> combine_duplicate_switch_targets(terminator); </ins> self.super_terminator(terminator, location); } }

-                                          // + literal: Const { ty: unsafe fn(Option<T>) -> T {Option::<T>::unwrap_unchecked}, val: Value(<ZST>) } +         StorageLive(_3);                 // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 +         _4 = discriminant(_2);           // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL <del> +         switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb1]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL </del> <ins> +         switchInt(move _4) -> [1: bb2, otherwise: bb1]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL </ins> } bb1: {

<ins> // compile-flags: -Zmir-opt-level=2 -Zinline-mir // ignore-debug: standard library debug assertions add a panic that breaks this optimization #![crate_type = "lib"] pub enum Thing { A, B, } // EMIT_MIR instcombine_duplicate_switch_targets_e2e.ub_if_b.PreCodegen.after.mir pub unsafe fn ub_if_b(t: Thing) -> Thing { match t { Thing::A => t, Thing::B => std::hint::unreachable_unchecked(), } } </ins>

<ins> // MIR for `ub_if_b` after PreCodegen fn ub_if_b(_1: Thing) -> Thing { debug t => _1;                       // in scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+0:23: +0:24 let mut _0: Thing;                   // return place in scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+0:36: +0:41 let mut _2: isize;                   // in scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+2:9: +2:17 scope 1 (inlined unreachable_unchecked) { // at $DIR/instcombine_duplicate_switch_targets_e2e.rs:14:21: 14:55 scope 2 { scope 3 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } } bb0: { _2 = discriminant(_1);           // scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+1:11: +1:12 switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+1:5: +1:12 } bb1: { unreachable;                     // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } bb2: { _0 = move _1;                    // scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+2:21: +2:22 return;                          // scope 0 at $DIR/instcombine_duplicate_switch_targets_e2e.rs:+5:2: +5:2 } } </ins>