diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 0d42ccc1a73c9..cf643931717be 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1256,55 +1256,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } CallKind::Tail => { - match fn_abi.args[i].mode { - PassMode::Indirect { on_stack: false, .. } => { - let Some(tmp) = tail_call_temporaries[i].take() else { - span_bug!( - fn_span, - "missing temporary for indirect tail call argument #{i}" - ) - }; - - let local = self.mir.args_iter().nth(i).unwrap(); - - match &self.locals[local] { - LocalRef::Place(arg) => { - bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout); - op.val = Ref(arg.val); - } - LocalRef::Operand(arg) => { - let Ref(place_value) = arg.val else { - bug!("only `Ref` should use `PassMode::Indirect`"); - }; - bx.typed_place_copy( - place_value, - tmp.val, - fn_abi.args[i].layout, - ); - op.val = arg.val; - } - LocalRef::UnsizedPlace(_) => { - span_bug!(fn_span, "unsized types are not supported") - } - LocalRef::PendingOperand => { - span_bug!(fn_span, "argument local should not be pending") - } - }; - - bx.lifetime_end(tmp.val.llval, tmp.layout.size); - } - PassMode::Indirect { on_stack: true, .. } => { - // FIXME: some LLVM backends (notably x86) do not correctly pass byval - // arguments to tail calls (as of LLVM 21). See also: - // - // - https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841 - // - https://github.com/rust-lang/rust/issues/144855 + if let PassMode::Indirect { on_stack: false, .. } = fn_abi.args[i].mode { + let Some(tmp) = tail_call_temporaries[i].take() else { span_bug!( fn_span, - "arguments using PassMode::Indirect {{ on_stack: true, .. }} are currently not supported for tail calls" + "missing temporary for indirect tail call argument #{i}" ) - } - _ => (), + }; + + let local = self.mir.args_iter().nth(i).unwrap(); + + match &self.locals[local] { + LocalRef::Place(arg) => { + bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout); + op.val = Ref(arg.val); + } + LocalRef::Operand(arg) => { + let Ref(place_value) = arg.val else { + bug!("only `Ref` should use `PassMode::Indirect`"); + }; + bx.typed_place_copy(place_value, tmp.val, fn_abi.args[i].layout); + op.val = arg.val; + } + LocalRef::UnsizedPlace(_) => { + span_bug!(fn_span, "unsized types are not supported") + } + LocalRef::PendingOperand => { + span_bug!(fn_span, "argument local should not be pending") + } + }; + + bx.lifetime_end(tmp.val.llval, tmp.layout.size); } } } diff --git a/tests/ui/explicit-tail-calls/support/basic.rs b/tests/ui/explicit-tail-calls/support/basic.rs new file mode 100644 index 0000000000000..d46dd726c0bd1 --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/basic.rs @@ -0,0 +1,97 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: riscv +//@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +//@[riscv] needs-llvm-components: riscv +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[inline(never)] +fn simple1(x: u64) -> u64 { + x +} + +#[unsafe(no_mangle)] +fn simple2(x: u64) -> u64 { + become simple1(x); +} diff --git a/tests/ui/explicit-tail-calls/support/bystack.rs b/tests/ui/explicit-tail-calls/support/bystack.rs new file mode 100644 index 0000000000000..ad1e0827f9f05 --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/bystack.rs @@ -0,0 +1,108 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Riscv does not support byval in LLVM 22 (but wil in LLVM 23) +// +// //@ revisions: riscv +// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +// //@[riscv] needs-llvm-components: riscv +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +struct PassedByVal { + a: u64, + b: u64, + c: u64, + d: u64, +} + +#[inline(never)] +extern "C" fn callee(x: PassedByVal) -> PassedByVal { + x +} + +#[unsafe(no_mangle)] +extern "C" fn byval(x: PassedByVal) -> PassedByVal { + become callee(x); +} diff --git a/tests/ui/explicit-tail-calls/support/byval.rs b/tests/ui/explicit-tail-calls/support/byval.rs new file mode 100644 index 0000000000000..965c63c8688a8 --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/byval.rs @@ -0,0 +1,108 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Riscv does not support byval in LLVM 22 (but wil in LLVM 23) +// +// //@ revisions: riscv +// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +// //@[riscv] needs-llvm-components: riscv +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// The rust calling convention will pass this by-value. +struct PassedByVal { + a: u64, + b: u64, + c: u64, + d: u64, +} + +#[inline(never)] +fn callee(x: PassedByVal) -> PassedByVal { + x +} + +#[unsafe(no_mangle)] +fn byval(x: PassedByVal) -> PassedByVal { + become callee(x); +}