Skip to content

Commit fae8c6e

Browse files
authored
Rollup merge of #155974 - folkertdev:c-variadic-experimental-arch, r=joshtriplett
add `c_variadic_experimental_arch` feature tracking issue: #155973 Based on https://hackmd.io/pIbUgMQuQcGaibJcinOcEw#Stabilize-c-variadic-function-definitions-rust155697, we'll gate niche targets where we don't control the implementation of `va_arg`, the ABI is unclear, or in general where we're not confident stabilizing the implementation.
2 parents 0a05ddf + 41796ec commit fae8c6e

13 files changed

Lines changed: 242 additions & 19 deletions

compiler/rustc_abi/src/extern_abi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ impl StableOrd for ExternAbi {
261261
rustc_error_messages::into_diag_arg_using_display!(ExternAbi);
262262

263263
#[cfg(feature = "nightly")]
264+
#[derive(Debug)]
264265
pub enum CVariadicStatus {
265266
NotSupported,
266267
Stable,

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -762,12 +762,23 @@ impl<'a> AstValidator<'a> {
762762
match fn_ctxt {
763763
FnCtxt::Foreign => return,
764764
FnCtxt::Free | FnCtxt::Assoc(_) => {
765-
if !self.sess.target.supports_c_variadic_definitions() {
766-
self.dcx().emit_err(errors::CVariadicNotSupported {
767-
variadic_span: variadic_param.span,
768-
target: &*self.sess.target.llvm_target,
769-
});
770-
return;
765+
match self.sess.target.supports_c_variadic_definitions() {
766+
CVariadicStatus::NotSupported => {
767+
self.dcx().emit_err(errors::CVariadicNotSupported {
768+
variadic_span: variadic_param.span,
769+
target: &*self.sess.target.llvm_target,
770+
});
771+
return;
772+
}
773+
CVariadicStatus::Unstable { feature } if !self.features.enabled(feature) => {
774+
let msg =
775+
format!("C-variadic function definitions on this target are unstable");
776+
feature_err(&self.sess, feature, variadic_param.span, msg).emit();
777+
return;
778+
}
779+
CVariadicStatus::Unstable { .. } | CVariadicStatus::Stable => {
780+
/* fall through */
781+
}
771782
}
772783

773784
match sig.header.ext {

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size};
1+
use rustc_abi::{Align, BackendRepr, CVariadicStatus, Endian, HasDataLayout, Primitive, Size};
22
use rustc_codegen_ssa::MemFlags;
33
use rustc_codegen_ssa::common::IntPredicate;
44
use rustc_codegen_ssa::mir::operand::OperandRef;
@@ -1038,6 +1038,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10381038
assert!(!bx.layout_of(target_ty).is_zst());
10391039

10401040
let target = &bx.cx.tcx.sess.target;
1041+
let stability = target.supports_c_variadic_definitions();
1042+
10411043
match target.arch {
10421044
Arch::X86 => emit_ptr_va_arg(
10431045
bx,
@@ -1094,6 +1096,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10941096
ForceRightAdjust::Yes,
10951097
),
10961098
Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => {
1099+
std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
10971100
// FIXME: clang manually adjusts the alignment for this ABI. It notes:
10981101
//
10991102
// > To be compatible with GCC's behaviors, we force arguments with
@@ -1215,10 +1218,15 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
12151218
Arch::SpirV => bug!("spirv does not support c-variadic functions"),
12161219

12171220
Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => {
1221+
std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1222+
12181223
// Clang uses the LLVM implementation for these architectures.
12191224
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
12201225
}
1226+
12211227
Arch::Other(ref arch) => {
1228+
std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1229+
12221230
// Just to be safe we error out explicitly here, instead of crossing our fingers that
12231231
// the default LLVM implementation has the correct behavior for this target.
12241232
bug!("c-variadic functions are not currently implemented for custom target {arch}")

compiler/rustc_feature/src/unstable.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,9 @@ declare_features! (
420420
(unstable, bpf_target_feature, "1.54.0", Some(150247)),
421421
/// Allows using C-variadics.
422422
(unstable, c_variadic, "1.34.0", Some(44930)),
423+
/// Allows defining c-variadic functions on targets where this feature has not yet
424+
/// undergone sufficient testing for stabilization.
425+
(unstable, c_variadic_experimental_arch, "CURRENT_RUSTC_VERSION", Some(155973)),
423426
/// Allows defining c-variadic naked functions with any extern ABI that is allowed
424427
/// on c-variadic foreign functions.
425428
(unstable, c_variadic_naked_functions, "1.93.0", Some(148767)),

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ symbols! {
548548
c_str_literals,
549549
c_unwind,
550550
c_variadic,
551+
c_variadic_experimental_arch,
551552
c_variadic_naked_functions,
552553
c_void,
553554
call,

compiler/rustc_target/src/spec/mod.rs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ use std::str::FromStr;
4747
use std::{fmt, io};
4848

4949
use rustc_abi::{
50-
Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError,
50+
Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout,
51+
TargetDataLayoutError,
5152
};
5253
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
5354
use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
@@ -2208,30 +2209,54 @@ impl Target {
22082209
Ok(dl)
22092210
}
22102211

2211-
pub fn supports_c_variadic_definitions(&self) -> bool {
2212+
pub fn supports_c_variadic_definitions(&self) -> CVariadicStatus {
22122213
use Arch::*;
22132214

22142215
match self.arch {
2216+
// These targets just inherently do not support c-variadic definitions.
2217+
Bpf | SpirV => CVariadicStatus::NotSupported,
2218+
22152219
// The c-variadic ABI for this target may change in the future, per this comment in
22162220
// clang:
22172221
//
22182222
// > To be compatible with GCC's behaviors, we force arguments with
22192223
// > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
22202224
// > `unsigned long long` and `double` to have 4-byte alignment. This
22212225
// > behavior may be changed when RV32E/ILP32E is ratified.
2222-
RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false,
2223-
2224-
// These targets just do not support c-variadic definitions.
2225-
Bpf | SpirV => false,
2226+
RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => {
2227+
CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch }
2228+
}
22262229

22272230
// We don't know how c-variadics work for this target. Using the default LLVM
2228-
// fallback implementation may work, but just to be safe we disallow this.
2229-
Other(_) => false,
2231+
// fallback implementation probably works, but we can't guarantee it.
2232+
Other(_) => CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch },
22302233

2231-
AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64
2232-
| M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC
2233-
| PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86
2234-
| X86_64 | Xtensa => true,
2234+
// These targets require more testing before we commit to c-variadic definitions
2235+
// being stable.
2236+
//
2237+
// To stabilize c-variadic functions for one of these targets, the following
2238+
// requirements must be met:
2239+
//
2240+
// - Check that `core::ffi::VaArgSafe` is (un)implemented for all the correct types.
2241+
// - Add an assembly test to `tests/assembly-llvm/c-variadic` that tests the assembly
2242+
// for all implementers of `VaArgSafe`. The generated assembly should either match
2243+
// `clang`, or we should understand and document why it deviates.
2244+
// - Ensure that `va_arg` is implemented in rustc. For stable targets we don't rely on
2245+
// the LLVM implementation, it has historically caused miscompilations.
2246+
// - The `tests/ui/c-variadic/roundtrip.rs` test must pass for the target. It may
2247+
// need slight modifications for embedded targets, that's fine.
2248+
// - Check that calling c-variadic functions defined in Rust can be called from C.
2249+
// For most targets `tests/run-make/c-link-to-rust-va-list-fn` can be used here.
2250+
// For no_std targets a manual setup may be needed.
2251+
Sparc | Avr | M68k | Msp430 => {
2252+
CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch }
2253+
}
2254+
2255+
AArch64 | AmdGpu | Arm | Arm64EC | CSky | Hexagon | LoongArch32 | LoongArch64
2256+
| Mips | Mips32r6 | Mips64 | Mips64r6 | Nvptx64 | PowerPC | PowerPC64 | RiscV32
2257+
| RiscV64 | S390x | Sparc64 | Wasm32 | Wasm64 | X86 | X86_64 | Xtensa => {
2258+
CVariadicStatus::Stable
2259+
}
22352260
}
22362261
}
22372262
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0658]: C-variadic function definitions on this target are unstable
2+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39
3+
|
4+
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
5+
| ^^^^^^^
6+
|
7+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
8+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: C-variadic function definitions on this target are unstable
12+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45
13+
|
14+
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
15+
| ^^^^^^^
16+
|
17+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
18+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: requires `va_list` lang_item
2+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:26:39
3+
|
4+
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
5+
| ^^^^^^^
6+
7+
error: requires `va_list` lang_item
8+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:30:45
9+
|
10+
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
11+
| ^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0658]: C-variadic function definitions on this target are unstable
2+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39
3+
|
4+
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
5+
| ^^^^^^^
6+
|
7+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
8+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: C-variadic function definitions on this target are unstable
12+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45
13+
|
14+
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
15+
| ^^^^^^^
16+
|
17+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
18+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0658]: C-variadic function definitions on this target are unstable
2+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39
3+
|
4+
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
5+
| ^^^^^^^
6+
|
7+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
8+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: C-variadic function definitions on this target are unstable
12+
--> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45
13+
|
14+
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
15+
| ^^^^^^^
16+
|
17+
= note: see issue #155973 <https://github.com/rust-lang/rust/issues/155973> for more information
18+
= help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)