about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@osdyne.com>2025-09-15 02:53:29 -0700
committerEsteban Küber <esteban@osdyne.com>2025-09-15 02:53:29 -0700
commit9405e76431374e25077b374ed0cd9c920a1c0f4f (patch)
tree696c431be15b451d16b90017bca4131ca3156574
parent52618eb338609df44978b0ca4451ab7941fd1c7a (diff)
downloadrust-9405e76431374e25077b374ed0cd9c920a1c0f4f.tar.gz
rust-9405e76431374e25077b374ed0cd9c920a1c0f4f.zip
Detect attempt to use var-args in closure
```
error: unexpected `...`
  --> $DIR/varargs-in-closure-isnt-supported.rs:5:20
   |
LL |     let mut lol = |...| ();
   |                    ^^^ not a valid pattern
   |
   = note: C-variadic type `...` is not allowed here
```
-rw-r--r--compiler/rustc_parse/messages.ftl1
-rw-r--r--compiler/rustc_parse/src/errors.rs4
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs27
-rw-r--r--tests/ui/closures/varargs-in-closure-isnt-supported.rs11
-rw-r--r--tests/ui/closures/varargs-in-closure-isnt-supported.stderr22
5 files changed, 56 insertions, 9 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 72cd75f6d89..6d9521c7d2b 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -189,6 +189,7 @@ parse_dotdotdot = unexpected token: `...`
 parse_dotdotdot_rest_pattern = unexpected `...`
     .label = not a valid pattern
     .suggestion = for a rest pattern, use `..` instead of `...`
+    .note = C-variadic type `...` is not allowed here
 
 parse_double_colon_in_bound = expected `:` followed by trait or lifetime
     .suggestion = use single colon
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 00ca5acd84d..2b107fe35d5 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2723,7 +2723,9 @@ pub(crate) struct DotDotDotRestPattern {
     #[label]
     pub span: Span,
     #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
-    pub suggestion: Span,
+    pub suggestion: Option<Span>,
+    #[note]
+    pub var_args: Option<()>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index c4d30b3d328..fda19d62bc7 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -756,7 +756,7 @@ impl<'a> Parser<'a> {
             self.bump(); // `..`
             PatKind::Rest
         } else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) {
-            self.recover_dotdotdot_rest_pat(lo)
+            self.recover_dotdotdot_rest_pat(lo, expected)
         } else if let Some(form) = self.parse_range_end() {
             self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
         } else if self.eat(exp!(Bang)) {
@@ -886,16 +886,27 @@ impl<'a> Parser<'a> {
 
     /// Recover from a typoed `...` pattern that was encountered
     /// Ref: Issue #70388
-    fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
+    fn recover_dotdotdot_rest_pat(&mut self, lo: Span, expected: Option<Expected>) -> PatKind {
         // A typoed rest pattern `...`.
         self.bump(); // `...`
 
-        // The user probably mistook `...` for a rest pattern `..`.
-        self.dcx().emit_err(DotDotDotRestPattern {
-            span: lo,
-            suggestion: lo.with_lo(lo.hi() - BytePos(1)),
-        });
-        PatKind::Rest
+        if let Some(Expected::ParameterName) = expected {
+            // We have `...` in a closure argument, likely meant to be var-arg, which aren't
+            // supported in closures (#146489).
+            PatKind::Err(self.dcx().emit_err(DotDotDotRestPattern {
+                span: lo,
+                suggestion: None,
+                var_args: Some(()),
+            }))
+        } else {
+            // The user probably mistook `...` for a rest pattern `..`.
+            self.dcx().emit_err(DotDotDotRestPattern {
+                span: lo,
+                suggestion: Some(lo.with_lo(lo.hi() - BytePos(1))),
+                var_args: None,
+            });
+            PatKind::Rest
+        }
     }
 
     /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.rs b/tests/ui/closures/varargs-in-closure-isnt-supported.rs
new file mode 100644
index 00000000000..5dff69194f9
--- /dev/null
+++ b/tests/ui/closures/varargs-in-closure-isnt-supported.rs
@@ -0,0 +1,11 @@
+// var-args are not supported in closures, ensure we don't misdirect people (#146489)
+#![feature(c_variadic)]
+
+unsafe extern "C" fn thats_not_a_pattern(mut ap: ...) -> u32 {
+    let mut lol = |...| (); //~ ERROR: unexpected `...`
+    unsafe { ap.arg::<u32>() } //~^ NOTE: C-variadic type `...` is not allowed here
+    //~| ERROR: type annotations needed
+    //~| NOTE: not a valid pattern
+}
+
+fn main() {}
diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr
new file mode 100644
index 00000000000..4f66ff59af1
--- /dev/null
+++ b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr
@@ -0,0 +1,22 @@
+error: unexpected `...`
+  --> $DIR/varargs-in-closure-isnt-supported.rs:5:20
+   |
+LL |     let mut lol = |...| ();
+   |                    ^^^ not a valid pattern
+   |
+   = note: C-variadic type `...` is not allowed here
+
+error[E0282]: type annotations needed
+  --> $DIR/varargs-in-closure-isnt-supported.rs:5:20
+   |
+LL |     let mut lol = |...| ();
+   |                    ^^^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     let mut lol = |...: /* Type */| ();
+   |                       ++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.