Change:
Running this code in release mode fails: : : When run with : This code passes under MIRI, so this is not the result of UB. Edit: this turned out to be because we had set in our build. We managed to bisect this in-tree down to , which updated the LLVM submodule to 17.0.0. That, along with the nature of the bug, gives us confidence that this is likely a miscompile when using the flag. This reproduces with the latest nightly: as well as the nightly immediately after the LLVM upgrade: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
You may already know this, but: Unless you set all the "also warn on..." flags on at once, the Rust MIR interpreter allowing something to pass should only be taken as a probabilistic statement on UB. It defaults to conservative. There are several undecided points of the Rust operational model that may become explicitly UB but are not necessarily flagged as such by miri, and even though "Rust hasn't defined it as formally always-UB" means "rustc should not be attempting to suggest LLVM optimizes based on this", we sometimes discover LLVM has an optimization that is technically valid according to the LLVM language's model if you interpret vague things in an... interesting way. We also sometimes discover LLVM has simply an invalid transformation, of course, which still seems more likely. "The compiler told you to reject the evidence of your eyes and ears. It was its final, most essential command."
Thank you, yes. I should clarify that I ran the crate through MIRI to ensure that this is not the result of UB in the Rust specification of this program. I did that because the repro currently pulls in two external crates which are not guaranteed to be UB-free. You are correct that this does not guarantee that UB doesn't sneak in during the translation from Rust semantics to LLVM semantics.
From a quick look, à la , bisects to the on the main function. I haven't tried reducing yet so I'm not sure if the following IR has been extracted correctly, but here goes: this doesn't reproduce the regression this does reproduce the regression The diff between the two is quite small, and the reproducer should reduce nicely. I'll try doing so tomorrow if no one gets to it before then. (cc in the meantime) update: nothing substantial on the reduction yet , and I've asked the LLVM WG for help in .
Thanks for the help, I have reproduced the erroneous pass ( is very helpful!). I threw together a script that compiles a .ll file, runs it to verify it does not assert, then runs the optimization pass, recompiles, and runs to verify it does assert. I have that plugged into and am letting that run for a while to see if it can minimize the reproduction.
I'd love to take a look at the script: I had hoped to do exactly that, but had issues and went the other route of minimizing from the rust side (starting with , but after doing that I wondered if I'd also have to minimize and and asked the WG for help with building and running the repro for ).
Here's of the script I'm running with . I was able to grab the .ll from right before the bad pass (in ) and plug that into .
claim
Upstream issue: I shared my reduced method for this issue. Some interesting steps may be generic. we bisected to . I guess we assume one branch is unreachable. project disable LTO. change the code to to check the symbol dismissed. bisected to the IR before with opt16. also be removed. My guess is that JumpThreadingPass is just a failure and we need to continue to find the error. (Key!) pipeline with opt-16: to opt16 vs opt17 on the step ^^ PR coming soon (Going back to my parent's home later, so the PR will be tomorrow.). I also need some trade-off thoughts for the PR.
In case it's useful, I also completed a reduction: . The diff between them is pretty small and also shows a branch being optimized out: ! Reading through this a bit more closely, I think that may have been too aggressive. It looks like it removed the branch checking that the deserialized value equals two, which is not what I wanted. This reduction may just end up being garbage.
Sorry I got the wrong conclusion. The error should appear in JumpThreading. ‍
Maybe You could try on .
Unfortunately there are also still gaps between Miri and the , as explained in Miri's . However, to my knowledge Miri can detect all de-facto UB that is exploited by LLVM or MIR optimizations. So a difference between the behavior of Miri and the compiled program is always one of the result of non-determinism (different absolute allocation addresses, different thread scheduling, ...) a consequence of an integer-to-pointer cast (that's why Miri warns about them by default) a bug in Miri a bug in codegen The main caveat is that future Miri/rustc updates can lead to UB reports in previously UB-free programs, if Miri starts detecting more of the UB permitted by the spec.
I have reverse-engineered a minimal repro with no deps based on the miscompiled LLVM IR: And expresses between the two nightlies which bumped the LLVM version: I'm moving this into a compiler codegen test and will close this issue when it is checked in.

Discussion:
<ins> // compile-flags: -O -Ccodegen-units=1 #![crate_type = "lib"] #[repr(i64)] pub enum Boolean { False = 0, True = 1, } impl Clone for Boolean { fn clone(&self) -> Self { *self } } impl Copy for Boolean {} extern "C" { fn set_value(foo: *mut i64); fn bar(); } pub fn foo(x: bool) { let mut foo = core::mem::MaybeUninit::<i64>::uninit(); unsafe { set_value(foo.as_mut_ptr()); } if x { let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() }; if matches!(l1, Boolean::False) { unsafe { *foo.as_mut_ptr() = 0; } } } let l2 = unsafe { *foo.as_mut_ptr() }; if l2 == 2 { // CHECK: call void @bar unsafe { bar(); } } } </ins>