diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 2308502df0703..4b01b6b3f4793 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -761,7 +761,7 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { - if !self.sess.target.arch.supports_c_variadic_definitions() { + 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, diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 98d2c3f131b0e..58b4e7f93976f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1186,9 +1186,10 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( // 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(_) => { - // For custom targets, use the LLVM va_arg instruction as a fallback. - bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) + Arch::Other(ref arch) => { + // 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_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 77cc6dd1036c8..7ebb177cfd5fa 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1939,24 +1939,6 @@ impl Arch { } } - pub fn supports_c_variadic_definitions(&self) -> bool { - use Arch::*; - - match self { - // These targets just do not support c-variadic definitions. - Bpf | SpirV => false, - - // We don't know if the target supports c-variadic definitions, but we don't want - // to needlessly restrict custom target.json configurations. - Other(_) => true, - - 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, - } - } - /// Whether `#[rustc_scalable_vector]` is supported for a target architecture pub fn supports_scalable_vectors(&self) -> bool { use Arch::*; @@ -2170,6 +2152,33 @@ impl Target { Ok(dl) } + + pub fn supports_c_variadic_definitions(&self) -> bool { + use Arch::*; + + match self.arch { + // 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 == "ilp32e" => false, + + // These targets just do not support c-variadic definitions. + Bpf | SpirV => false, + + // 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, + + 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, + } + } } pub trait HasTargetSpec {