Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: I expected to see this happen: compiled function correctly handles Instead, this happened: compiler generates code with infinite loop. See asm (from ): <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
It seems, that bug was introduced between 1.69 and 1.70:
I am not particularly well versed in miscompilations, but the IR we emit to LLVM looks fine. Investigating more later, but I suspect an LLVM update affects this.
reduced LLVM IR: optimizes to Needs + to reproduce. Looks like the tail call optimization pass writes into the argument, even thou it is at that point. Did not bisect, but this was probably introduced by the upgrade to LLVM 16: label A-llvm I-unsound
If anyone's interested in a Rust level test, it can be reduced a decent amount: looking at that LLVM IR it could probably be reduced more, but really at this point there's not a whole lot left to remove.
Yeah, it looks like tailcallelim introducing a write to a parameter is the culprit. Strangely, Alive2 is okay with writing to a argument, and only thinks it's UB if it's non-: This makes some sense semantically (since the hidden copy of the argument means modifications aren't visible to the caller), but seems to be in contradiction with the langref, which : Opened
Bisected to upgrade to LLVM16 Seems to also repro on the most recent LLVM17 try build from :
Bisected: Here are some possibly relevant discussions:
claim
label +T-compiler +I-compiler-nominated Nominating for compiler discussion, because is proposing the LLVM fix for backport to our 16 branch in , in hopes of getting this into 1.72-beta. We don't really have a policy mechanism for this since master has already moved to LLVM 17, but we could accept that LLVM 16 backport in our fork and then update the LLVM 16 submodule directly in beta. (That would also pull in .)
I think this backport was necessary. It may have led to other undetected end-to-end miscompilation. Something unexpected seems to have happened. Should we create a new rustc branch of llvm-project every time we create a beta branch?
label +regression-from-stable-to-stable
It doesn't come up often, but we always have the option of adding a branch if needed. I think this particular case is innocuous enough to allow, but I didn't want it to sneak in without notice.
Okay, I can reopen a new PR for the new branch if needed.
Thanks for nominating We during the compiler triage meeting today and think that accepting a beta-backport of would be best to mitigate this miscompilation. We would prefer not to take at the same time and would rather let that ride the normal release train if that's possible?
Since the master branch has been switched to LLVM 17. Possibly revert at branch rustc/16.0-2023-06-05 is also fine?
In a way, that PR's backport got orphaned because its version of the submodule was derailed from the release train, replaced by our LLVM 17 update. But the original change it wanted is part of 17, so it will ride the train that way. Yes, I think that sounds fine. Please go ahead and add that revert to rust-lang/llvm-project, noting these reasons in the revert commit message. When we apply the submodule update to beta, it should ideally come with a rust codegen test, and we'll also want that test to land on master when LLVM 17 is fixed. (And don't close this issue until then!)
This patch has been backported to LLVM 17. I will pick the test from
Awesome, thank you both and
72-beta's LLVM 16 was fixed in , so I'm moving the milestone to 1.73 until we update and test LLVM 17.

Discussion:
<del> Subproject commit 7c612e1732f3976fcfe29526ad796cbb6174b829 </del> <ins> Subproject commit 1833c2be108aefcb5d25f6280cf9763b1feb8005 </ins>

<ins> // compile-flags: -O // min-llvm-version: 17 // only-x86_64-unknown-linux-gnu // We want to check that this function does not mis-optimize to loop jumping. #![crate_type = "lib"] #[repr(C)] pub enum Expr { Sum, // must have more than usize data Sub(usize, u8), } #[no_mangle] pub extern "C" fn issue_114312(expr: Expr) { // CHECK-LABEL: @issue_114312( // CHECK-NOT: readonly // CHECK-SAME: byval // CHECK-NEXT: start: // CHECK-NEXT: ret void match expr { Expr::Sum => {} Expr::Sub(_, _) => issue_114312(Expr::Sum), } } </ins>

<ins> // run-pass // This test used to be miscompiled by LLVM 17. #![allow(dead_code)] enum Pass { Opaque { clear_color: [f32; 4], with_depth_pre_pass: bool, }, Transparent, } enum LoadOp { Clear, Load, } #[inline(never)] fn check(x: Option<LoadOp>) { assert!(x.is_none()); } #[inline(never)] fn test(mode: Pass) { check(match mode { Pass::Opaque { with_depth_pre_pass: true, .. } | Pass::Transparent => None, _ => Some(LoadOp::Clear), }); } fn main() { println!("Hello, world!"); test(Pass::Transparent); } </ins>