From 41796ecf1c75fc00119097b4545939f21979e01a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 29 Apr 2026 21:54:15 +0200 Subject: [PATCH] add `c_variadic_experimental_arch` feature --- compiler/rustc_abi/src/extern_abi.rs | 1 + .../rustc_ast_passes/src/ast_validation.rs | 23 ++++++--- compiler/rustc_codegen_llvm/src/va_arg.rs | 10 +++- compiler/rustc_feature/src/unstable.rs | 3 ++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 49 ++++++++++++++----- ...te-c_variadic_experimental_arch.avr.stderr | 23 +++++++++ ...c_variadic_experimental_arch.custom.stderr | 14 ++++++ ...e-c_variadic_experimental_arch.m68k.stderr | 23 +++++++++ ...c_variadic_experimental_arch.msp430.stderr | 23 +++++++++ ...variadic_experimental_arch.riscv32e.stderr | 23 +++++++++ ...ature-gate-c_variadic_experimental_arch.rs | 45 +++++++++++++++++ ...-c_variadic_experimental_arch.sparc.stderr | 23 +++++++++ 13 files changed, 242 insertions(+), 19 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 95ba2ee3b78f8..0a7519625efb6 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -259,6 +259,7 @@ impl StableOrd for ExternAbi { rustc_error_messages::into_diag_arg_using_display!(ExternAbi); #[cfg(feature = "nightly")] +#[derive(Debug)] pub enum CVariadicStatus { NotSupported, Stable, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 770189d8c7999..cdcef59419f6f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -762,12 +762,23 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { - if !self.sess.target.supports_c_variadic_definitions() { - self.dcx().emit_err(errors::CVariadicNotSupported { - variadic_span: variadic_param.span, - target: &*self.sess.target.llvm_target, - }); - return; + match self.sess.target.supports_c_variadic_definitions() { + CVariadicStatus::NotSupported => { + self.dcx().emit_err(errors::CVariadicNotSupported { + variadic_span: variadic_param.span, + target: &*self.sess.target.llvm_target, + }); + return; + } + CVariadicStatus::Unstable { feature } if !self.features.enabled(feature) => { + let msg = + format!("C-variadic function definitions on this target are unstable"); + feature_err(&self.sess, feature, variadic_param.span, msg).emit(); + return; + } + CVariadicStatus::Unstable { .. } | CVariadicStatus::Stable => { + /* fall through */ + } } match sig.header.ext { diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index cfdd47b3a8c8c..09d3a5a3f040f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; +use rustc_abi::{Align, BackendRepr, CVariadicStatus, Endian, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; @@ -1038,6 +1038,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( assert!(!bx.layout_of(target_ty).is_zst()); let target = &bx.cx.tcx.sess.target; + let stability = target.supports_c_variadic_definitions(); + match target.arch { Arch::X86 => emit_ptr_va_arg( bx, @@ -1094,6 +1096,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( ForceRightAdjust::Yes, ), Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); // FIXME: clang manually adjusts the alignment for this ABI. It notes: // // > To be compatible with GCC's behaviors, we force arguments with @@ -1215,10 +1218,15 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( Arch::SpirV => bug!("spirv does not support c-variadic functions"), Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Clang uses the LLVM implementation for these architectures. bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } + Arch::Other(ref arch) => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Just to be safe we error out explicitly here, instead of crossing our fingers that // the default LLVM implementation has the correct behavior for this target. bug!("c-variadic functions are not currently implemented for custom target {arch}") diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3bb4bc863def2..13ef1da6a8060 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -393,6 +393,9 @@ declare_features! ( (unstable, bpf_target_feature, "1.54.0", Some(150247)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), + /// Allows defining c-variadic functions on targets where this feature has not yet + /// undergone sufficient testing for stabilization. + (unstable, c_variadic_experimental_arch, "CURRENT_RUSTC_VERSION", Some(155973)), /// Allows defining c-variadic naked functions with any extern ABI that is allowed /// on c-variadic foreign functions. (unstable, c_variadic_naked_functions, "1.93.0", Some(148767)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4cacdbd3408a5..64a1890726309 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -548,6 +548,7 @@ symbols! { c_str_literals, c_unwind, c_variadic, + c_variadic_experimental_arch, c_variadic_naked_functions, c_void, call, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 768e43146a0c1..9da621c300d8f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -47,7 +47,8 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{ - Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError, + Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, + TargetDataLayoutError, }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; @@ -2208,10 +2209,13 @@ impl Target { Ok(dl) } - pub fn supports_c_variadic_definitions(&self) -> bool { + pub fn supports_c_variadic_definitions(&self) -> CVariadicStatus { use Arch::*; match self.arch { + // These targets just inherently do not support c-variadic definitions. + Bpf | SpirV => CVariadicStatus::NotSupported, + // The c-variadic ABI for this target may change in the future, per this comment in // clang: // @@ -2219,19 +2223,40 @@ impl Target { // > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, // > `unsigned long long` and `double` to have 4-byte alignment. This // > behavior may be changed when RV32E/ILP32E is ratified. - RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false, - - // These targets just do not support c-variadic definitions. - Bpf | SpirV => false, + RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } // We don't know how c-variadics work for this target. Using the default LLVM - // fallback implementation may work, but just to be safe we disallow this. - Other(_) => false, + // fallback implementation probably works, but we can't guarantee it. + Other(_) => CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch }, - AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 - | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 - | X86_64 | Xtensa => true, + // These targets require more testing before we commit to c-variadic definitions + // being stable. + // + // To stabilize c-variadic functions for one of these targets, the following + // requirements must be met: + // + // - Check that `core::ffi::VaArgSafe` is (un)implemented for all the correct types. + // - Add an assembly test to `tests/assembly-llvm/c-variadic` that tests the assembly + // for all implementers of `VaArgSafe`. The generated assembly should either match + // `clang`, or we should understand and document why it deviates. + // - Ensure that `va_arg` is implemented in rustc. For stable targets we don't rely on + // the LLVM implementation, it has historically caused miscompilations. + // - The `tests/ui/c-variadic/roundtrip.rs` test must pass for the target. It may + // need slight modifications for embedded targets, that's fine. + // - Check that calling c-variadic functions defined in Rust can be called from C. + // For most targets `tests/run-make/c-link-to-rust-va-list-fn` can be used here. + // For no_std targets a manual setup may be needed. + Sparc | Avr | M68k | Msp430 => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } + + AArch64 | AmdGpu | Arm | Arm64EC | CSky | Hexagon | LoongArch32 | LoongArch64 + | Mips | Mips32r6 | Mips64 | Mips64r6 | Nvptx64 | PowerPC | PowerPC64 | RiscV32 + | RiscV64 | S390x | Sparc64 | Wasm32 | Wasm64 | X86 | X86_64 | Xtensa => { + CVariadicStatus::Stable + } } } } diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr new file mode 100644 index 0000000000000..fd9d7777a3886 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr @@ -0,0 +1,14 @@ +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:26:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:30:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs new file mode 100644 index 0000000000000..98b5f063d5844 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs @@ -0,0 +1,45 @@ +//@ add-minicore +//@ ignore-backends: gcc +// +//@ revisions: riscv32e sparc avr m68k msp430 +// +//@[riscv32e] compile-flags: --target riscv32e-unknown-none-elf +//@[riscv32e] needs-llvm-components: riscv +// +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +// +//@[avr] compile-flags: --target avr-none -Ctarget-cpu=atmega328p +//@[avr] needs-llvm-components: avr +// +//@[m68k] compile-flags: --target m68k-unknown-none-elf -Ctarget-cpu=M68020 +//@[m68k] needs-llvm-components: m68k +// +//@[msp430] compile-flags: --target msp430-none-elf -Ctarget-cpu=msp430 +//@[msp430] needs-llvm-components: msp430 +#![feature(no_core, lang_items, rustc_attrs, c_variadic)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(transparent)] +struct VaListInner { + ptr: *const c_void, +} + +#[repr(transparent)] +#[lang = "va_list"] +pub struct VaList<'a> { + inner: VaListInner, + _marker: PhantomData<&'a mut ()>, +} + +pub unsafe extern "C" fn test(_: i32, ap: ...) {} +//~^ ERROR C-variadic function definitions on this target are unstable + +trait Trait { + unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + //~^ ERROR C-variadic function definitions on this target are unstable +} diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`.