Change:
The following program runs fine in Miri on mir-opt-levels 0-2, but in level 3 it errors: The error is: Looks like something changes the liveness ranges of locals and it does so incorrectly. Cc
Could you describe affected rustc version and reproduction steps?
The rustc version is commit , but most likely a nightly will also do it. To reproduce, run this in a Miri checkout:
The SimplifyComparisonIntegral introduces StorageDead for a local which didn't have any markers before. Currently this also makes the local dead on the entry to the function. Related to the issue about semantics of StorageLive without matching StorageDead (this would be the reverse).
The LLVM docs for their version of (which the Rust thing translates to) So just introducing a without also having appropriate is pretty clearly wrong, I would say.
That is the doc for , not . The doc for is:
oops sorry, yeah. We'd have to check the MIR here to see if it makes any sense at all; however, currently I think not just Miri but also our dataflow framework assumes that variables with any liveness annotations are initially dead.
Diff for this case before/after SimplifyComparisonIntegral: Note the placed in both successors of the , when there was no to begin with. cc -- along the lines of , you could leave the as a copy in this case for later optimisation passes to clean up. This is definitely a case I can cover for .
Does this analysis ensure that is not used any more afterwards? As in, would it be sufficient to add a in the start block? (I am not saying that that's a good fix, just trying to feel out the design space here.) I guess I am also surprised that an "integral comparison simplification" pass touches storage liveness.
That part is my fault. I incorrectly assumed that there's a storagedead before the switch. Maybe there is one in some situations, idk, if there is, we should probably just not do the optimization instead of rewriting the storage markers.
Should this be marked as I-unsound?
Assigning as discussed as part of the . modify labels: +P-medium -I-prioritize
Error: Label P-medium can only be set by Rust team members Please let know if you're having trouble with this bot.

Discussion:
_ => unreachable!(), } <del> let terminator = bb.terminator_mut(); // add StorageDead for the place switched on at the top of each target for bb_idx in new_targets.iter() { storage_deads_to_insert.push(( *bb_idx, Statement { source_info: terminator.source_info, kind: StatementKind::StorageDead(opt.to_switch_on.local), }, )); } terminator.kind = TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), switch_ty: opt.branch_value_ty, values: vec![new_value].into(), targets: new_targets, }; </del> // delete comparison statement if it the value being switched on was moved, which means it can not be user later on if opt.can_remove_bin_op_stmt { bb.statements[opt.bin_op_stmt_idx].make_nop();

} } <ins> let terminator = bb.terminator(); </ins> // remove StorageDead (if it exists) being used in the assign of the comparison for (stmt_idx, stmt) in bb.statements.iter().enumerate() { if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local) { continue; } <del> storage_deads_to_remove.push((stmt_idx, opt.bb_idx)) </del> <ins> storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); // if we have StorageDeads to remove then make sure to insert them at the top of each target for bb_idx in new_targets.iter() { storage_deads_to_insert.push(( *bb_idx, Statement { source_info: terminator.source_info, kind: StatementKind::StorageDead(opt.to_switch_on.local), }, )); } </ins> } <ins> let terminator = bb.terminator_mut(); terminator.kind = TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), switch_ty: opt.branch_value_ty, values: vec![new_value].into(), targets: new_targets, }; </ins> } for (idx, bb_idx) in storage_deads_to_remove {

<ins> // Check that we do not insert StorageDead at each target if StorageDead was never seen // EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff use std::fmt::Debug; fn test<T: Copy + Debug + PartialEq>(x: T) { let v: &[T] = &[x, x, x]; match v { [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], _ => unreachable!(), }; } fn main() { test(0u32); } </ins>

<ins> - // MIR for `test` before SimplifyComparisonIntegral + // MIR for `test` after SimplifyComparisonIntegral fn test(_1: T) -> () { debug x => _1;                       // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 let mut _0: ();                      // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 let _2: &[T];                        // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 let mut _3: &[T; 3];                 // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 let _4: &[T; 3];                     // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 let _5: [T; 3];                      // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 let mut _6: T;                       // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 let mut _7: T;                       // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 let mut _8: T;                       // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 let _9: [*const T; 3];               // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 let mut _10: usize;                  // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 let mut _11: usize;                  // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 let mut _12: bool;                   // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 let mut _16: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 let mut _17: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 let mut _18: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 let mut _19: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 let mut _20: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _21: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _22: !;                      // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { debug v => _2;                   // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 let _13: &T;                     // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 let _14: &T;                     // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 let _15: &T;                     // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 scope 2 { debug v1 => _13;             // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 debug v2 => _14;             // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 debug v3 => _15;             // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 } } bb0: { StorageLive(_2);                 // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 StorageLive(_3);                 // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 StorageLive(_4);                 // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 StorageLive(_5);                 // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 StorageLive(_6);                 // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 _6 = _1;                         // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 StorageLive(_7);                 // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 _7 = _1;                         // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 StorageLive(_8);                 // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 _8 = _1;                         // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 StorageDead(_8);                 // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 StorageDead(_7);                 // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 StorageDead(_6);                 // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 _4 = &_5;                        // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _3 = _4;                         // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 StorageDead(_3);                 // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 StorageDead(_4);                 // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 StorageLive(_9);                 // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 _10 = Len((*_2));                // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 _11 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -         _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -         switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +         nop;                             // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 +         switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 } bb1: { StorageLive(_22);                // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL begin_panic::<&str>(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar(<ZST>)) } // ty::Const // + ty: &str // + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) } } bb2: { StorageLive(_13);                // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 _13 = &(*_2)[0 of 3];            // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 StorageLive(_14);                // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 _14 = &(*_2)[1 of 3];            // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 StorageLive(_15);                // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 _15 = &(*_2)[2 of 3];            // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 StorageLive(_16);                // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 StorageLive(_17);                // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 _17 = &raw const (*_13);         // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 _16 = _17;                       // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 StorageLive(_18);                // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 StorageLive(_19);                // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 _19 = &raw const (*_14);         // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 _18 = _19;                       // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 StorageLive(_20);                // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 StorageLive(_21);                // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 _21 = &raw const (*_15);         // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 _20 = _21;                       // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 StorageDead(_21);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_20);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_19);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_18);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_17);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_16);                // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_15);                // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_14);                // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_13);                // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 StorageDead(_9);                 // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 _0 = const ();                   // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 StorageDead(_5);                 // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 StorageDead(_2);                 // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 return;                          // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 } } </ins>