From 19978b4b071d1215a2e884d0b19492657921db40 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:08:13 +0200 Subject: [PATCH 01/10] Correctly track `first_param` --- compiler/rustc_parse/src/parser/path.rs | 4 +- tests/ui/fn/named-fn-trait-parameters.rs | 6 +-- tests/ui/fn/named-fn-trait-parameters.stderr | 44 +++++--------------- 3 files changed, 14 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index cbd0891c7fe9a..c15928dddea3f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -397,6 +397,7 @@ impl<'a> Parser<'a> { } let dcx = self.dcx(); + let mut first_param = true; let parse_params_result = self.parse_paren_comma_seq(|p| { // Inside parenthesized type arguments, we want types only, not names. let mode = FnParseMode { @@ -404,7 +405,8 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, false, false)?; + let param = p.parse_param_general(&mode, first_param, false)?; + first_param = false; if !matches!(param.pat.kind, PatKind::Missing) { self.psess .gated_spans diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 00b00b53a94d6..746854ab7f4e2 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -26,10 +26,8 @@ fn semantics( //~^ ERROR unexpected token: `:` self1: impl Fn(self), - //~^ ERROR unexpected `self` parameter in function self2: impl Fn(self, self), //~^ ERROR unexpected `self` parameter in function - //~| ERROR unexpected `self` parameter in function self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function @@ -56,11 +54,9 @@ fn syntax( pat5: impl Fn((((((x))))): bool), //~^ ERROR unexpected token: `:` - self1: impl Fn(self), // FIXME should be accepted - //~^ ERROR unexpected `self` parameter in function + self1: impl Fn(self), self2: impl Fn(self, self), //~^ ERROR unexpected `self` parameter in function - //~| ERROR unexpected `self` parameter in function self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index fa583ec52c543..1321afb77a735 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -29,82 +29,58 @@ LL | pat5: impl Fn((((((x))))): bool), | ^ unexpected token after this error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:28:20 - | -LL | self1: impl Fn(self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:20 - | -LL | self2: impl Fn(self, self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:26 + --> $DIR/named-fn-trait-parameters.rs:29:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:33:26 + --> $DIR/named-fn-trait-parameters.rs:31:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error: expected type, found `1` - --> $DIR/named-fn-trait-parameters.rs:48:19 + --> $DIR/named-fn-trait-parameters.rs:46:19 | LL | pat1: impl Fn(1..3: bool), | ^ expected type error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:50:25 + --> $DIR/named-fn-trait-parameters.rs:48:25 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^ unexpected token after this error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:52:25 + --> $DIR/named-fn-trait-parameters.rs:50:25 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^ expected one of `!`, `(`, `+`, `::`, or `<` error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:54:27 + --> $DIR/named-fn-trait-parameters.rs:52:27 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^ expected one of `!`, `(`, `+`, `::`, or `<` error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:56:30 + --> $DIR/named-fn-trait-parameters.rs:54:30 | LL | pat5: impl Fn((((((x))))): bool), | ^ unexpected token after this error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:59:20 - | -LL | self1: impl Fn(self), // FIXME should be accepted - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:20 - | -LL | self2: impl Fn(self, self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:58:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:64:26 + --> $DIR/named-fn-trait-parameters.rs:60:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: aborting due to 18 previous errors +error: aborting due to 14 previous errors From acc7dd9f869024ae59d889f96ae2d3347f1e692f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:15:44 +0200 Subject: [PATCH 02/10] Add `FnContext::ParenthesizedArgumentList` --- compiler/rustc_parse/src/parser/diagnostics.rs | 1 + compiler/rustc_parse/src/parser/function.rs | 2 ++ compiler/rustc_parse/src/parser/path.rs | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6d4a0215eb7b3..a8bc293d96751 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2379,6 +2379,7 @@ impl<'a> Parser<'a> { target: match context { FnContext::Trait => "methods without bodies", FnContext::FunctionPtrType => "function pointer types", + FnContext::ParenthesizedArgumentList => "parenthesized argument list", FnContext::Free => unreachable!("This method is not called in free functions, as patterns are always allowed there"), FnContext::Impl => unreachable!("This method is not called in impls, as patterns are always allowed there"), }, diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 57fe19226066c..2224bf1ec8efa 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -103,6 +103,8 @@ pub(crate) enum FnContext { Free, /// A Function Pointer Type `fn(..)`. FunctionPtrType, + /// A Parenthesized Argument List `impl Fn(...)` + ParenthesizedArgumentList, /// A Trait context. Trait, /// An Impl block. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c15928dddea3f..1fe4d72b3cee1 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -401,7 +401,7 @@ impl<'a> Parser<'a> { let parse_params_result = self.parse_paren_comma_seq(|p| { // Inside parenthesized type arguments, we want types only, not names. let mode = FnParseMode { - context: FnContext::Free, + context: FnContext::ParenthesizedArgumentList, req_name: |_, _| false, req_body: false, }; From 19c0f5c216dfe0d63ceb605827fb92229f59a70d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:35:23 +0200 Subject: [PATCH 03/10] Don't suggest using a pattern when `recover_arg_parse` fails While the stderrs in this commit are neutral, some better some worse, there were quite a few bad diagnostics if we enable `recover_arg_parse` for parenthesized argument lists --- compiler/rustc_parse/src/parser/function.rs | 14 ++++++++++++-- .../dotdotdot-rest-pattern-suggestion-span.rs | 2 +- .../dotdotdot-rest-pattern-suggestion-span.stderr | 4 ++-- tests/ui/parser/issue-116781.rs | 4 ++-- tests/ui/parser/issue-116781.stderr | 8 ++++---- .../rfc-2565-param-attrs/attr-without-param.rs | 2 +- .../rfc-2565-param-attrs/attr-without-param.stderr | 4 ++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 2224bf1ec8efa..a042826c231a8 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -816,9 +816,19 @@ impl<'a> Parser<'a> { Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), Err(err) if recover_arg_parse => { // Recover from attempting to parse the argument as a type without pattern. - err.cancel(); this.restore_snapshot(parser_snapshot_before_ty); - this.recover_arg_parse(fn_parse_mode.context)? + match this.recover_arg_parse(fn_parse_mode.context) { + Ok(res) => { + // We managed to parse the argument as a pattern, cancel the original error and emit a better one + err.cancel(); + res + } + Err(new_err) => { + // We did not manage to parse the argument as a pattern, avoid suggesting a pattern and emit the original error + new_err.cancel(); + return Err(err); + } + } } Err(err) => return Err(err), } diff --git a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs index 0db10726c5dc4..36091b480d3c3 100644 --- a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs +++ b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs @@ -10,7 +10,7 @@ impl S { fn f(···>) } //~| ERROR unknown start of token //~| ERROR unknown start of token //~| ERROR unexpected `...` -//~| ERROR expected `:`, found `>` +//~| ERROR unexpected token: `>` //~| ERROR expected one of //~| ERROR associated function in `impl` without body //~| ERROR cannot find type `S` in this scope diff --git a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr index d483c40ca5e0b..0889ca8a495af 100644 --- a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr +++ b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr @@ -48,11 +48,11 @@ LL - impl S { fn f(···>) } LL + impl S { fn f(..>) } | -error: expected `:`, found `>` +error: unexpected token: `>` --> $DIR/dotdotdot-rest-pattern-suggestion-span.rs:8:18 | LL | impl S { fn f(···>) } - | ^ expected `:` + | ^ unexpected token after this error: expected one of `->`, `where`, or `{`, found `}` --> $DIR/dotdotdot-rest-pattern-suggestion-span.rs:8:21 diff --git a/tests/ui/parser/issue-116781.rs b/tests/ui/parser/issue-116781.rs index 176350fe2eec6..5ff0989b3df00 100644 --- a/tests/ui/parser/issue-116781.rs +++ b/tests/ui/parser/issue-116781.rs @@ -1,8 +1,8 @@ #[derive(Debug)] struct Foo { #[cfg(true)] - field: fn(($),), //~ ERROR expected pattern, found `$` - //~^ ERROR expected pattern, found `$` + field: fn(($),), //~ ERROR expected type, found `$` + //~^ ERROR expected type, found `$` } fn main() {} diff --git a/tests/ui/parser/issue-116781.stderr b/tests/ui/parser/issue-116781.stderr index 1a77b60a50dc8..fdfadf4a9e313 100644 --- a/tests/ui/parser/issue-116781.stderr +++ b/tests/ui/parser/issue-116781.stderr @@ -1,14 +1,14 @@ -error: expected pattern, found `$` +error: expected type, found `$` --> $DIR/issue-116781.rs:4:16 | LL | field: fn(($),), - | ^ expected pattern + | ^ expected type -error: expected pattern, found `$` +error: expected type, found `$` --> $DIR/issue-116781.rs:4:16 | LL | field: fn(($),), - | ^ expected pattern + | ^ expected type | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs index 14402eaeecac1..d775545dd571c 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs @@ -11,7 +11,7 @@ impl T for S { #[cfg(false)] trait T { - fn f(#[attr]); //~ ERROR expected argument name, found `)` + fn f(#[attr]); //~ ERROR expected type, found `)` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr index 2fa03f3cb0bba..65b265fb6289a 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr @@ -10,11 +10,11 @@ error: expected parameter name, found `)` LL | fn f(#[attr]) {} | ^ expected parameter name -error: expected argument name, found `)` +error: expected type, found `)` --> $DIR/attr-without-param.rs:14:17 | LL | fn f(#[attr]); - | ^ expected argument name + | ^ expected type error: aborting due to 3 previous errors From e603db4aa67c4149543a79dc5fbdc466f334f0e2 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:39:16 +0200 Subject: [PATCH 04/10] Enable `recover_arg_parse` for parenthesized argument lists --- compiler/rustc_parse/src/parser/path.rs | 2 +- tests/ui/fn/named-fn-trait-parameters.rs | 21 +-- tests/ui/fn/named-fn-trait-parameters.stderr | 147 ++++++++++++++---- .../issues/issue-103748-ICE-wrong-braces.rs | 1 + .../issue-103748-ICE-wrong-braces.stderr | 10 +- 5 files changed, 135 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1fe4d72b3cee1..e4ba1e7d18e51 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -405,7 +405,7 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, first_param, false)?; + let param = p.parse_param_general(&mode, first_param, true)?; first_param = false; if !matches!(param.pat.kind, PatKind::Missing) { self.psess diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 746854ab7f4e2..16dd8e8cf6d5a 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -15,15 +15,16 @@ fn allowed( // Patterns are semantically rejected fn semantics( pat1: impl Fn(1..3: bool), - //~^ ERROR expected type, found `1` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat2: impl Fn((x, y): (bool, bool)), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat3: impl Fn(Thing { a, b }: Thing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat4: impl Fn(NoThing { a, b }: NoThing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list + //~| ERROR cannot find type `NoThing` in this scope pat5: impl Fn((((((x))))): bool), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), self2: impl Fn(self, self), @@ -44,15 +45,15 @@ fn semantics( #[cfg(false)] fn syntax( pat1: impl Fn(1..3: bool), - //~^ ERROR expected type, found `1` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat2: impl Fn((x, y): (bool, bool)), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat3: impl Fn(Thing { a, b }: Thing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat4: impl Fn(NoThing { a, b }: NoThing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat5: impl Fn((((((x))))): bool), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), self2: impl Fn(self, self), diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 1321afb77a735..5f3a802e07372 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -1,86 +1,165 @@ -error: expected type, found `1` +error[E0642]: patterns aren't allowed in parenthesized argument list --> $DIR/named-fn-trait-parameters.rs:17:19 | LL | pat1: impl Fn(1..3: bool), - | ^ expected type + | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat1: impl Fn(1..3: bool), +LL + pat1: impl Fn(_: bool), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:19:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:19:19 | LL | pat2: impl Fn((x, y): (bool, bool)), - | ^ unexpected token after this + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat2: impl Fn((x, y): (bool, bool)), +LL + pat2: impl Fn(_: (bool, bool)), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:21:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:21:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat3: impl Fn(Thing { a, b }: Thing), +LL + pat3: impl Fn(_: Thing), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:23:27 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:23:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(_: NoThing), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:25:30 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:26:19 | LL | pat5: impl Fn((((((x))))): bool), - | ^ unexpected token after this + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat5: impl Fn((((((x))))): bool), +LL + pat5: impl Fn(_: bool), + | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:29:26 + --> $DIR/named-fn-trait-parameters.rs:30:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:31:26 + --> $DIR/named-fn-trait-parameters.rs:32:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: expected type, found `1` - --> $DIR/named-fn-trait-parameters.rs:46:19 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:47:19 | LL | pat1: impl Fn(1..3: bool), - | ^ expected type + | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat1: impl Fn(1..3: bool), +LL + pat1: impl Fn(_: bool), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:48:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:49:19 | LL | pat2: impl Fn((x, y): (bool, bool)), - | ^ unexpected token after this + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat2: impl Fn((x, y): (bool, bool)), +LL + pat2: impl Fn(_: (bool, bool)), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:50:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:51:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat3: impl Fn(Thing { a, b }: Thing), +LL + pat3: impl Fn(_: Thing), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:52:27 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:53:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(_: NoThing), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:54:30 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:55:19 | LL | pat5: impl Fn((((((x))))): bool), - | ^ unexpected token after this + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat5: impl Fn((((((x))))): bool), +LL + pat5: impl Fn(_: bool), + | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:58:26 + --> $DIR/named-fn-trait-parameters.rs:59:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:60:26 + --> $DIR/named-fn-trait-parameters.rs:61:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: aborting due to 14 previous errors +error[E0425]: cannot find type `NoThing` in this scope + --> $DIR/named-fn-trait-parameters.rs:23:37 + | +LL | pat4: impl Fn(NoThing { a, b }: NoThing), + | ^^^^^^^ not found in this scope + | +note: similarly named struct `Thing` defined here + --> $DIR/named-fn-trait-parameters.rs:73:1 + | +LL | struct Thing { a: bool, b: bool } + | ^^^^^^^^^^^^ +help: a struct with a similar name exists + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(NoThing { a, b }: Thing), + | + +error: aborting due to 15 previous errors +Some errors have detailed explanations: E0425, E0642. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index 60dd88e65400a..08997f8a6afd0 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs @@ -3,3 +3,4 @@ struct Apple((Apple, Option(Banana ? Citron))); //~^ ERROR invalid `?` in type //~| ERROR unexpected token: `Citron` +//~| ERROR expected a pattern, found an expression diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index c92535c3906bc..fff09d19772f5 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr @@ -16,5 +16,13 @@ error: unexpected token: `Citron` LL | struct Apple((Apple, Option(Banana ? Citron))); | ^^^^^^ unexpected token after this -error: aborting due to 2 previous errors +error: expected a pattern, found an expression + --> $DIR/issue-103748-ICE-wrong-braces.rs:3:29 + | +LL | struct Apple((Apple, Option(Banana ? Citron))); + | ^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: + +error: aborting due to 3 previous errors From f1e7b1ecca1cf1c57aead940365d9f09a50cf420 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:14:44 +0200 Subject: [PATCH 05/10] Semantically forbid `self` params in parenthesized argument lists --- .../rustc_ast_passes/src/ast_validation.rs | 13 +++++-- tests/ui/fn/named-fn-trait-parameters.rs | 4 +- tests/ui/fn/named-fn-trait-parameters.stderr | 38 +++++++++++++------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index fe5c604544448..234ba16daaade 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -397,7 +397,7 @@ impl<'a> AstValidator<'a> { let c_variadic_span = self.check_decl_cvariadic_pos(fn_decl); self.check_decl_splatting(fn_decl, c_variadic_span, splat_semantic); self.check_decl_attrs(fn_decl); - self.check_decl_self_param(fn_decl, self_semantic); + self.check_decl_self_param(&fn_decl.inputs, self_semantic); } /// Emits fatal error if function declaration has more than `u16::MAX` arguments @@ -544,8 +544,8 @@ impl<'a> AstValidator<'a> { }); } - fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { - if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { + fn check_decl_self_param(&self, fn_inputs: &[Param], self_semantic: SelfSemantic) { + if let (SelfSemantic::No, [param, ..]) = (self_semantic, fn_inputs) { if param.is_self() { self.dcx().emit_err(diagnostics::FnParamForbiddenSelf { span: param.span }); } @@ -2208,6 +2208,13 @@ impl Visitor<'_> for AstValidator<'_> { |this| visit::walk_anon_const(this, anon_const), ) } + + fn visit_path_segment(&mut self, seg: &PathSegment) -> Self::Result { + if let Some(Parenthesized(args)) = &seg.args { + self.check_decl_self_param(&args.inputs, SelfSemantic::No); + } + visit::walk_path_segment(self, seg); + } } pub fn check_crate( diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 16dd8e8cf6d5a..0c9340221899b 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -27,8 +27,10 @@ fn semantics( //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), + //~^ ERROR `self` parameter is only allowed in associated functions self2: impl Fn(self, self), - //~^ ERROR unexpected `self` parameter in function + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR unexpected `self` parameter in function self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 5f3a802e07372..3f3dced1907af 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -59,19 +59,19 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:26 + --> $DIR/named-fn-trait-parameters.rs:31:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:32:26 + --> $DIR/named-fn-trait-parameters.rs:34:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:47:19 + --> $DIR/named-fn-trait-parameters.rs:49:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:49:19 + --> $DIR/named-fn-trait-parameters.rs:51:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:51:19 + --> $DIR/named-fn-trait-parameters.rs:53:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:53:19 + --> $DIR/named-fn-trait-parameters.rs:55:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:55:19 + --> $DIR/named-fn-trait-parameters.rs:57:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,17 +131,33 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:59:26 + --> $DIR/named-fn-trait-parameters.rs:61:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:63:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function +error: `self` parameter is only allowed in associated functions + --> $DIR/named-fn-trait-parameters.rs:29:20 + | +LL | self1: impl Fn(self), + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: `self` parameter is only allowed in associated functions + --> $DIR/named-fn-trait-parameters.rs:31:20 + | +LL | self2: impl Fn(self, self), + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + error[E0425]: cannot find type `NoThing` in this scope --> $DIR/named-fn-trait-parameters.rs:23:37 | @@ -149,7 +165,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:73:1 + --> $DIR/named-fn-trait-parameters.rs:75:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ @@ -159,7 +175,7 @@ LL - pat4: impl Fn(NoThing { a, b }: NoThing), LL + pat4: impl Fn(NoThing { a, b }: Thing), | -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0425, E0642. For more information about an error, try `rustc --explain E0425`. From 26ba932cb875261f96b5e89f6052c0ab88158d9b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:21:43 +0200 Subject: [PATCH 06/10] Semantically forbid patterns in parenthesized argument lists --- .../rustc_ast_passes/src/ast_validation.rs | 14 +++-- compiler/rustc_ast_passes/src/diagnostics.rs | 7 +++ tests/ui/fn/named-fn-trait-parameters.rs | 7 ++- tests/ui/fn/named-fn-trait-parameters.stderr | 56 +++++++++++++++---- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 234ba16daaade..010afc6be5534 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -291,8 +291,11 @@ impl<'a> AstValidator<'a> { }); } - fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { - for Param { pat, .. } in &decl.inputs { + fn check_decl_no_pat( + fn_inputs: &[Param], + mut report_err: impl FnMut(Span, Option, bool), + ) { + for Param { pat, .. } in fn_inputs { match pat.kind { PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} PatKind::Ident(BindingMode::MUT, ident, None) => { @@ -1200,7 +1203,7 @@ impl<'a> AstValidator<'a> { SelfSemantic::No, SplatSemantic::from_extern(bfty.ext), ); - Self::check_decl_no_pat(&bfty.decl, |span, _, _| { + Self::check_decl_no_pat(&bfty.decl.inputs, |span, _, _| { self.dcx().emit_err(diagnostics::PatternFnPointer { span }); }); if let Extern::Implicit(extern_span) = bfty.ext { @@ -2009,7 +2012,7 @@ impl Visitor<'_> for AstValidator<'_> { // Functions without bodies cannot have patterns. if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk { - Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { + Self::check_decl_no_pat(&sig.decl.inputs, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { let is_foreign = matches!(ctxt, FnCtxt::Foreign); @@ -2212,6 +2215,9 @@ impl Visitor<'_> for AstValidator<'_> { fn visit_path_segment(&mut self, seg: &PathSegment) -> Self::Result { if let Some(Parenthesized(args)) = &seg.args { self.check_decl_self_param(&args.inputs, SelfSemantic::No); + Self::check_decl_no_pat(&args.inputs, |span, _, _| { + self.dcx().emit_err(diagnostics::PatternParenthesizedArgList { span }); + }); } visit::walk_path_segment(self, seg); } diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 5ab905b5df52b..19516272ce166 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -675,6 +675,13 @@ pub(crate) struct PatternFnPointer { pub span: Span, } +#[derive(Diagnostic)] +#[diag("patterns aren't allowed in parenthesized argument lists", code = E0561)] +pub(crate) struct PatternParenthesizedArgList { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("only a single explicit lifetime bound is permitted", code = E0226)] pub(crate) struct TraitObjectBound { diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 0c9340221899b..14f913c8bdd3d 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -34,13 +34,18 @@ fn semantics( self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function - // FIXME should be rejected restricted_pat1: impl Fn(mut x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat2: impl Fn(&x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat3: impl Fn(&&x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat4: impl Fn(false: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat5: impl Fn(&_: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat6: impl Fn(&true: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 3f3dced1907af..43644fee0cb0c 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -71,7 +71,7 @@ LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:49:19 + --> $DIR/named-fn-trait-parameters.rs:54:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:51:19 + --> $DIR/named-fn-trait-parameters.rs:56:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:53:19 + --> $DIR/named-fn-trait-parameters.rs:58:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:55:19 + --> $DIR/named-fn-trait-parameters.rs:60:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:57:19 + --> $DIR/named-fn-trait-parameters.rs:62:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:66:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:63:26 + --> $DIR/named-fn-trait-parameters.rs:68:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -158,6 +158,42 @@ LL | self2: impl Fn(self, self), | = note: associated functions are those in `impl` or `trait` definitions +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:37:30 + | +LL | restricted_pat1: impl Fn(mut x: ()), + | ^^^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:39:30 + | +LL | restricted_pat2: impl Fn(&x: ()), + | ^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:41:30 + | +LL | restricted_pat3: impl Fn(&&x: ()), + | ^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:43:30 + | +LL | restricted_pat4: impl Fn(false: ()), + | ^^^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:45:30 + | +LL | restricted_pat5: impl Fn(&_: ()), + | ^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:47:30 + | +LL | restricted_pat6: impl Fn(&true: ()), + | ^^^^^ + error[E0425]: cannot find type `NoThing` in this scope --> $DIR/named-fn-trait-parameters.rs:23:37 | @@ -165,7 +201,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:75:1 + --> $DIR/named-fn-trait-parameters.rs:80:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ @@ -175,7 +211,7 @@ LL - pat4: impl Fn(NoThing { a, b }: NoThing), LL + pat4: impl Fn(NoThing { a, b }: Thing), | -error: aborting due to 17 previous errors +error: aborting due to 23 previous errors -Some errors have detailed explanations: E0425, E0642. +Some errors have detailed explanations: E0425, E0561, E0642. For more information about an error, try `rustc --explain E0425`. From 930507ec764c9bb7cfc1756c5bb0458947586ef3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:25:24 +0200 Subject: [PATCH 07/10] No longer mark `named_fn_trait_parameters` as incomplete --- compiler/rustc_feature/src/unstable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 7efa784bd8622..5bad528963987 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -642,7 +642,7 @@ declare_features! ( /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows providing names to parameters of `impl Fn` etc - (incomplete, named_fn_trait_parameters, "1.99.0", Some(158499)), + (unstable, named_fn_trait_parameters, "1.99.0", Some(158499)), /// Allows specifying the as-needed link modifier (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)), /// Allow negative trait implementations. From 70339fc8f6dbab8fde0201390dfa5a21812e84b1 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 14:05:43 +0200 Subject: [PATCH 08/10] Test that duplicate names are semantically allowed --- tests/ui/fn/fn-ptr-pattern.rs | 2 ++ tests/ui/fn/fn-ptr-pattern.stderr | 16 ++++++++-------- tests/ui/fn/named-fn-trait-parameters.rs | 2 ++ tests/ui/fn/named-fn-trait-parameters.stderr | 16 ++++++++-------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/tests/ui/fn/fn-ptr-pattern.rs b/tests/ui/fn/fn-ptr-pattern.rs index 9bf759af19af7..4260a5095048e 100644 --- a/tests/ui/fn/fn-ptr-pattern.rs +++ b/tests/ui/fn/fn-ptr-pattern.rs @@ -42,6 +42,8 @@ fn semantics( //~^ ERROR patterns aren't allowed in function pointer types restricted_pat6: fn(&true: ()), //~^ ERROR patterns aren't allowed in function pointer types + + duplicate_names: fn(x: usize, x: usize), ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/fn-ptr-pattern.stderr b/tests/ui/fn/fn-ptr-pattern.stderr index 4425caee39e3f..27982d26dbc54 100644 --- a/tests/ui/fn/fn-ptr-pattern.stderr +++ b/tests/ui/fn/fn-ptr-pattern.stderr @@ -71,7 +71,7 @@ LL | self3: fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:50:14 + --> $DIR/fn-ptr-pattern.rs:52:14 | LL | pat1: fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: fn(_: bool), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:52:14 + --> $DIR/fn-ptr-pattern.rs:54:14 | LL | pat2: fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:54:14 + --> $DIR/fn-ptr-pattern.rs:56:14 | LL | pat3: fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: fn(_: Thing), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:56:14 + --> $DIR/fn-ptr-pattern.rs:58:14 | LL | pat4: fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: fn(_: NoThing), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:58:14 + --> $DIR/fn-ptr-pattern.rs:60:14 | LL | pat5: fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/fn-ptr-pattern.rs:62:21 + --> $DIR/fn-ptr-pattern.rs:64:21 | LL | self2: fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/fn-ptr-pattern.rs:64:21 + --> $DIR/fn-ptr-pattern.rs:66:21 | LL | self3: fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -201,7 +201,7 @@ LL | pat4: fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/fn-ptr-pattern.rs:75:1 + --> $DIR/fn-ptr-pattern.rs:77:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 14f913c8bdd3d..103ce5902048e 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -46,6 +46,8 @@ fn semantics( //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat6: impl Fn(&true: ()), //~^ ERROR patterns aren't allowed in parenthesized argument lists + + duplicate_names: impl Fn(x: usize, x: usize), ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 43644fee0cb0c..d675826ff8559 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -71,7 +71,7 @@ LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:54:19 + --> $DIR/named-fn-trait-parameters.rs:56:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:56:19 + --> $DIR/named-fn-trait-parameters.rs:58:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:58:19 + --> $DIR/named-fn-trait-parameters.rs:60:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:60:19 + --> $DIR/named-fn-trait-parameters.rs:62:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:62:19 + --> $DIR/named-fn-trait-parameters.rs:64:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:66:26 + --> $DIR/named-fn-trait-parameters.rs:68:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:68:26 + --> $DIR/named-fn-trait-parameters.rs:70:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -201,7 +201,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:80:1 + --> $DIR/named-fn-trait-parameters.rs:82:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ From d5e94f259e3a573e0fe4a327276525d672e57142 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 14 Sep 2026 10:27:06 +0200 Subject: [PATCH 09/10] Remove `parse_param_general` --- compiler/rustc_parse/src/parser/function.rs | 6 ++---- compiler/rustc_parse/src/parser/path.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index a042826c231a8..220cc5a3bc069 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -693,7 +693,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(fn_parse_mode, first_param, true).or_else(|e| { + let param = p.parse_param_general(fn_parse_mode, first_param).or_else(|e| { let guar = e.emit(); // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. @@ -726,7 +726,6 @@ impl<'a> Parser<'a> { &mut self, fn_parse_mode: &FnParseMode, first_param: bool, - recover_arg_parse: bool, ) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; @@ -814,7 +813,7 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), - Err(err) if recover_arg_parse => { + Err(err) => { // Recover from attempting to parse the argument as a type without pattern. this.restore_snapshot(parser_snapshot_before_ty); match this.recover_arg_parse(fn_parse_mode.context) { @@ -830,7 +829,6 @@ impl<'a> Parser<'a> { } } } - Err(err) => return Err(err), } }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index e4ba1e7d18e51..6bc7195b8371c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -405,7 +405,7 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, first_param, true)?; + let param = p.parse_param_general(&mode, first_param)?; first_param = false; if !matches!(param.pat.kind, PatKind::Missing) { self.psess From 99bb4bb2573e40c90acd61a36f8fd0d2dcc1061a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 14 Sep 2026 10:29:28 +0200 Subject: [PATCH 10/10] Improve docs for `GenericArgs::Parenthesized` --- compiler/rustc_ast/src/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c14ad62e9a60b..b7a9765d09273 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -255,7 +255,7 @@ impl PathSegment { pub enum GenericArgs { /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`. AngleBracketed(AngleBracketedArgs), - /// The `(A, B)` and `C` in `Foo(A, B) -> C`. + /// The `(A, B)` and `C` in `Foo(A, B) -> C`, used for the `Fn` trait among others. Parenthesized(ParenthesizedArgs), /// `(..)` in return type notation. ParenthesizedElided(Span),