From 181e1b7137f0529109509c8a8609541705a0ff3b Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Sat, 5 Jul 2025 15:42:09 +1200 Subject: [PATCH 1/2] diag: improve handling of patterns in fn ptr and trait decl --- compiler/rustc_ast_passes/messages.ftl | 2 + .../rustc_ast_passes/src/ast_validation.rs | 7 ++- compiler/rustc_ast_passes/src/errors.rs | 2 + compiler/rustc_parse/messages.ftl | 5 +- compiler/rustc_parse/src/errors.rs | 7 +-- .../rustc_parse/src/parser/diagnostics.rs | 26 ++++++--- compiler/rustc_parse/src/parser/item.rs | 40 ++++++++------ compiler/rustc_parse/src/parser/path.rs | 2 +- tests/ui/error-codes/E0642-2015.fixed | 19 +++++++ tests/ui/error-codes/E0642-2015.rs | 19 +++++++ tests/ui/error-codes/E0642-2015.stderr | 41 ++++++++++++++ tests/ui/error-codes/E0642.fixed | 8 +-- tests/ui/error-codes/E0642.rs | 8 +-- tests/ui/error-codes/E0642.stderr | 32 ++--------- tests/ui/issues/issue-50571.fixed | 2 +- tests/ui/issues/issue-50571.rs | 2 +- tests/ui/issues/issue-50571.stderr | 6 +-- .../macros/no-patterns-in-args-macro.stderr | 12 +++++ tests/ui/parser/self-param-semantic-fail.rs | 6 +-- .../ui/parser/self-param-semantic-fail.stderr | 29 +++------- tests/ui/pattern/no-patterns-in-args-2.stderr | 6 +++ tests/ui/pattern/no-patterns-in-args.rs | 12 ++++- tests/ui/pattern/no-patterns-in-args.stderr | 54 +++++++++++++++++-- 23 files changed, 244 insertions(+), 103 deletions(-) create mode 100644 tests/ui/error-codes/E0642-2015.fixed create mode 100644 tests/ui/error-codes/E0642-2015.rs create mode 100644 tests/ui/error-codes/E0642-2015.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index d58c140c696d8..21b0042267884 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -222,8 +222,10 @@ ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies .label = pattern not allowed in function without body + .suggestion = give this argument a name or use an underscore to ignore it ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types + .suggestion = give this argument a name or use an underscore to ignore it ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 53e2a1c695a8f..ba1df994660b8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -788,8 +788,11 @@ impl<'a> AstValidator<'a> { TyKind::BareFn(bfty) => { self.check_bare_fn_safety(bfty.decl_span, bfty.safety); self.check_fn_decl(&bfty.decl, SelfSemantic::No); - Self::check_decl_no_pat(&bfty.decl, |span, _, _| { - self.dcx().emit_err(errors::PatternFnPointer { span }); + Self::check_decl_no_pat(&bfty.decl, |span, ident, _| { + // `self` in bare fn ptr is already an error; don't add an extra one. + if !ident.is_some_and(|ident| ident.name == kw::SelfLower) { + self.dcx().emit_err(errors::PatternFnPointer { span }); + } }); if let Extern::Implicit(extern_span) = bfty.ext { self.handle_missing_abi(extern_span, ty.id); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index d387a4a310ea0..d2471f76e474b 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -404,6 +404,7 @@ impl Subdiagnostic for EmptyLabelManySpans { #[diag(ast_passes_pattern_in_fn_pointer, code = E0561)] pub(crate) struct PatternFnPointer { #[primary_span] + #[suggestion(code = "_", style = "verbose")] pub span: Span, } @@ -685,6 +686,7 @@ pub(crate) struct PatternInForeign { pub(crate) struct PatternInBodiless { #[primary_span] #[label] + #[suggestion(code = "_", style = "verbose")] pub span: Span, } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index af9f873554919..dfbfb59e80432 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -753,8 +753,9 @@ parse_path_found_c_variadic_params = `Trait(...)` syntax does not support c_vari parse_path_found_named_params = `Trait(...)` syntax does not support named parameters .suggestion = remove the parameter name -parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies - .suggestion = give this argument a name or use an underscore to ignore it +parse_pattern_in_trait_fn_in_2015 = patterns aren't allowed in trait methods in the 2015 edition + .note = upgrading editions will fix this error + .suggestion = in this edition, give this argument a name or use an underscore to ignore it parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@` .label_pattern = pattern on the left, should be on the right diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7f1b0991f0c89..df77b299abafe 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1490,10 +1490,11 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] -#[diag(parse_pattern_method_param_without_body, code = E0642)] -pub(crate) struct PatternMethodParamWithoutBody { +#[diag(parse_pattern_in_trait_fn_in_2015)] +#[note] +pub(crate) struct PatternInTraitFnIn2015 { #[primary_span] - #[suggestion(code = "_", applicability = "machine-applicable", style = "verbose")] + #[suggestion(code = "_", style = "verbose")] pub span: Span, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 1df0ccbd8af76..6f38867a7c6a8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -38,7 +38,7 @@ use crate::errors::{ DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, + IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternInTraitFnIn2015, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, @@ -2346,16 +2346,28 @@ impl<'a> Parser<'a> { None } - pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; + pub(super) fn recover_arg_parse( + &mut self, + emit_error: bool, + ) -> PResult<'a, (P, P)> { + let mut pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; self.expect(exp!(Colon))?; let ty = self.parse_ty()?; - self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span }); + // Don't emit an error if we can emit a better one during AST passes (i.e., with patterns in + // bare fn ptrs). This branch is only missed if are guaranteed to emit an error later. + if emit_error { + self.dcx().emit_err(PatternInTraitFnIn2015 { span: pat.span }); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + pat = P(Pat { + kind: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID, + tokens: None, + }); + } - // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. - let pat = - P(Pat { kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID, tokens: None }); Ok((pat, ty)) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9ed7124a11c38..134a00d9db27a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2932,6 +2932,8 @@ impl<'a> Parser<'a> { /// Parses the parameter list of a function, including the `(` and `)` delimiters. pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec> { let mut first_param = true; + let is_bare_fn_ptr = self.prev_token.is_keyword(kw::Fn); + // Parse the arguments, starting out with `self` being allowed... if self.token != TokenKind::OpenParen // might be typo'd trait impl, handled elsewhere @@ -2946,22 +2948,23 @@ 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(req_name, first_param, true).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. - // For example when parsing `*mut Self` in function `fn oof(*mut Self)`. - let lo = if let TokenKind::OpenParen = p.prev_token.kind { - p.prev_token.span.shrink_to_hi() - } else { - p.prev_token.span - }; - p.restore_snapshot(snapshot); - // Skip every token until next possible arg or end. - p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]); - // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar)) - }); + let param = + p.parse_param_general(req_name, first_param, true, is_bare_fn_ptr).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. + // For example when parsing `*mut Self` in function `fn oof(*mut Self)`. + let lo = if let TokenKind::OpenParen = p.prev_token.kind { + p.prev_token.span.shrink_to_hi() + } else { + p.prev_token.span + }; + p.restore_snapshot(snapshot); + // Skip every token until next possible arg or end. + p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]); + // Create a placeholder argument for proper arg count (issue #34264). + Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar)) + }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; param @@ -2975,11 +2978,13 @@ impl<'a> Parser<'a> { /// /// - `self` is syntactically allowed when `first_param` holds. /// - `recover_arg_parse` is used to recover from a failed argument parse. + /// - `is_bare_fn_ptr` is used to improve diagnostics for bare fn ptrs. pub(super) fn parse_param_general( &mut self, req_name: ReqName, first_param: bool, recover_arg_parse: bool, + is_bare_fn_ptr: bool, ) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; @@ -3040,6 +3045,7 @@ impl<'a> Parser<'a> { ty = this.unexpected_any(); } } + match ty { Ok(ty) => { let pat = this.mk_pat(ty.span, PatKind::Missing); @@ -3052,7 +3058,7 @@ impl<'a> Parser<'a> { // 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()? + this.recover_arg_parse(!is_bare_fn_ptr)? } Err(err) => return Err(err), } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1f4049f197fa8..cddacf0b1a262 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -400,7 +400,7 @@ impl<'a> Parser<'a> { let dcx = self.dcx(); let parse_params_result = self.parse_paren_comma_seq(|p| { - let param = p.parse_param_general(|_| false, false, false); + let param = p.parse_param_general(|_| false, false, false, false); param.map(move |param| { if !matches!(param.pat.kind, PatKind::Missing) { dcx.emit_err(FnPathFoundNamedParams { diff --git a/tests/ui/error-codes/E0642-2015.fixed b/tests/ui/error-codes/E0642-2015.fixed new file mode 100644 index 0000000000000..40957641a672a --- /dev/null +++ b/tests/ui/error-codes/E0642-2015.fixed @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![allow(unused)] // for rustfix + +#[derive(Clone, Copy)] +struct S; + +trait T { + fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + + fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + fn method(_: S) {} //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + + fn f(&ident: &S) {} // ok + fn g(&&ident: &&S) {} // ok + fn h(mut ident: S) {} // ok +} + +fn main() {} diff --git a/tests/ui/error-codes/E0642-2015.rs b/tests/ui/error-codes/E0642-2015.rs new file mode 100644 index 0000000000000..8962b28641b83 --- /dev/null +++ b/tests/ui/error-codes/E0642-2015.rs @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![allow(unused)] // for rustfix + +#[derive(Clone, Copy)] +struct S; + +trait T { + fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + + fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + fn method(S { .. }: S) {} //~ ERROR patterns aren't allowed in trait methods in the 2015 edition + + fn f(&ident: &S) {} // ok + fn g(&&ident: &&S) {} // ok + fn h(mut ident: S) {} // ok +} + +fn main() {} diff --git a/tests/ui/error-codes/E0642-2015.stderr b/tests/ui/error-codes/E0642-2015.stderr new file mode 100644 index 0000000000000..a7b7a23d227f9 --- /dev/null +++ b/tests/ui/error-codes/E0642-2015.stderr @@ -0,0 +1,41 @@ +error: patterns aren't allowed in trait methods in the 2015 edition + --> $DIR/E0642-2015.rs:9:12 + | +LL | fn foo((x, y): (i32, i32)); + | ^^^^^^ + | + = note: upgrading editions will fix this error +help: in this edition, give this argument a name or use an underscore to ignore it + | +LL - fn foo((x, y): (i32, i32)); +LL + fn foo(_: (i32, i32)); + | + +error: patterns aren't allowed in trait methods in the 2015 edition + --> $DIR/E0642-2015.rs:11:12 + | +LL | fn bar((x, y): (i32, i32)) {} + | ^^^^^^ + | + = note: upgrading editions will fix this error +help: in this edition, give this argument a name or use an underscore to ignore it + | +LL - fn bar((x, y): (i32, i32)) {} +LL + fn bar(_: (i32, i32)) {} + | + +error: patterns aren't allowed in trait methods in the 2015 edition + --> $DIR/E0642-2015.rs:12:15 + | +LL | fn method(S { .. }: S) {} + | ^^^^^^^^ + | + = note: upgrading editions will fix this error +help: in this edition, give this argument a name or use an underscore to ignore it + | +LL - fn method(S { .. }: S) {} +LL + fn method(_: S) {} + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/error-codes/E0642.fixed b/tests/ui/error-codes/E0642.fixed index 1b7e0684254a3..e715736ad1951 100644 --- a/tests/ui/error-codes/E0642.fixed +++ b/tests/ui/error-codes/E0642.fixed @@ -1,3 +1,4 @@ +//@ edition:2024 //@ run-rustfix #![allow(unused)] // for rustfix @@ -6,11 +7,10 @@ struct S; trait T { - fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies + fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in functions without bodies [E0642] - fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies - - fn method(_: S) {} //~ ERROR patterns aren't allowed in methods without bodies + fn bar((x, y): (i32, i32)) {} // ok + fn method(S { .. }: S) {} // ok fn f(&ident: &S) {} // ok fn g(&&ident: &&S) {} // ok diff --git a/tests/ui/error-codes/E0642.rs b/tests/ui/error-codes/E0642.rs index ceac23574083c..425accda71518 100644 --- a/tests/ui/error-codes/E0642.rs +++ b/tests/ui/error-codes/E0642.rs @@ -1,3 +1,4 @@ +//@ edition:2024 //@ run-rustfix #![allow(unused)] // for rustfix @@ -6,11 +7,10 @@ struct S; trait T { - fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies + fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in functions without bodies [E0642] - fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies - - fn method(S { .. }: S) {} //~ ERROR patterns aren't allowed in methods without bodies + fn bar((x, y): (i32, i32)) {} // ok + fn method(S { .. }: S) {} // ok fn f(&ident: &S) {} // ok fn g(&&ident: &&S) {} // ok diff --git a/tests/ui/error-codes/E0642.stderr b/tests/ui/error-codes/E0642.stderr index 97309e95b6b49..1824a440e0b80 100644 --- a/tests/ui/error-codes/E0642.stderr +++ b/tests/ui/error-codes/E0642.stderr @@ -1,8 +1,8 @@ -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:9:12 +error[E0642]: patterns aren't allowed in functions without bodies + --> $DIR/E0642.rs:10:12 | LL | fn foo((x, y): (i32, i32)); - | ^^^^^^ + | ^^^^^^ pattern not allowed in function without body | help: give this argument a name or use an underscore to ignore it | @@ -10,30 +10,6 @@ LL - fn foo((x, y): (i32, i32)); LL + fn foo(_: (i32, i32)); | -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:11:12 - | -LL | fn bar((x, y): (i32, i32)) {} - | ^^^^^^ - | -help: give this argument a name or use an underscore to ignore it - | -LL - fn bar((x, y): (i32, i32)) {} -LL + fn bar(_: (i32, i32)) {} - | - -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/E0642.rs:13:15 - | -LL | fn method(S { .. }: S) {} - | ^^^^^^^^ - | -help: give this argument a name or use an underscore to ignore it - | -LL - fn method(S { .. }: S) {} -LL + fn method(_: S) {} - | - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed index 6d73f17cca4ca..80f4f6967427e 100644 --- a/tests/ui/issues/issue-50571.fixed +++ b/tests/ui/issues/issue-50571.fixed @@ -4,7 +4,7 @@ #![allow(dead_code)] trait Foo { fn foo(_: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies + //~^ ERROR: patterns aren't allowed in trait methods in the 2015 edition } fn main() {} diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs index dd840ffe4d170..b3fbc3d32773a 100644 --- a/tests/ui/issues/issue-50571.rs +++ b/tests/ui/issues/issue-50571.rs @@ -4,7 +4,7 @@ #![allow(dead_code)] trait Foo { fn foo([a, b]: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies + //~^ ERROR: patterns aren't allowed in trait methods in the 2015 edition } fn main() {} diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr index 9b00fe0f5db64..5667d78a4d05a 100644 --- a/tests/ui/issues/issue-50571.stderr +++ b/tests/ui/issues/issue-50571.stderr @@ -1,10 +1,11 @@ -error[E0642]: patterns aren't allowed in methods without bodies +error: patterns aren't allowed in trait methods in the 2015 edition --> $DIR/issue-50571.rs:6:12 | LL | fn foo([a, b]: [i32; 2]) {} | ^^^^^^ | -help: give this argument a name or use an underscore to ignore it + = note: upgrading editions will fix this error +help: in this edition, give this argument a name or use an underscore to ignore it | LL - fn foo([a, b]: [i32; 2]) {} LL + fn foo(_: [i32; 2]) {} @@ -12,4 +13,3 @@ LL + fn foo(_: [i32; 2]) {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/macros/no-patterns-in-args-macro.stderr b/tests/ui/macros/no-patterns-in-args-macro.stderr index 0016c7953f344..f7a832e706a8b 100644 --- a/tests/ui/macros/no-patterns-in-args-macro.stderr +++ b/tests/ui/macros/no-patterns-in-args-macro.stderr @@ -3,12 +3,24 @@ error[E0642]: patterns aren't allowed in functions without bodies | LL | m!((bad, pat)); | ^^^^^^^^^^ pattern not allowed in function without body + | +help: give this argument a name or use an underscore to ignore it + | +LL - m!((bad, pat)); +LL + m!(_); + | error[E0561]: patterns aren't allowed in function pointer types --> $DIR/no-patterns-in-args-macro.rs:20:8 | LL | m!((bad, pat)); | ^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - m!((bad, pat)); +LL + m!(_); + | error[E0130]: patterns aren't allowed in foreign function declarations --> $DIR/no-patterns-in-args-macro.rs:20:8 diff --git a/tests/ui/parser/self-param-semantic-fail.rs b/tests/ui/parser/self-param-semantic-fail.rs index 621aab279aa4a..864ec9d389ccc 100644 --- a/tests/ui/parser/self-param-semantic-fail.rs +++ b/tests/ui/parser/self-param-semantic-fail.rs @@ -40,15 +40,14 @@ extern "C" { fn f7(self: u8); //~^ ERROR `self` parameter is only allowed in associated functions fn f8(mut self: u8); -//~^ ERROR `self` parameter is only allowed in associated functions -//~| ERROR patterns aren't allowed in + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR patterns aren't allowed in } type X1 = fn(self); //~^ ERROR `self` parameter is only allowed in associated functions type X2 = fn(mut self); //~^ ERROR `self` parameter is only allowed in associated functions -//~| ERROR patterns aren't allowed in type X3 = fn(&self); //~^ ERROR `self` parameter is only allowed in associated functions type X4 = fn(&mut self); @@ -61,4 +60,3 @@ type X7 = fn(self: u8); //~^ ERROR `self` parameter is only allowed in associated functions type X8 = fn(mut self: u8); //~^ ERROR `self` parameter is only allowed in associated functions -//~| ERROR patterns aren't allowed in diff --git a/tests/ui/parser/self-param-semantic-fail.stderr b/tests/ui/parser/self-param-semantic-fail.stderr index e5d679773696b..1ff586dbef9c9 100644 --- a/tests/ui/parser/self-param-semantic-fail.stderr +++ b/tests/ui/parser/self-param-semantic-fail.stderr @@ -154,14 +154,8 @@ LL | type X2 = fn(mut self); | = note: associated functions are those in `impl` or `trait` definitions -error[E0561]: patterns aren't allowed in function pointer types - --> $DIR/self-param-semantic-fail.rs:49:14 - | -LL | type X2 = fn(mut self); - | ^^^^^^^^ - error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:52:14 + --> $DIR/self-param-semantic-fail.rs:51:14 | LL | type X3 = fn(&self); | ^^^^^ not semantically valid as function parameter @@ -169,7 +163,7 @@ LL | type X3 = fn(&self); = note: associated functions are those in `impl` or `trait` definitions error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:54:14 + --> $DIR/self-param-semantic-fail.rs:53:14 | LL | type X4 = fn(&mut self); | ^^^^^^^^^ not semantically valid as function parameter @@ -177,7 +171,7 @@ LL | type X4 = fn(&mut self); = note: associated functions are those in `impl` or `trait` definitions error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:56:22 + --> $DIR/self-param-semantic-fail.rs:55:22 | LL | type X5 = for<'a> fn(&'a self); | ^^^^^^^^ not semantically valid as function parameter @@ -185,7 +179,7 @@ LL | type X5 = for<'a> fn(&'a self); = note: associated functions are those in `impl` or `trait` definitions error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:58:22 + --> $DIR/self-param-semantic-fail.rs:57:22 | LL | type X6 = for<'a> fn(&'a mut self); | ^^^^^^^^^^^^ not semantically valid as function parameter @@ -193,7 +187,7 @@ LL | type X6 = for<'a> fn(&'a mut self); = note: associated functions are those in `impl` or `trait` definitions error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:60:14 + --> $DIR/self-param-semantic-fail.rs:59:14 | LL | type X7 = fn(self: u8); | ^^^^ not semantically valid as function parameter @@ -201,20 +195,13 @@ LL | type X7 = fn(self: u8); = note: associated functions are those in `impl` or `trait` definitions error: `self` parameter is only allowed in associated functions - --> $DIR/self-param-semantic-fail.rs:62:14 + --> $DIR/self-param-semantic-fail.rs:61:14 | LL | type X8 = fn(mut self: u8); | ^^^^^^^^ not semantically valid as function parameter | = note: associated functions are those in `impl` or `trait` definitions -error[E0561]: patterns aren't allowed in function pointer types - --> $DIR/self-param-semantic-fail.rs:62:14 - | -LL | type X8 = fn(mut self: u8); - | ^^^^^^^^ - -error: aborting due to 28 previous errors +error: aborting due to 26 previous errors -Some errors have detailed explanations: E0130, E0561. -For more information about an error, try `rustc --explain E0130`. +For more information about this error, try `rustc --explain E0130`. diff --git a/tests/ui/pattern/no-patterns-in-args-2.stderr b/tests/ui/pattern/no-patterns-in-args-2.stderr index 6adcbb9dccd82..d7275a7e691a8 100644 --- a/tests/ui/pattern/no-patterns-in-args-2.stderr +++ b/tests/ui/pattern/no-patterns-in-args-2.stderr @@ -3,6 +3,12 @@ error[E0642]: patterns aren't allowed in functions without bodies | LL | fn f2(&arg: u8); | ^^^^ pattern not allowed in function without body + | +help: give this argument a name or use an underscore to ignore it + | +LL - fn f2(&arg: u8); +LL + fn f2(_: u8); + | error: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-2.rs:4:11 diff --git a/tests/ui/pattern/no-patterns-in-args.rs b/tests/ui/pattern/no-patterns-in-args.rs index 54836b0a3f538..78e6abc2b8aef 100644 --- a/tests/ui/pattern/no-patterns-in-args.rs +++ b/tests/ui/pattern/no-patterns-in-args.rs @@ -7,8 +7,16 @@ extern "C" { // fn g3(u8); // Not yet } -type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types -type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types +struct Foo { + bar: u32 +} + +type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types [E0561] +type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types [E0561] +type A3 = fn(&_: ()); //~ ERROR patterns aren't allowed in function pointer types [E0561] +type A4 = fn((): ()); //~ ERROR patterns aren't allowed in function pointer types [E0561] +type A5 = fn(Foo { bar }: Foo); //~ ERROR patterns aren't allowed in function pointer types [E0561] + type B1 = fn(arg: u8); // OK type B2 = fn(_: u8); // OK type B3 = fn(u8); // OK diff --git a/tests/ui/pattern/no-patterns-in-args.stderr b/tests/ui/pattern/no-patterns-in-args.stderr index 1c2ce86646787..bdb1486b5f746 100644 --- a/tests/ui/pattern/no-patterns-in-args.stderr +++ b/tests/ui/pattern/no-patterns-in-args.stderr @@ -17,18 +17,66 @@ LL | fn f3(arg @ _: u8); | ^^^^^^^ pattern not allowed in foreign function error[E0561]: patterns aren't allowed in function pointer types - --> $DIR/no-patterns-in-args.rs:10:14 + --> $DIR/no-patterns-in-args.rs:14:14 | LL | type A1 = fn(mut arg: u8); | ^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - type A1 = fn(mut arg: u8); +LL + type A1 = fn(_: u8); + | error[E0561]: patterns aren't allowed in function pointer types - --> $DIR/no-patterns-in-args.rs:11:14 + --> $DIR/no-patterns-in-args.rs:15:14 | LL | type A2 = fn(&arg: u8); | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - type A2 = fn(&arg: u8); +LL + type A2 = fn(_: u8); + | + +error[E0561]: patterns aren't allowed in function pointer types + --> $DIR/no-patterns-in-args.rs:16:14 + | +LL | type A3 = fn(&_: ()); + | ^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - type A3 = fn(&_: ()); +LL + type A3 = fn(_: ()); + | + +error[E0561]: patterns aren't allowed in function pointer types + --> $DIR/no-patterns-in-args.rs:17:14 + | +LL | type A4 = fn((): ()); + | ^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - type A4 = fn((): ()); +LL + type A4 = fn(_: ()); + | + +error[E0561]: patterns aren't allowed in function pointer types + --> $DIR/no-patterns-in-args.rs:18:14 + | +LL | type A5 = fn(Foo { bar }: Foo); + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - type A5 = fn(Foo { bar }: Foo); +LL + type A5 = fn(_: Foo); + | -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0130, E0561. For more information about an error, try `rustc --explain E0130`. From 038c8d4307fc1255a2e3b9a4b76820457694b789 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Sat, 5 Jul 2025 15:57:15 +1200 Subject: [PATCH 2/2] rustc_error_codes: improve docs for E0642 --- .../rustc_error_codes/src/error_codes/E0642.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0642.md b/compiler/rustc_error_codes/src/error_codes/E0642.md index c790aa154bde9..26585de06c45e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0642.md +++ b/compiler/rustc_error_codes/src/error_codes/E0642.md @@ -1,8 +1,12 @@ -Trait methods currently cannot take patterns as arguments. +Trait methods cannot take patterns as arguments. + +Traits cannot control the way in which implementations take arguments, only the +types of those arguments. A pattern here has no effect, because the +implementation can bind its arguments however it would like. Erroneous code example: -```compile_fail,E0642 +```compile_fail,E0642,edition2024 trait Foo { fn foo((x, y): (i32, i32)); // error: patterns aren't allowed // in trait methods @@ -16,3 +20,9 @@ trait Foo { fn foo(x_and_y: (i32, i32)); // ok! } ``` + +And you can use patterns in its implementations: + +impl Foo for Bar { + fn foo((x, y): (i32, i32)) { /* ... */ } // ok! +}