about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs42
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs4
-rw-r--r--tests/ui/c-variadic/issue-86053-1.stderr4
-rw-r--r--tests/ui/c-variadic/no-closure.rs17
-rw-r--r--tests/ui/c-variadic/no-closure.stderr35
-rw-r--r--tests/ui/c-variadic/valid.rs29
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.rs12
-rw-r--r--tests/ui/parser/variadic-ffi-semantic-restrictions.stderr91
8 files changed, 140 insertions, 94 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 6133cc3548b..538918a890d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -665,46 +665,42 @@ impl<'a> AstValidator<'a> {
     /// - Non-const
     /// - Either foreign, or free and `unsafe extern "C"` semantically
     fn check_c_variadic_type(&self, fk: FnKind<'a>) {
-        let variadic_spans: Vec<_> = fk
-            .decl()
-            .inputs
-            .iter()
-            .filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
-            .map(|arg| arg.span)
-            .collect();
+        // `...` is already rejected when it is not the final parameter.
+        let variadic_param = match fk.decl().inputs.last() {
+            Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
+            _ => return,
+        };
 
-        if variadic_spans.is_empty() {
-            return;
-        }
+        let FnKind::Fn(fn_ctxt, _, Fn { sig, .. }) = fk else {
+            // Unreachable because the parser already rejects `...` in closures.
+            unreachable!("C variable argument list cannot be used in closures")
+        };
 
-        if let Some(header) = fk.header()
-            && let Const::Yes(const_span) = header.constness
-        {
-            let mut spans = variadic_spans.clone();
-            spans.push(const_span);
+        // C-variadics are not yet implemented in const evaluation.
+        if let Const::Yes(const_span) = sig.header.constness {
             self.dcx().emit_err(errors::ConstAndCVariadic {
-                spans,
+                spans: vec![const_span, variadic_param.span],
                 const_span,
-                variadic_spans: variadic_spans.clone(),
+                variadic_span: variadic_param.span,
             });
         }
 
-        match (fk.ctxt(), fk.header()) {
-            (Some(FnCtxt::Foreign), _) => return,
-            (Some(FnCtxt::Free), Some(header)) => match header.ext {
+        match fn_ctxt {
+            FnCtxt::Foreign => return,
+            FnCtxt::Free => match sig.header.ext {
                 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
                 | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
                 | Extern::Implicit(_)
-                    if matches!(header.safety, Safety::Unsafe(_)) =>
+                    if matches!(sig.header.safety, Safety::Unsafe(_)) =>
                 {
                     return;
                 }
                 _ => {}
             },
-            _ => {}
+            FnCtxt::Assoc(_) => {}
         };
 
-        self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
+        self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
     }
 
     fn check_item_named(&self, ident: Ident, kind: &str) {
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ae8f056cb4e..476ed27a10e 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -322,7 +322,7 @@ pub(crate) struct ExternItemAscii {
 #[diag(ast_passes_bad_c_variadic)]
 pub(crate) struct BadCVariadic {
     #[primary_span]
-    pub span: Vec<Span>,
+    pub span: Span,
 }
 
 #[derive(Diagnostic)]
@@ -656,7 +656,7 @@ pub(crate) struct ConstAndCVariadic {
     #[label(ast_passes_const)]
     pub const_span: Span,
     #[label(ast_passes_variadic)]
-    pub variadic_spans: Vec<Span>,
+    pub variadic_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 675dfd335c4..b58016b5a81 100644
--- a/tests/ui/c-variadic/issue-86053-1.stderr
+++ b/tests/ui/c-variadic/issue-86053-1.stderr
@@ -47,10 +47,10 @@ 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
-  --> $DIR/issue-86053-1.rs:11:12
+  --> $DIR/issue-86053-1.rs:11:36
    |
 LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
-   |            ^^^                     ^^^
+   |                                    ^^^
 
 error[E0412]: cannot find type `F` in this scope
   --> $DIR/issue-86053-1.rs:11:48
diff --git a/tests/ui/c-variadic/no-closure.rs b/tests/ui/c-variadic/no-closure.rs
new file mode 100644
index 00000000000..c0b77786e8b
--- /dev/null
+++ b/tests/ui/c-variadic/no-closure.rs
@@ -0,0 +1,17 @@
+#![feature(c_variadic)]
+#![crate_type = "lib"]
+
+// Check that `...` in closures is rejected.
+
+const F: extern "C" fn(...) = |_: ...| {};
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn foo() {
+    let f = |...| {};
+    //~^ ERROR: `..` patterns are not allowed here
+    //~| ERROR: unexpected `...`
+
+    let f = |_: ...| {};
+    //~^ ERROR C-variadic type `...` may not be nested inside another type
+    f(1i64)
+}
diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr
new file mode 100644
index 00000000000..77bd106bb95
--- /dev/null
+++ b/tests/ui/c-variadic/no-closure.stderr
@@ -0,0 +1,35 @@
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/no-closure.rs:6:35
+   |
+LL | const F: extern "C" fn(...) = |_: ...| {};
+   |                                   ^^^
+
+error: unexpected `...`
+  --> $DIR/no-closure.rs:10:14
+   |
+LL |     let f = |...| {};
+   |              ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let f = |...| {};
+LL +     let f = |..| {};
+   |
+
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/no-closure.rs:14:17
+   |
+LL |     let f = |_: ...| {};
+   |                 ^^^
+
+error: `..` patterns are not allowed here
+  --> $DIR/no-closure.rs:10:14
+   |
+LL |     let f = |...| {};
+   |              ^^^
+   |
+   = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0743`.
diff --git a/tests/ui/c-variadic/valid.rs b/tests/ui/c-variadic/valid.rs
new file mode 100644
index 00000000000..5a0b32026dc
--- /dev/null
+++ b/tests/ui/c-variadic/valid.rs
@@ -0,0 +1,29 @@
+//@ run-pass
+#![feature(c_variadic)]
+
+// In rust (and C23 and above) `...` can be the only argument.
+unsafe extern "C" fn only_dot_dot_dot(mut ap: ...) -> i32 {
+    unsafe { ap.arg() }
+}
+
+unsafe extern "C-unwind" fn abi_c_unwind(mut ap: ...) -> i32 {
+    unsafe { ap.arg() }
+}
+
+#[allow(improper_ctypes_definitions)]
+unsafe extern "C" fn mix_int_float(mut ap: ...) -> (i64, f64, *const i32, f64) {
+    (ap.arg(), ap.arg(), ap.arg(), ap.arg())
+}
+
+fn main() {
+    unsafe {
+        assert_eq!(only_dot_dot_dot(32), 32);
+        assert_eq!(abi_c_unwind(32), 32);
+
+        // Passing more arguments than expected is allowed.
+        assert_eq!(only_dot_dot_dot(32, 1i64, core::ptr::null::<i32>(), 3.14f64), 32);
+
+        let ptr = &14i32 as *const i32;
+        assert_eq!(mix_int_float(12i64, 13.0f64, ptr, 15.0f64), (12, 13.0, ptr, 15.0));
+    }
+}
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
index e7a0248cffa..243924e6c53 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -16,8 +16,7 @@ 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
 
 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
-//~| ERROR `...` must be the last argument of a C-variadic function
+//~^ 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
@@ -26,8 +25,7 @@ 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
 
 extern "C" fn f3_3(..., x: isize) {}
-//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-//~| ERROR `...` must be the last argument of a C-variadic function
+//~^ ERROR `...` must be the last argument of a C-variadic function
 
 const unsafe extern "C" fn f4_1(x: isize, ...) {}
 //~^ ERROR functions cannot be both `const` and C-variadic
@@ -77,9 +75,7 @@ trait T {
     fn t_f4(...);
     //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
     fn t_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 `...` must be the last argument of a C-variadic function
+    //~^ ERROR `...` must be the last argument of a C-variadic function
     fn t_f6(..., x: isize);
-    //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
-    //~| ERROR `...` must be the last argument of a C-variadic function
+    //~^ ERROR `...` must be the last argument of a C-variadic function
 }
diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 5379045967a..5c55cc38b56 100644
--- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -29,118 +29,103 @@ 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:18: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:22:30
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
    |
 LL | 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:25:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
    |
 LL | extern "C" fn f3_2(...) {}
    |                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20
-   |
-LL | extern "C" fn f3_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:28:20
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
    |
 LL | extern "C" fn f3_3(..., x: isize) {}
    |                    ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:32:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30: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:36:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34: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:36:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39: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:41:1
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:1
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
-   | ^^^^^                    ^^^            ^^^ C-variadic because of this
-   | |                        |
-   | |                        C-variadic because of this
-   | `const` because of this
+   | ^^^^^ `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:41:26
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
    |
 LL | const extern "C" fn f4_3(..., x: isize, ...) {}
-   |                          ^^^            ^^^
+   |                                         ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:45: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:54:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:52: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:56:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
    |
 LL |     fn i_f2(...) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:56: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:58:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:56:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^            ^^^
+   |                            ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59: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:61:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^            ^^^
+   |                            ^^^
 
 error: functions cannot be both `const` and C-variadic
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:5
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:5
    |
 LL |     const fn i_f5(x: isize, ...) {}
    |     ^^^^^                   ^^^ C-variadic because of this
@@ -148,61 +133,49 @@ LL |     const fn i_f5(x: isize, ...) {}
    |     `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:64:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62: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:71:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:69: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:73:23
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:71: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:75:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73: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:77:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
    |
 LL |     fn t_f4(...);
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
-   |
-LL |     fn t_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:79:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13
    |
 LL |     fn t_f5(..., x: isize) {}
    |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13
-   |
-LL |     fn t_f6(..., 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:82:13
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
    |
 LL |     fn t_f6(..., x: isize);
    |             ^^^
 
 error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
-  --> $DIR/variadic-ffi-semantic-restrictions.rs:32:43
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:43
    |
 LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
    |                                           ^^^   - value is dropped here
@@ -210,7 +183,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:36:36
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
    |
 LL | const extern "C" fn f4_2(x: isize, ...) {}
    |                                    ^^^   - value is dropped here
@@ -218,13 +191,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:64:29
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62: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 36 previous errors
+error: aborting due to 32 previous errors
 
 For more information about this error, try `rustc --explain E0493`.