diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 238eebd73a0fa..371604b88ef2b 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -1843,7 +1843,7 @@ pub(crate) struct AttributeOnEmptyType { } #[derive(Diagnostic)] -#[diag("patterns aren't allowed in methods without bodies", code = E0642)] +#[diag("patterns aren't allowed in {$target}", code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] #[suggestion( @@ -1853,6 +1853,7 @@ pub(crate) struct PatternMethodParamWithoutBody { style = "verbose" )] pub span: Span, + pub target: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 1c99c2c2dae1e..6176784b3bbe3 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2385,12 +2385,22 @@ impl<'a> Parser<'a> { } #[cold] - pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (Box, Box)> { + pub(super) fn recover_arg_parse( + &mut self, + context: FnContext, + ) -> PResult<'a, (Box, Box)> { let 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 }); + self.dcx().emit_err(PatternMethodParamWithoutBody { + span: pat.span, + target: match context { + FnContext::Trait => "methods without bodies", + FnContext::FunctionPtrType => "function pointer types", + 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"), + }, + }); // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. let pat = Box::new(Pat { kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID }); diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index c7eb84f553614..1523aba4be9ab 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -101,6 +101,8 @@ pub(crate) struct FnParseMode { pub(crate) enum FnContext { /// Free context. Free, + /// A Function Pointer Type `fn(..)`. + FunctionPtrType, /// A Trait context. Trait, /// An Impl block. @@ -818,7 +820,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(fn_parse_mode.context)? } Err(err) => return Err(err), } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b975e01796b89..98593c3c303c2 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -882,7 +882,7 @@ impl<'a> Parser<'a> { } let mode = crate::parser::FnParseMode { req_name: |_, _| false, - context: FnContext::Free, + context: FnContext::FunctionPtrType, req_body: false, }; let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?; diff --git a/tests/ui/fn/fn-ptr-pattern.rs b/tests/ui/fn/fn-ptr-pattern.rs new file mode 100644 index 0000000000000..017356d561915 --- /dev/null +++ b/tests/ui/fn/fn-ptr-pattern.rs @@ -0,0 +1,28 @@ +fn patterns( + pat1: fn(true: bool), + //~^ ERROR patterns aren't allowed in function pointer types + pat2: fn(1..3: bool), + //~^ ERROR patterns aren't allowed in function pointer types + pat3: fn((x, y): (bool, bool)), + //~^ ERROR patterns aren't allowed in function pointer types + pat4: fn(self), + //~^ ERROR `self` parameter is only allowed in associated functions + pat5: fn(self, self), + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR unexpected `self` parameter in function + pat6: fn(bool, self), + //~^ ERROR unexpected `self` parameter in function + pat7: fn(Thing { a, b }: Thing), + //~^ ERROR patterns aren't allowed in function pointer types + pat8: fn(NoThing { a, b }: NoThing), + //~^ ERROR patterns aren't allowed in function pointer types + //~| ERROR cannot find type `NoThing` in this scope + pat9: fn((((((x))))): bool), + //~^ ERROR patterns aren't allowed in function pointer types +) { } + +struct Thing { a: bool, b: bool } + +fn main() { + +} diff --git a/tests/ui/fn/fn-ptr-pattern.stderr b/tests/ui/fn/fn-ptr-pattern.stderr new file mode 100644 index 0000000000000..99d890cbbc9dc --- /dev/null +++ b/tests/ui/fn/fn-ptr-pattern.stderr @@ -0,0 +1,113 @@ +error[E0642]: patterns aren't allowed in function pointer types + --> $DIR/fn-ptr-pattern.rs:4:14 + | +LL | pat2: fn(1..3: bool), + | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat2: fn(1..3: bool), +LL + pat2: fn(_: bool), + | + +error[E0642]: patterns aren't allowed in function pointer types + --> $DIR/fn-ptr-pattern.rs:6:14 + | +LL | pat3: fn((x, y): (bool, bool)), + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat3: fn((x, y): (bool, bool)), +LL + pat3: fn(_: (bool, bool)), + | + +error: unexpected `self` parameter in function + --> $DIR/fn-ptr-pattern.rs:10:20 + | +LL | pat5: fn(self, self), + | ^^^^ must be the first parameter of an associated function + +error: unexpected `self` parameter in function + --> $DIR/fn-ptr-pattern.rs:13:20 + | +LL | pat6: 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:15:14 + | +LL | pat7: fn(Thing { a, b }: Thing), + | ^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat7: fn(Thing { a, b }: Thing), +LL + pat7: fn(_: Thing), + | + +error[E0642]: patterns aren't allowed in function pointer types + --> $DIR/fn-ptr-pattern.rs:17:14 + | +LL | pat8: fn(NoThing { a, b }: NoThing), + | ^^^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat8: fn(NoThing { a, b }: NoThing), +LL + pat8: fn(_: NoThing), + | + +error[E0642]: patterns aren't allowed in function pointer types + --> $DIR/fn-ptr-pattern.rs:20:14 + | +LL | pat9: fn((((((x))))): bool), + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat9: fn((((((x))))): bool), +LL + pat9: fn(_: bool), + | + +error[E0561]: patterns aren't allowed in function pointer types + --> $DIR/fn-ptr-pattern.rs:2:14 + | +LL | pat1: fn(true: bool), + | ^^^^ + +error: `self` parameter is only allowed in associated functions + --> $DIR/fn-ptr-pattern.rs:8:14 + | +LL | pat4: 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/fn-ptr-pattern.rs:10:14 + | +LL | pat5: 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/fn-ptr-pattern.rs:17:32 + | +LL | pat8: fn(NoThing { a, b }: NoThing), + | ^^^^^^^ +... +LL | struct Thing { a: bool, b: bool } + | ------------ similarly named struct `Thing` defined here + | +help: a struct with a similar name exists + | +LL - pat8: fn(NoThing { a, b }: NoThing), +LL + pat8: fn(NoThing { a, b }: Thing), + | + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0425, E0561, E0642. +For more information about an error, try `rustc --explain E0425`.