From 2ff1413ed5a81b6014ce0e96091d7d9718929ce1 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Mon, 7 Sep 2026 19:20:02 +0700 Subject: [PATCH 1/3] Add test for invalid C variadic arguments --- tests/ui/lint/invalid_c_variadic_arguments.rs | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 tests/ui/lint/invalid_c_variadic_arguments.rs diff --git a/tests/ui/lint/invalid_c_variadic_arguments.rs b/tests/ui/lint/invalid_c_variadic_arguments.rs new file mode 100644 index 0000000000000..3cd06a15ce82b --- /dev/null +++ b/tests/ui/lint/invalid_c_variadic_arguments.rs @@ -0,0 +1,119 @@ +//@ check-pass + +use std::ffi::VaArgSafe; + +unsafe extern "C" fn variadic(_: ...) {} + +fn main() { + unsafe { + variadic(); + variadic(1_i32); + variadic(String::new()); + variadic(1_i32, String::new()); + variadic(String::new(), 1_i32); + variadic(String::new(), String::new()); + } +} + +fn generic(x: T) { + unsafe { + variadic(x); + } +} + +fn generic_with_bound(x: T) { + unsafe { + variadic(x); + } +} + +fn indirect() { + unsafe { + let f = variadic; + f(String::new()); + let f_ref = &f; + f_ref(String::new()); + let g = variadic as unsafe extern "C" fn(...); + g(String::new()); + let g_ref = &g; + g_ref(String::new()); + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyStruct { + x: i32, + y: i32, +} + +unsafe extern "C" fn variadic_after_struct(_: MyStruct, _: ...) {} + +fn simple_variadic_after_struct(my_struct: MyStruct) { + unsafe { + variadic_after_struct(my_struct); + variadic_after_struct(my_struct, 1_i32); + variadic_after_struct(my_struct, String::new()); + variadic_after_struct(my_struct, 1_i32, String::new()); + variadic_after_struct(my_struct, String::new(), 1_i32); + variadic_after_struct(my_struct, String::new(), String::new()); + } +} + +trait Trait { + type Assoc<'a>; +} + +// Unlikely case which our lint doesn't catch. +fn lifetime_dependent<'a, 'b, T: Trait: VaArgSafe>>(x: ::Assoc<'b>) { + unsafe { + variadic(x); + } +} + +// We don't lint (thin) references even though they currently don't implement VaArgSafe +fn references(tr: &T, tm: &mut T, ur: &U, um: &mut U) { + unsafe { + variadic(&String::new()); + variadic(&mut String::new()); + variadic(&String::new() as &dyn Send); + variadic(&mut String::new() as &mut dyn Send); + variadic(tr); + variadic(tm); + variadic(ur); + variadic(um); + } +} + +// Quirk with our current hard error: It allows infer vars as varargs +// even if they wouldn't be allowed when the concrete type is known. +fn infer_var() { + unsafe { + let mut x = 1; + variadic(x); + x = 1_u8; + } +} + +fn integer_float_fallback() { + unsafe { + variadic(1); + variadic(1.0); + } +} + +struct Thing; +impl Thing { + unsafe extern "C" fn variadic_method(&self, _: ...) {} +} + +fn method_call_syntax() { + unsafe { + Thing.variadic_method(); + Thing.variadic_method(1_i32); + Thing.variadic_method(String::new()); + Thing.variadic_method(1_i32, String::new()); + Thing.variadic_method(String::new(), 1_i32); + Thing.variadic_method(String::new(), String::new()); + } +} From 987b211bf1695a1b64841a08763a25c8e00cb47a Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Tue, 8 Sep 2026 21:03:56 +0700 Subject: [PATCH 2/3] Add FCW for invalid C variadic arguments --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 3 + compiler/rustc_lint/src/builtin.rs | 125 ++++++++- compiler/rustc_lint/src/diagnostics.rs | 7 + compiler/rustc_lint/src/lib.rs | 1 + .../tests/fail/c-variadic-ignored-argument.rs | 1 + .../ui/abi/mir/mir_codegen_calls_variadic.rs | 4 +- .../const-eval/c-variadic-ignored-argument.rs | 1 + tests/ui/lint/invalid_c_variadic_arguments.rs | 50 ++++ .../lint/invalid_c_variadic_arguments.stderr | 253 ++++++++++++++++++ 9 files changed, 442 insertions(+), 3 deletions(-) create mode 100644 tests/ui/lint/invalid_c_variadic_arguments.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ba44d1966d971..8a1be4680f765 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -492,6 +492,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure we've checked this expr at least once. let arg_ty = self.check_expr(arg); + // FIXME: Remove this redundant check once we turn the + // `invalid_c_variadic_arguments` FCW into a hard error. + // If the function is c-style variadic, we skipped a bunch of arguments // so we need to check those, and write out the types // Ideally this would be folded into the above, for uniform style diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a2112293df204..1aa3e6cc0721a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -48,8 +48,8 @@ use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::diagnostics::{ - BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations, - BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatterns, + BuiltinAnonymousParams, BuiltinCVariadicArgument, BuiltinConstNoMangle, BuiltinDerefNullptr, + BuiltinDoubleNegations, BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatterns, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, @@ -3179,3 +3179,124 @@ impl<'tcx> LateLintPass<'tcx> for InternalEqTraitMethodImpls { } } } + +// Once we turn this into a hard error, we should delete the redundant check from +// `rustc_hir_typeck::fn_ctxt::FnCtxt::check_argument_types`. +// Turning this into a hard error should consist of adding a trait obligation +// in the type-checking of function arguments. +declare_lint! { + /// The `invalid_c_variadic_arguments` lint detects when a value of + /// an unsupported type is passed as a C-variadic argument (varargs). + /// + /// ### Example + /// + /// ```rust + /// unsafe extern "C" fn variadic(_: ...) {} + /// + /// pub fn foo(x: T) { + /// unsafe { + /// variadic(x); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Only certain types are supported in C-variadic arguments (varargs). + /// In particular, only types that implement the `core::ffi::VaArgSafe` + /// trait are supported. + /// + /// Using unsupported types causes undefined behavior. However, the compiler + /// previously didn't consistently check to prevent this from happening in + /// all cases. + /// + /// Currently, this lint does not warn on references to `Sized` types, despite + /// the fact that they (unlike raw pointers) don't implement `VaArgSafe`. + /// This is because we might decide to officially support them in the future, + /// by making them implement `VaArgSafe`, and there is too much existing code + /// that passes references as varargs. + /// + /// If you encounter this lint in a generic context which will be instantiated + /// only with supported types, consider adding a trait bound such as + /// `T: VaArgSafe`. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #162483] for more details. + /// + /// [issue #162483]: https://github.com/rust-lang/rust/issues/162483 + pub INVALID_C_VARIADIC_ARGUMENTS, + Warn, + "arguments passed as C variadic arguments that don't implement `VaArgSafe`", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #162483), + }; +} + +declare_lint_pass!(InvalidCVariadicArguments => [INVALID_C_VARIADIC_ARGUMENTS]); + +impl<'tcx> LateLintPass<'tcx> for InvalidCVariadicArguments { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + let (fn_sig, args, is_method_syntax) = match expr.kind { + hir::ExprKind::Call(f, args) => { + let fn_ty = cx.typeck_results().expr_ty_adjusted(f); + if !matches!(fn_ty.kind(), ty::FnPtr(_, _) | ty::FnDef(_, _)) { + // The call expression is done via one of the Fn traits. + // Those don't support C variadics, so nothing to lint here. + return; + } + (fn_ty.fn_sig(cx.tcx), args, false) + } + hir::ExprKind::MethodCall(_, _, args, _) => { + // This can be `None` if the receiver has a error in type-checking. + // For example: `tests/ui/consts/const-eval/infinite_loop.rs` + let Some(method_def) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + else { + cx.tcx.dcx().span_delayed_bug(expr.span, "method should have a DefId"); + return; + }; + (cx.tcx.fn_sig(method_def).skip_binder(), args, true) + } + _ => { + return; + } + }; + + if !fn_sig.c_variadic() { + return; + } + let num_args = fn_sig.inputs().skip_binder().len(); + // num_args includes the method receiver + let arg_offset = if is_method_syntax { num_args.strict_sub(1) } else { num_args }; + let Some(va_arg_safe) = cx.tcx.lang_items().get(LangItem::VaArgSafe) else { + return; + }; + + for arg in &args[arg_offset..] { + let arg_ty = cx.typeck_results().expr_ty_adjusted(arg); + if cx + .tcx + .infer_ctxt() + .build(cx.typing_mode()) + .type_implements_trait(va_arg_safe, [arg_ty], cx.param_env) + .must_apply_modulo_regions() + { + continue; + } + // Thin references technically do not implement `VaArgSafe`. + // However, we might make them implement `VaArgSafe` later, + // so, do not lint such arguments. + if let ty::Ref(_, referent_ty, _) = arg_ty.kind() + && referent_ty.is_sized(cx.tcx, cx.typing_env()) + { + continue; + } + cx.emit_span_lint( + INVALID_C_VARIADIC_ARGUMENTS, + arg.span, + BuiltinCVariadicArgument { arg_ty }, + ); + } + } +} diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index a15eb4c569d03..f0e6739b77f03 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -3219,3 +3219,10 @@ pub(crate) enum RawBorrowViaReferenceSuggestion<'a> { #[help("consider using `&raw {$mutbl}` for a safer and more explicit raw pointer")] Spanless { mutbl: &'a str }, } + +#[derive(Diagnostic)] +#[diag("type `{$arg_ty}` does not implement `VaArgSafe`")] +#[note("values passed as C-variadic arguments must implement `core::ffi::VaArgSafe`")] +pub(crate) struct BuiltinCVariadicArgument<'tcx> { + pub arg_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a8f4f06aaa4f7..2c4ad57205a58 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -243,6 +243,7 @@ late_lint_methods!( InteriorMutableConsts: InteriorMutableConsts, InternalEqTraitMethodImpls: InternalEqTraitMethodImpls, InvalidAtomicOrdering: InvalidAtomicOrdering, + InvalidCVariadicArguments: InvalidCVariadicArguments, InvalidFromUtf8: InvalidFromUtf8, InvalidNoMangleItems: InvalidNoMangleItems, InvalidReferenceCasting: InvalidReferenceCasting, diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs index 9c369433d6f06..487f3e304ddb4 100644 --- a/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs @@ -1,3 +1,4 @@ +#![expect(invalid_c_variadic_arguments)] // While 1-ZST are currently ignored on most ABIs, we don't guarantee that, and it's UB to // rely on it. diff --git a/tests/ui/abi/mir/mir_codegen_calls_variadic.rs b/tests/ui/abi/mir/mir_codegen_calls_variadic.rs index 0c1a59b38d3eb..b0c830f4cde01 100644 --- a/tests/ui/abi/mir/mir_codegen_calls_variadic.rs +++ b/tests/ui/abi/mir/mir_codegen_calls_variadic.rs @@ -1,11 +1,13 @@ //@ run-pass +use std::ffi::VaArgSafe; + #[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn rust_interesting_average(_: i64, ...) -> f64; } -fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 { +fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 { unsafe { rust_interesting_average( 6, a, a as f64, b, b as f64, c, c as f64, d, d as f64, e, e as f64, f, g, diff --git a/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs b/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs index 506d6ad5fee23..90564ebc4246e 100644 --- a/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs +++ b/tests/ui/consts/const-eval/c-variadic-ignored-argument.rs @@ -3,6 +3,7 @@ #![feature(const_c_variadic)] #![feature(const_destruct)] #![crate_type = "lib"] +#![expect(invalid_c_variadic_arguments)] // Regression test for when a c-variadic argument is `PassMode::Ignore`. The caller won't pass the // argument, but the callee ABI does have the argument. Ensure that const-eval is able to handle diff --git a/tests/ui/lint/invalid_c_variadic_arguments.rs b/tests/ui/lint/invalid_c_variadic_arguments.rs index 3cd06a15ce82b..7308369291853 100644 --- a/tests/ui/lint/invalid_c_variadic_arguments.rs +++ b/tests/ui/lint/invalid_c_variadic_arguments.rs @@ -9,15 +9,27 @@ fn main() { variadic(); variadic(1_i32); variadic(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(1_i32, String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(String::new(), 1_i32); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(String::new(), String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out + //~| WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } fn generic(x: T) { unsafe { variadic(x); + //~^ WARN type `T` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } @@ -31,12 +43,20 @@ fn indirect() { unsafe { let f = variadic; f(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out let f_ref = &f; f_ref(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out let g = variadic as unsafe extern "C" fn(...); g(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out let g_ref = &g; g_ref(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } @@ -54,9 +74,19 @@ fn simple_variadic_after_struct(my_struct: MyStruct) { variadic_after_struct(my_struct); variadic_after_struct(my_struct, 1_i32); variadic_after_struct(my_struct, String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic_after_struct(my_struct, 1_i32, String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic_after_struct(my_struct, String::new(), 1_i32); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic_after_struct(my_struct, String::new(), String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out + //~| WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } @@ -77,11 +107,19 @@ fn references(tr: &T, tm: &mut T, ur: &U, um: &mut U) { variadic(&String::new()); variadic(&mut String::new()); variadic(&String::new() as &dyn Send); + //~^ WARN type `&dyn Send` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(&mut String::new() as &mut dyn Send); + //~^ WARN type `&mut dyn Send` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(tr); variadic(tm); variadic(ur); + //~^ WARN type `&U` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out variadic(um); + //~^ WARN type `&mut U` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } @@ -91,6 +129,8 @@ fn infer_var() { unsafe { let mut x = 1; variadic(x); + //~^ WARN type `u8` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out x = 1_u8; } } @@ -112,8 +152,18 @@ fn method_call_syntax() { Thing.variadic_method(); Thing.variadic_method(1_i32); Thing.variadic_method(String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out Thing.variadic_method(1_i32, String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out Thing.variadic_method(String::new(), 1_i32); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out Thing.variadic_method(String::new(), String::new()); + //~^ WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out + //~| WARN type `String` does not implement `VaArgSafe` + //~| WARN this was previously accepted by the compiler but is being phased out } } diff --git a/tests/ui/lint/invalid_c_variadic_arguments.stderr b/tests/ui/lint/invalid_c_variadic_arguments.stderr new file mode 100644 index 0000000000000..f8efd51d122e5 --- /dev/null +++ b/tests/ui/lint/invalid_c_variadic_arguments.stderr @@ -0,0 +1,253 @@ +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:11:18 + | +LL | variadic(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + = note: `#[warn(invalid_c_variadic_arguments)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:14:25 + | +LL | variadic(1_i32, String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:17:18 + | +LL | variadic(String::new(), 1_i32); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:20:18 + | +LL | variadic(String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:20:33 + | +LL | variadic(String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `T` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:30:18 + | +LL | variadic(x); + | ^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:45:11 + | +LL | f(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:49:15 + | +LL | f_ref(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:53:11 + | +LL | g(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:57:15 + | +LL | g_ref(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:76:42 + | +LL | variadic_after_struct(my_struct, String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:79:49 + | +LL | variadic_after_struct(my_struct, 1_i32, String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:82:42 + | +LL | variadic_after_struct(my_struct, String::new(), 1_i32); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:85:42 + | +LL | variadic_after_struct(my_struct, String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:85:57 + | +LL | variadic_after_struct(my_struct, String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `&dyn Send` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:109:18 + | +LL | variadic(&String::new() as &dyn Send); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `&mut dyn Send` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:112:18 + | +LL | variadic(&mut String::new() as &mut dyn Send); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `&U` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:117:18 + | +LL | variadic(ur); + | ^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `&mut U` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:120:18 + | +LL | variadic(um); + | ^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `u8` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:131:18 + | +LL | variadic(x); + | ^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:154:31 + | +LL | Thing.variadic_method(String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:157:38 + | +LL | Thing.variadic_method(1_i32, String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:160:31 + | +LL | Thing.variadic_method(String::new(), 1_i32); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:163:31 + | +LL | Thing.variadic_method(String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: type `String` does not implement `VaArgSafe` + --> $DIR/invalid_c_variadic_arguments.rs:163:46 + | +LL | Thing.variadic_method(String::new(), String::new()); + | ^^^^^^^^^^^^^ + | + = note: values passed as C-variadic arguments must implement `core::ffi::VaArgSafe` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #162483 + +warning: 25 warnings emitted + From 68f7b2f79468e20a34d4ff4454d2a5d313296399 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Wed, 9 Sep 2026 18:09:38 +0700 Subject: [PATCH 3/3] Hard error for crater if cfg is set --- compiler/rustc_lint/src/builtin.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 1aa3e6cc0721a..50bd1fef8b665 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3292,6 +3292,14 @@ impl<'tcx> LateLintPass<'tcx> for InvalidCVariadicArguments { { continue; } + // TODO Remove this before merging. This is for crater only. + #[allow(rustc::symbol_intern_string_literal)] + if cx.tcx.sess.config.contains(&(Symbol::intern("crater_hack"), None)) { + cx.tcx.dcx().span_err( + arg.span, + format!("CRATER ERROR: C-variadic argument with type `{}`.", arg_ty), + ); + } cx.emit_span_lint( INVALID_C_VARIADIC_ARGUMENTS, arg.span,