Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_abi/src/extern_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 17 additions & 6 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_codegen_llvm/src/va_arg.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}")
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ symbols! {
c_str_literals,
c_unwind,
c_variadic,
c_variadic_experimental_arch,
c_variadic_naked_functions,
c_void,
call,
Expand Down
49 changes: 37 additions & 12 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -2208,30 +2209,54 @@ 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:
//
// > To be compatible with GCC's behaviors, we force arguments with
// > 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
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
Loading