diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index f03c7dd5b9d59..f1f734b855c14 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -80,6 +80,8 @@ ast_passes_c_variadic_must_be_unsafe = ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list +ast_passes_c_variadic_not_supported = the `{$target}` target does not support c-variadic functions + ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e57f8da26769b..42461bd5eb106 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -710,6 +710,14 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { + if !self.sess.target.arch.supports_c_variadic_definitions() { + self.dcx().emit_err(errors::CVariadicNotSupported { + variadic_span: variadic_param.span, + target: &*self.sess.target.llvm_target, + }); + return; + } + match sig.header.ext { Extern::Implicit(_) => { if !matches!(sig.header.safety, Safety::Unsafe(_)) { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c700ae517140c..bf9309614fe20 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -733,6 +733,14 @@ pub(crate) struct CoroutineAndCVariadic { pub variadic_span: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_not_supported)] +pub(crate) struct CVariadicNotSupported<'a> { + #[primary_span] + pub variadic_span: Span, + pub target: &'a str, +} + #[derive(Diagnostic)] #[diag(ast_passes_pattern_in_foreign, code = E0130)] // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2b1c7174fb15d..424026bdceab8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1925,6 +1925,24 @@ impl Arch { Self::Other(name) => rustc_span::Symbol::intern(name), } } + + 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 | PowerPC64LE | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 + | Wasm64 | X86 | X86_64 | Xtensa => true, + } + } } crate::target_spec_enum! {