From 3a02b357d36414dca2e388e761c41c0f611bd460 Mon Sep 17 00:00:00 2001 From: "Mark Z. Ding" Date: Wed, 29 Oct 2025 09:33:38 -0400 Subject: [PATCH 1/2] Add tests to demonstrate explicit tail call bug --- .../explicit-tail-calls/become-cast-return.rs | 22 +++++++++++++++++++ .../become-indirect-return.rs | 21 ++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/ui/explicit-tail-calls/become-cast-return.rs create mode 100644 tests/ui/explicit-tail-calls/become-indirect-return.rs diff --git a/tests/ui/explicit-tail-calls/become-cast-return.rs b/tests/ui/explicit-tail-calls/become-cast-return.rs new file mode 100644 index 0000000000000..3052886d7b8f8 --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-cast-return.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ ignore-backends: gcc +//@ known-bug: #148239 +//@ compile-flags: -Zno-codegen +#![expect(incomplete_features)] +#![feature(explicit_tail_calls)] + +#[inline(never)] +fn leaf(_: &Box) -> [u8; 1] { + [1] +} + +#[inline(never)] +fn dispatch(param: &Box) -> [u8; 1] { + become leaf(param) +} + +fn main() { + let data = Box::new(0); + let out = dispatch(&data); + assert_eq!(out, [1]); +} diff --git a/tests/ui/explicit-tail-calls/become-indirect-return.rs b/tests/ui/explicit-tail-calls/become-indirect-return.rs new file mode 100644 index 0000000000000..c94683d15f40b --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-indirect-return.rs @@ -0,0 +1,21 @@ +//@ run-pass +//@ ignore-backends: gcc +//@ known-bug: #148239 +#![expect(incomplete_features)] +#![feature(explicit_tail_calls)] + +#[inline(never)] +fn op_dummy(_param: &Box) -> [u8; 24] { + [1; 24] +} + +#[inline(never)] +fn dispatch(param: &Box) -> [u8; 24] { + become op_dummy(param) +} + +fn main() { + let param = Box::new(0); + let result = dispatch(¶m); + assert_ne!(result, [1; 24]); // the data is not right! +} From 52959a85cca72bdacaae9793005ff7cc7af43762 Mon Sep 17 00:00:00 2001 From: "Mark Z. Ding" Date: Wed, 29 Oct 2025 09:38:56 -0400 Subject: [PATCH 2/2] Fix musttail returns for cast/indirect ABIs --- compiler/rustc_codegen_llvm/src/builder.rs | 6 +----- compiler/rustc_codegen_ssa/src/mir/block.rs | 12 +++++++++++- tests/ui/explicit-tail-calls/become-cast-return.rs | 4 +--- .../ui/explicit-tail-calls/become-indirect-return.rs | 3 +-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index c082a82306848..49d38e05c8b06 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -16,7 +16,6 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -1458,10 +1457,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { match &fn_abi.ret.mode { PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(), - PassMode::Direct(_) | PassMode::Pair { .. } => self.ret(call), - mode @ PassMode::Cast { .. } => { - bug!("Encountered `PassMode::{mode:?}` during codegen") - } + PassMode::Direct(_) | PassMode::Pair { .. } | PassMode::Cast { .. } => self.ret(call), } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e2241a77d186c..0d1e27a34dc5b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1063,7 +1063,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); target.map(|target| (return_dest, target)) } - CallKind::Tail => None, + CallKind::Tail => { + if fn_abi.ret.is_indirect() { + match self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs) { + ReturnDest::Nothing => {} + _ => bug!( + "tail calls to functions with indirect returns cannot store into a destination" + ), + } + } + None + } }; // Split the rust-call tupled arguments off. diff --git a/tests/ui/explicit-tail-calls/become-cast-return.rs b/tests/ui/explicit-tail-calls/become-cast-return.rs index 3052886d7b8f8..212a0ddcbca15 100644 --- a/tests/ui/explicit-tail-calls/become-cast-return.rs +++ b/tests/ui/explicit-tail-calls/become-cast-return.rs @@ -1,7 +1,5 @@ -//@ check-pass +//@ run-pass //@ ignore-backends: gcc -//@ known-bug: #148239 -//@ compile-flags: -Zno-codegen #![expect(incomplete_features)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/explicit-tail-calls/become-indirect-return.rs b/tests/ui/explicit-tail-calls/become-indirect-return.rs index c94683d15f40b..7eec34f3b95c9 100644 --- a/tests/ui/explicit-tail-calls/become-indirect-return.rs +++ b/tests/ui/explicit-tail-calls/become-indirect-return.rs @@ -1,6 +1,5 @@ //@ run-pass //@ ignore-backends: gcc -//@ known-bug: #148239 #![expect(incomplete_features)] #![feature(explicit_tail_calls)] @@ -17,5 +16,5 @@ fn dispatch(param: &Box) -> [u8; 24] { fn main() { let param = Box::new(0); let result = dispatch(¶m); - assert_ne!(result, [1; 24]); // the data is not right! + assert_eq!(result, [1; 24]); }