about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-09-10 20:29:10 +0200
committerGitHub <noreply@github.com>2025-09-10 20:29:10 +0200
commitbb45ea3accf536e0915991c5d9120bab8a87541e (patch)
tree301e5c15dcb2f6f64faf288a1fe2a1db1eaac790 /tests
parent86d39a06734cae9492d83498aac9bbdf3aa20508 (diff)
parent9196844f0d86242ee3d6a446fe681b6b2d2d674c (diff)
downloadrust-bb45ea3accf536e0915991c5d9120bab8a87541e.tar.gz
rust-bb45ea3accf536e0915991c5d9120bab8a87541e.zip
Rollup merge of #146342 - folkertdev:c-variadic-errors-take-3, r=workingjubilee
Improve C-variadic error messages: part 2

tracking issue: https://github.com/rust-lang/rust/issues/44930

a reimplementation of https://github.com/rust-lang/rust/pull/143546 that builds on https://github.com/rust-lang/rust/pull/146165.

This PR

- disallows coroutines (e.g. `async fn`) from having a `...` argument
- disallows associated functions (both in traits and standard impl blocks) from having a `...` argument
- splits up a generic "ill-formed C-variadic function" into specific errors about using an incorrect ABI, not specifying an ABI, or missing the unsafe keyword

C-variadic coroutines probably don't make sense? C-variadic functions are for FFI purposes, combining that with async functions seems weird.

For associated functions, we're just cutting scope. It's probably fine, but it's probably better to explicitly allow it. So for now, at least give a more targeted error message.

Made to be reviewed commit-by-commit.

cc `@workingjubilee`
r? compiler
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/c-variadic/issue-86053-1.rs2
-rw-r--r--tests/ui/c-variadic/issue-86053-1.stderr4
-rw-r--r--tests/ui/c-variadic/not-async.rs7
-rw-r--r--tests/ui/c-variadic/not-async.stderr19
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs12
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr30
-rw-r--r--tests/ui/feature-gates/feature-gate-c_variadic.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-c_variadic.stderr12
-rw-r--r--tests/ui/inference/note-and-explain-ReVar-124973.rs3
-rw-r--r--tests/ui/inference/note-and-explain-ReVar-124973.stderr8
-rw-r--r--tests/ui/mir/issue-83499-input-output-iteration-ice.rs5
-rw-r--r--tests/ui/mir/issue-83499-input-output-iteration-ice.stderr20
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.rs37
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.stderr138
14 files changed, 190 insertions, 115 deletions
diff --git a/tests/ui/c-variadic/issue-86053-1.rs b/tests/ui/c-variadic/issue-86053-1.rs
index 537d0263adf..58dfee55cf8 100644
--- a/tests/ui/c-variadic/issue-86053-1.rs
+++ b/tests/ui/c-variadic/issue-86053-1.rs
@@ -13,6 +13,6 @@ fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
     //~| ERROR unexpected `self` parameter in function
     //~| ERROR unexpected `self` parameter in function
     //~| ERROR `...` must be the last argument of a C-variadic function
-    //~| 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 non-extern functions
     //~| ERROR cannot find type `F` in this scope
 }
diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr
index b58016b5a81..adbc04d3a65 100644
--- a/tests/ui/c-variadic/issue-86053-1.stderr
+++ b/tests/ui/c-variadic/issue-86053-1.stderr
@@ -46,11 +46,13 @@ error: `...` must be the last argument of a C-variadic function
 LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
    |            ^^^
 
-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 non-extern functions
   --> $DIR/issue-86053-1.rs:11:36
    |
 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/c-variadic/not-async.rs b/tests/ui/c-variadic/not-async.rs
new file mode 100644
index 00000000000..45a7e1f8972
--- /dev/null
+++ b/tests/ui/c-variadic/not-async.rs
@@ -0,0 +1,7 @@
+//@ edition: 2021
+#![feature(c_variadic)]
+#![crate_type = "lib"]
+
+async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
+//~^ ERROR functions cannot be both `async` and C-variadic
+//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
diff --git a/tests/ui/c-variadic/not-async.stderr b/tests/ui/c-variadic/not-async.stderr
new file mode 100644
index 00000000000..b8caf0d8bd8
--- /dev/null
+++ b/tests/ui/c-variadic/not-async.stderr
@@ -0,0 +1,19 @@
+error: functions cannot be both `async` and C-variadic
+  --> $DIR/not-async.rs:5:1
+   |
+LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
+   | ^^^^^ `async` because of this                        ^^^ C-variadic because of this
+
+error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
+  --> $DIR/not-async.rs:5:59
+   |
+LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
+   | --------------------------------------------------------- ^^
+   | |
+   | opaque type defined here
+   |
+   = note: hidden type `{async fn body of cannot_be_async()}` captures lifetime `'_`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
index ad4fca8252d..eb6f4a32365 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
@@ -53,9 +53,7 @@ extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait {
     x
 }
 
-extern "cmse-nonsecure-entry" fn static_trait_object(
-    x: &'static dyn Trait,
-) -> &'static dyn Trait {
+extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait {
     //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798]
     x
 }
@@ -63,14 +61,12 @@ extern "cmse-nonsecure-entry" fn static_trait_object(
 #[repr(transparent)]
 struct WrapperTransparent<'a>(&'a dyn Trait);
 
-extern "cmse-nonsecure-entry" fn wrapped_trait_object(
-    x: WrapperTransparent,
-) -> WrapperTransparent {
+extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent {
     //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798]
     x
 }
 
-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
+unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
+    //~^ 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 7aeb6969feb..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
-  --> $DIR/generics.rs:73:53
+error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions
+  --> $DIR/generics.rs:69:60
    |
-LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
-   |                                                     ^^^^^^
+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
@@ -50,28 +54,28 @@ LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait
    = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
 
 error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers
-  --> $DIR/generics.rs:58:6
+  --> $DIR/generics.rs:56:80
    |
-LL | ) -> &'static dyn Trait {
-   |      ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
+LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait {
+   |                                                                                ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
    |
    = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers
    = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
 
 error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers
-  --> $DIR/generics.rs:68:6
+  --> $DIR/generics.rs:64:81
    |
-LL | ) -> WrapperTransparent {
-   |      ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
+LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent {
+   |                                                                                 ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
    |
    = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers
    = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
 
 error: requires `va_list` lang_item
-  --> $DIR/generics.rs:73:53
+  --> $DIR/generics.rs:69:60
    |
-LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
-   |                                                     ^^^^^^
+LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
+   |                                                            ^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.rs b/tests/ui/feature-gates/feature-gate-c_variadic.rs
index 45c68842093..88d91dbd081 100644
--- a/tests/ui/feature-gates/feature-gate-c_variadic.rs
+++ b/tests/ui/feature-gates/feature-gate-c_variadic.rs
@@ -1,10 +1,10 @@
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
-pub unsafe extern "C" fn test(_: i32, ap: ...) { }
+pub unsafe extern "C" fn test(_: i32, ap: ...) {}
 //~^ ERROR C-variadic functions are unstable
 
 trait Trait {
-    unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
+    unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
     //~^ ERROR C-variadic functions are unstable
-    //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~| ERROR associated functions cannot have a C variable argument list
 }
diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.stderr b/tests/ui/feature-gates/feature-gate-c_variadic.stderr
index e30a2f1ede3..808aa20948d 100644
--- a/tests/ui/feature-gates/feature-gate-c_variadic.stderr
+++ b/tests/ui/feature-gates/feature-gate-c_variadic.stderr
@@ -1,14 +1,14 @@
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+error: associated functions cannot have a C variable argument list
   --> $DIR/feature-gate-c_variadic.rs:7:45
    |
-LL |     unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
+LL |     unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
    |                                             ^^^^^^^
 
 error[E0658]: C-variadic functions are unstable
   --> $DIR/feature-gate-c_variadic.rs:3:1
    |
-LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information
    = help: add `#![feature(c_variadic)]` to the crate attributes to enable
@@ -17,8 +17,8 @@ LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { }
 error[E0658]: C-variadic functions are unstable
   --> $DIR/feature-gate-c_variadic.rs:7:5
    |
-LL |     unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information
    = help: add `#![feature(c_variadic)]` to the crate attributes to enable
diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.rs b/tests/ui/inference/note-and-explain-ReVar-124973.rs
index f1e24645636..aa4b909fa76 100644
--- a/tests/ui/inference/note-and-explain-ReVar-124973.rs
+++ b/tests/ui/inference/note-and-explain-ReVar-124973.rs
@@ -3,6 +3,7 @@
 #![feature(c_variadic)]
 
 async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
-//~^ ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
+//~^ ERROR functions cannot be both `async` and C-variadic
+//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
 
 fn main() {}
diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.stderr b/tests/ui/inference/note-and-explain-ReVar-124973.stderr
index 574f6508e4c..964fbc4a4fb 100644
--- a/tests/ui/inference/note-and-explain-ReVar-124973.stderr
+++ b/tests/ui/inference/note-and-explain-ReVar-124973.stderr
@@ -1,3 +1,9 @@
+error: functions cannot be both `async` and C-variadic
+  --> $DIR/note-and-explain-ReVar-124973.rs:5:1
+   |
+LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
+   | ^^^^^ `async` because of this                                      ^^^ C-variadic because of this
+
 error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
   --> $DIR/note-and-explain-ReVar-124973.rs:5:73
    |
@@ -8,6 +14,6 @@ LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
    |
    = note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs
index 9277994d9b3..dc0d14bf9d6 100644
--- a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs
+++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs
@@ -4,7 +4,6 @@
 
 fn main() {}
 
-fn foo(_: Bar, ...) -> impl {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-//~| ERROR cannot find type `Bar` in this scope
+unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
+//~^ ERROR cannot find type `Bar` in this scope
 //~| ERROR at least one trait must be specified
diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr
index 4a1aa49eb6e..31a393e7367 100644
--- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr
+++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr
@@ -1,21 +1,15 @@
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16
-   |
-LL | fn foo(_: Bar, ...) -> impl {}
-   |                ^^^
-
 error: at least one trait must be specified
-  --> $DIR/issue-83499-input-output-iteration-ice.rs:7:24
+  --> $DIR/issue-83499-input-output-iteration-ice.rs:7:42
    |
-LL | fn foo(_: Bar, ...) -> impl {}
-   |                        ^^^^
+LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
+   |                                          ^^^^
 
 error[E0412]: cannot find type `Bar` in this scope
-  --> $DIR/issue-83499-input-output-iteration-ice.rs:7:11
+  --> $DIR/issue-83499-input-output-iteration-ice.rs:7:29
    |
-LL | fn foo(_: Bar, ...) -> impl {}
-   |           ^^^ not found in this scope
+LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
+   |                             ^^^ not found in this scope
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
index 243924e6c53..4db056f15a5 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -4,25 +4,28 @@
 fn main() {}
 
 fn f1_1(x: isize, ...) {}
-//~^ 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 non-extern functions
 
 fn f1_2(...) {}
-//~^ 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 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 defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~^ ERROR functions with a C variable argument list must be unsafe
 
 extern "C" fn f2_2(...) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~^ ERROR functions with a C variable argument list must be unsafe
 
 extern "C" fn f2_3(..., x: isize) {}
 //~^ ERROR `...` must be the last argument of a C-variadic function
 
 extern "C" fn f3_1(x: isize, ...) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~^ ERROR functions with a C variable argument list must be unsafe
 
 extern "C" fn f3_2(...) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~^ ERROR functions with a C variable argument list must be unsafe
 
 extern "C" fn f3_3(..., x: isize) {}
 //~^ ERROR `...` must be the last argument of a C-variadic function
@@ -33,12 +36,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {}
 
 const extern "C" fn f4_2(x: isize, ...) {}
 //~^ ERROR functions cannot be both `const` and C-variadic
-//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~| ERROR functions with a C variable argument list must be unsafe
 //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
 
 const extern "C" fn f4_3(..., x: isize, ...) {}
 //~^ ERROR functions cannot be both `const` and C-variadic
-//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+//~| ERROR functions with a C variable argument list must be unsafe
 //~| ERROR `...` must be the last argument of a C-variadic function
 
 extern "C" {
@@ -50,30 +53,30 @@ struct X;
 
 impl X {
     fn i_f1(x: isize, ...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn i_f2(...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn i_f3(..., x: isize, ...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     //~| ERROR `...` must be the last argument of a C-variadic function
     fn i_f4(..., x: isize, ...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     //~| ERROR `...` must be the last argument of a C-variadic function
     const fn i_f5(x: isize, ...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     //~| ERROR functions cannot be both `const` and C-variadic
     //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
 }
 
 trait T {
     fn t_f1(x: isize, ...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn t_f2(x: isize, ...);
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn t_f3(...) {}
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn t_f4(...);
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
+    //~^ ERROR associated functions cannot have a C variable argument list
     fn t_f5(..., x: isize) {}
     //~^ ERROR `...` must be the last argument of a C-variadic function
     fn t_f6(..., x: isize);
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 5c55cc38b56..0cd78318de6 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -1,181 +1,225 @@
-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 non-extern functions
   --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19
    |
 LL | fn f1_1(x: isize, ...) {}
    |                   ^^^
+   |
+   = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
 
-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 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: 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 "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, ...) {}
    |                              ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL | unsafe extern "C" fn f2_1(x: isize, ...) {}
+   | ++++++
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
    |
 LL | extern "C" fn f2_2(...) {}
    |                    ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:30
    |
 LL | extern "C" fn f3_1(x: isize, ...) {}
    |                              ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL | unsafe extern "C" fn f3_1(x: isize, ...) {}
+   | ++++++
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
    |
 LL | extern "C" fn f3_2(...) {}
    |                    ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
+error: functions with a C variable argument list must be unsafe
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:42:41
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
    |                                         ^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:52:23
+error: associated functions cannot have a C variable argument list
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:55:23
    |
 LL |     fn i_f1(x: isize, ...) {}
    |                       ^^^
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
+error: associated functions cannot have a C variable argument list
+  --> $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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:28
+error: associated functions cannot have a C variable argument list
+  --> $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: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
+error: associated functions cannot have a C variable argument list
+  --> $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
    |     |
    |     `const` because of this
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
+error: associated functions cannot have a C variable argument list
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |                             ^^^
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:69:23
+error: associated functions cannot have a C variable argument list
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:72:23
    |
 LL |     fn t_f1(x: isize, ...) {}
    |                       ^^^
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23
+error: associated functions cannot have a C variable argument list
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:74:23
    |
 LL |     fn t_f2(x: isize, ...);
    |                       ^^^
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+error: associated functions cannot have a C variable argument list
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:76:13
    |
 LL |     fn t_f3(...) {}
    |             ^^^
 
-error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
+error: associated functions cannot have a C variable argument list
+  --> $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
@@ -183,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
@@ -191,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`.