about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-09-08 19:27:07 +0200
committerFolkert de Vries <folkert@folkertdev.nl>2025-09-09 21:38:38 +0200
commit9196844f0d86242ee3d6a446fe681b6b2d2d674c (patch)
treefdd9e15c5928163e6bc9dc4884d5e76a9341f554
parent0c96200f268df10d4f3ac102f3161c67e5e67221 (diff)
downloadrust-9196844f0d86242ee3d6a446fe681b6b2d2d674c.tar.gz
rust-9196844f0d86242ee3d6a446fe681b6b2d2d674c.zip
c-variadic: reject functions with unsupported extern ABI
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast_passes/messages.ftl7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs7
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs9
-rw-r--r--tests/ui/c-variadic/issue-86053-1.stderr2
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs2
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr8
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.rs3
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.stderr76
9 files changed, 79 insertions, 40 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 915bae9e5f5..3e8fddd9954 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2325,6 +2325,11 @@ impl FnSig {
             }
         }
     }
+
+    /// The span of the header's extern, or where to insert it if empty.
+    pub fn extern_span(&self) -> Span {
+        self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi())
+    }
 }
 
 /// A constraint on an associated item.
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 1aa38a1beda..8dcf3e3aa38 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim
     .label = {ast_passes_auto_super_lifetime}
     .suggestion = remove the super traits or lifetime bounds
 
-ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-
 ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
     .cannot_have = cannot have a body
     .invalid = the invalid body
@@ -68,11 +66,16 @@ ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
 
 ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list
 
+ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
+    .label = `extern "{$abi}"` because of this
+    .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
+
 ast_passes_c_variadic_must_be_unsafe =
     functions with a C variable argument list must be unsafe
     .suggestion = add the `unsafe` keyword to this definition
 
 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_const_and_c_variadic = functions cannot be both `const` and C-variadic
     .const = `const` because of this
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 7b32778ddf0..a6ef89b553d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -698,7 +698,6 @@ impl<'a> AstValidator<'a> {
             FnCtxt::Foreign => return,
             FnCtxt::Free => match sig.header.ext {
                 Extern::Implicit(_) => {
-                    // Implicitly defaults to C.
                     if !matches!(sig.header.safety, Safety::Unsafe(_)) {
                         self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
                             span: variadic_param.span,
@@ -708,7 +707,11 @@ impl<'a> AstValidator<'a> {
                 }
                 Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
                     if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
-                        self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
+                        self.dcx().emit_err(errors::CVariadicBadExtern {
+                            span: variadic_param.span,
+                            abi: symbol_unescaped,
+                            extern_span: sig.extern_span(),
+                        });
                     }
 
                     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 946a22d2e75..ae805042c54 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -327,6 +327,7 @@ pub(crate) struct CVariadicAssociatedFunction {
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_c_variadic_no_extern)]
+#[help]
 pub(crate) struct CVariadicNoExtern {
     #[primary_span]
     pub span: Span,
@@ -348,10 +349,14 @@ pub(crate) struct CVariadicMustBeUnsafe {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_bad_c_variadic)]
-pub(crate) struct BadCVariadic {
+#[diag(ast_passes_c_variadic_bad_extern)]
+#[help]
+pub(crate) struct CVariadicBadExtern {
     #[primary_span]
     pub span: Span,
+    pub abi: Symbol,
+    #[label]
+    pub extern_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr
index eb08370b4f8..adbc04d3a65 100644
--- a/tests/ui/c-variadic/issue-86053-1.stderr
+++ b/tests/ui/c-variadic/issue-86053-1.stderr
@@ -51,6 +51,8 @@ error: `...` is not supported for non-extern functions
    |
 LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
    |                                    ^^^
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
 
 error[E0412]: cannot find type `F` in this scope
   --> $DIR/issue-86053-1.rs:11:48
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
index 4ebc2bbf761..eb6f4a32365 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
@@ -67,6 +67,6 @@ extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) ->
 }
 
 unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR `...` is not supported for `extern "cmse-nonsecure-entry"` functions
     //~| ERROR requires `va_list` lang_item
 }
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr
index 55921e764ba..8937def9428 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr
@@ -1,8 +1,12 @@
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions
   --> $DIR/generics.rs:69:60
    |
 LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
-   |                                                            ^^^^^^
+   |        -----------------------------                       ^^^^^^
+   |        |
+   |        `extern "cmse-nonsecure-entry"` because of this
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
 
 error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type
   --> $DIR/generics.rs:30:1
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
index ff491322efc..4db056f15a5 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -9,6 +9,9 @@ fn f1_1(x: isize, ...) {}
 fn f1_2(...) {}
 //~^ ERROR `...` is not supported for non-extern functions
 
+unsafe extern "Rust" fn f1_3(...) {}
+//~^ ERROR `...` is not supported for `extern "Rust"` functions
+
 extern "C" fn f2_1(x: isize, ...) {}
 //~^ ERROR functions with a C variable argument list must be unsafe
 
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 98f1d79f8f4..0cd78318de6 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -3,16 +3,30 @@ error: `...` is not supported for non-extern functions
    |
 LL | fn f1_1(x: isize, ...) {}
    |                   ^^^
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
 
 error: `...` is not supported for non-extern functions
   --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9
    |
 LL | fn f1_2(...) {}
    |         ^^^
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
 
-error: functions with a C variable argument list must be unsafe
+error: `...` is not supported for `extern "Rust"` functions
   --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
    |
+LL | unsafe extern "Rust" fn f1_3(...) {}
+   |        -------------         ^^^
+   |        |
+   |        `extern "Rust"` because of this
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
+
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:30
+   |
 LL | extern "C" fn f2_1(x: isize, ...) {}
    |                              ^^^
    |
@@ -22,7 +36,7 @@ LL | unsafe extern "C" fn f2_1(x: isize, ...) {}
    | ++++++
 
 error: functions with a C variable argument list must be unsafe
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
    |
 LL | extern "C" fn f2_2(...) {}
    |                    ^^^
@@ -33,13 +47,13 @@ LL | unsafe extern "C" fn f2_2(...) {}
    | ++++++
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:21:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
    |                    ^^^
 
 error: functions with a C variable argument list must be unsafe
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:30
    |
 LL | extern "C" fn f3_1(x: isize, ...) {}
    |                              ^^^
@@ -50,7 +64,7 @@ LL | unsafe extern "C" fn f3_1(x: isize, ...) {}
    | ++++++
 
 error: functions with a C variable argument list must be unsafe
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
    |
 LL | extern "C" fn f3_2(...) {}
    |                    ^^^
@@ -61,25 +75,25 @@ LL | unsafe extern "C" fn f3_2(...) {}
    | ++++++
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:20
    |
 LL | extern "C" fn f3_3(..., x: isize) {}
    |                    ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:33:1
    |
 LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    | ^^^^^ `const` because of this             ^^^ C-variadic because of this
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:1
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    | ^^^^^ `const` because of this      ^^^ C-variadic because of this
 
 error: functions with a C variable argument list must be unsafe
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^
@@ -90,19 +104,19 @@ LL | const unsafe extern "C" fn f4_2(x: isize, ...) {}
    |       ++++++
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:26
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:42:26
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
    |                          ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:42:1
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
    | ^^^^^ `const` because of this           ^^^ C-variadic because of this
 
 error: functions with a C variable argument list must be unsafe
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:42:41
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
    |                                         ^^^
@@ -113,49 +127,49 @@ LL | const unsafe extern "C" fn f4_3(..., x: isize, ...) {}
    |       ++++++
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:45:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:48:13
    |
 LL |     fn e_f2(..., x: isize);
    |             ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:52:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:55:23
    |
 LL |     fn i_f1(x: isize, ...) {}
    |                       ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:57:13
    |
 LL |     fn i_f2(...) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
    |             ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:28
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
    |                            ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
    |             ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
    |                            ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:5
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:65:5
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |     ^^^^^                   ^^^ C-variadic because of this
@@ -163,49 +177,49 @@ LL |     const fn i_f5(x: isize, ...) {}
    |     `const` because of this
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |                             ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:69:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:72:23
    |
 LL |     fn t_f1(x: isize, ...) {}
    |                       ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:74:23
    |
 LL |     fn t_f2(x: isize, ...);
    |                       ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:76:13
    |
 LL |     fn t_f3(...) {}
    |             ^^^
 
 error: associated functions cannot have a C variable argument list
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:78:13
    |
 LL |     fn t_f4(...);
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:80:13
    |
 LL |     fn t_f5(..., x: isize) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13
    |
 LL |     fn t_f6(..., x: isize);
    |             ^^^
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:43
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:33:43
    |
 LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    |                                           ^^^   - value is dropped here
@@ -213,7 +227,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    |                                           the destructor for this type cannot be evaluated in constant functions
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^   - value is dropped here
@@ -221,13 +235,13 @@ LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    the destructor for this type cannot be evaluated in constant functions
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |                             ^^^   - value is dropped here
    |                             |
    |                             the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 32 previous errors
+error: aborting due to 33 previous errors
 
 For more information about this error, try `rustc --explain E0493`.