Change:
let source_info = terminator.source_info; self.source_info = Some(source_info); self.super_terminator(terminator, location); <ins> // Do NOT early return in this function, it does some crucial fixup of the state at the end! </ins> match &mut terminator.kind { TerminatorKind::Assert { expected, ref mut cond, .. } => { if let Some(ref value) = self.eval_operand(&cond) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(*expected); <del> let Ok(value_const) = self.ecx.read_scalar(&value) else { // FIXME should be used use_ecx rather than a local match... but we have // quite a few of these read_scalar/read_immediate that need fixing. return }; if expected != value_const { // Poison all places this operand references so that further code // doesn't use the invalid value match cond { Operand::Move(ref place) | Operand::Copy(ref place) => { Self::remove_const(&mut self.ecx, place.local); </del> <ins> // FIXME should be used use_ecx rather than a local match... but we have // quite a few of these read_scalar/read_immediate that need fixing. if let Ok(value_const) = self.ecx.read_scalar(&value) { if expected != value_const { // Poison all places this operand references so that further code // doesn't use the invalid value match cond { Operand::Move(ref place) | Operand::Copy(ref place) => { Self::remove_const(&mut self.ecx, place.local); } Operand::Constant(_) => {} } } else { if self.should_const_prop(value) { *cond = self.operand_from_scalar( value_const, self.tcx.types.bool, source_info.span, ); </ins> } <del> Operand::Constant(_) => {} } } else { if self.should_const_prop(value) { *cond = self.operand_from_scalar( value_const, self.tcx.types.bool, source_info.span, ); </del> } } }

Discussion:
This code normally prints but when compiled with it produces instead. This was noticed because MIR optimization is enabled by default on the current nightly. This is the LLVM IR for the function with . Notice how the inputs to (used by ) are , which is incorrect.
prioritize
label regression-from-stable-to-nightly, I-unsound, A-mir-opt, T-compiler
Can someone execute the snippet with and upload the resulting directory somewhere? That should allow me to debug from my phone
I’ve made a gist originally, too, but it looks like you can’t see all the files there. (Afaict only 300 of the 401 files show up.) Here’s a repo Edit: One downside of a repo (compared to a gist) is that I might want to get rid of it eventually; AFAIK, this shouldn’t be needed for too long anyway though.
With an assertion instead of println: Individual builds from , point to cc
Ouch. That probably means the unsoundness was already possible before my PR (as explained there, the check it removes was ineffective), but is easier to trigger now. Cc something is wrong in ConstProp handling of shifts and/or casts and/or bit-ops. Is there a reproducer that does not need shifts and casts and a bitop? That would make the issue easier to track down.
FWIW it prints 0xfffffffff0000000 in Miri so the interpreter is probably fine, and it's probably a problem with the ConstProp pass itself.
The original code was much more complex. I minimized it as much as I could, but at this point even removing a useless will cause the bug to no longer trigger.
Yeah I quite appreciate that it does fit in a few lines now. :)
The is not needed, but indeed the bug needs to trigger. And inlining. Very strange. ConstProp code is super hard to read and full of subtle (usually barely documented) invariants, so... this could be an interesting one to track down.
The inlined code looks fine, but it has the basic blocks in a strange order, which might explain why the ConstProp bug only occurs if inlining happens first.

The code just before ConstProp has this One possible explanation would be if ConstProp iterated the basic blocks in order, then by the time it reaches , the last assignment to it saw is in bb0. There is another assignment to in bb3, which is executed before bb2, but maybe somehow my change made it so that this is not taken into account properly any more.
Turns out the actual problem was an early return that I which skipped more code than it should have -- fixed by
WG-prioritization assigning priority (). label -I-prioritize +P-critical