Repository: rust-lang/rust
Pull request: c-variadic: error when we can't guarantee that the backend does the right thing

<!-- homu-ignore:start -->
*[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152935)*
<!-- homu-ignore:end -->

tracking issue: https://github.com/rust-lang/rust/issues/44930
r? workingjubilee 

as discussed in [#t-lang > stabilizing &#96;c_variadic&#96;](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/stabilizing.20.60c_variadic.60/with/574691397), display an error when we can't guarantee that the codegen backend (only LLVM is supported at the moment) does the right thing.


Changed files:
filename: compiler/rustc_ast_passes/src/ast_validation.rs
patch: @@ -762,7 +762,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,

filename: compiler/rustc_codegen_llvm/src/va_arg.rs
patch: @@ -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}")
         }
     }
 }

filename: compiler/rustc_target/src/spec/mod.rs
patch: @@ -1952,24 +1952,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::*;
@@ -2214,6 +2196,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 == LlvmAbi::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 {