Skip to content

Parser: Recover error from named params while parse_path #140671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,16 @@ parse_parenthesized_lifetime_suggestion = remove the parentheses
parse_path_double_colon = path separator must be a double colon
.suggestion = use a double colon instead
parse_path_found_attribute_in_params = `Trait(...)` syntax does not support attributes in parameters
.suggestion = remove the attributes
parse_path_found_c_variadic_params = `Trait(...)` syntax does not support c_variadic parameters
.suggestion = remove the `...`
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
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,30 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
pub fn_token_span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_path_found_named_params)]
pub(crate) struct FnPathFoundNamedParams {
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = "")]
pub named_param_span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_path_found_c_variadic_params)]
pub(crate) struct PathFoundCVariadicParams {
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = "")]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_path_found_attribute_in_params)]
pub(crate) struct PathFoundAttributeInParams {
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = "")]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_path_double_colon)]
pub(crate) struct PathSingleColon {
Expand Down
15 changes: 11 additions & 4 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2894,7 +2894,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(req_name, first_param).or_else(|e| {
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.
Expand Down Expand Up @@ -2922,7 +2922,13 @@ impl<'a> Parser<'a> {
/// Parses a single function parameter.
///
/// - `self` is syntactically allowed when `first_param` holds.
fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
/// - `recover_arg_parse` is used to recover from a failed argument parse.
pub(super) fn parse_param_general(
&mut self,
req_name: ReqName,
first_param: bool,
recover_arg_parse: bool,
) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
Expand Down Expand Up @@ -2990,12 +2996,13 @@ 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),
// Recover from attempting to parse the argument as a type without pattern.
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()?
}
Err(err) => return Err(err),
}
};

Expand Down
34 changes: 31 additions & 3 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ use rustc_ast::{
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
use rustc_errors::{Applicability, Diag, PResult};
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, PResult};
use rustc_span::{BytePos, Ident, Span, kw, sym};
use thin_vec::ThinVec;
use tracing::debug;

use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
use crate::errors::{self, PathSingleColon, PathTripleColon};
use crate::ast::{PatKind, Ty, TyKind};
use crate::errors::{
self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams,
PathSingleColon, PathTripleColon,
};
use crate::exp;
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};

Expand Down Expand Up @@ -396,7 +400,31 @@ impl<'a> Parser<'a> {
snapshot = Some(self.create_snapshot_for_diagnostic());
}

let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) {
let parse_type_params =
|p: &mut Parser<'a>, dcx: &mut DiagCtxtHandle<'a>| -> PResult<'a, P<Ty>> {
let param = p.parse_param_general(|_| false, false, false);
param.map(move |param| {
if !matches!(param.pat.kind, PatKind::Missing) {
dcx.emit_err(FnPathFoundNamedParams {
named_param_span: param.pat.span,
});
}
if matches!(param.ty.kind, TyKind::CVarArgs) {
dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span });
}
if !param.attrs.is_empty() {
dcx.emit_err(PathFoundAttributeInParams {
span: param.attrs[0].span,
});
}
param.ty
})
};

let mut dcx = self.dcx();
let (inputs, _) = match self
.parse_paren_comma_seq(|p| parse_type_params(p, &mut dcx))
{
Ok(output) => output,
Err(mut error) if prev_token_before_parsing == token::PathSep => {
error.span_label(
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/fn/fn-trait-use-named-params-issue-140169.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn f1(_: fn(a: u8)) {}
fn f2(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters
fn f3(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters
fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
//~^ ERROR `Trait(...)` syntax does not support named parameters
//~| ERROR `Trait(...)` syntax does not support named parameters
fn f5(_: impl Fn(u8, ...)) {}
//~^ ERROR `Trait(...)` syntax does not support c_variadic parameters
fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {}
//~^ ERROR `Trait(...)` syntax does not support attributes in parameters

fn main(){}
38 changes: 38 additions & 0 deletions tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
error: `Trait(...)` syntax does not support named parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:2:22
|
LL | fn f2(_: impl Fn(u8, vvvv: u8)) {}
| ^^^^ help: remove the parameter name

error: `Trait(...)` syntax does not support named parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:3:18
|
LL | fn f3(_: impl Fn(aaaa: u8, u8)) {}
| ^^^^ help: remove the parameter name

error: `Trait(...)` syntax does not support named parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:4:18
|
LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
| ^^^^ help: remove the parameter name

error: `Trait(...)` syntax does not support named parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:4:28
|
LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {}
| ^^^^ help: remove the parameter name

error: `Trait(...)` syntax does not support c_variadic parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:7:22
|
LL | fn f5(_: impl Fn(u8, ...)) {}
| ^^^ help: remove the `...`

error: `Trait(...)` syntax does not support attributes in parameters
--> $DIR/fn-trait-use-named-params-issue-140169.rs:9:22
|
LL | fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attributes

error: aborting due to 6 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

fn main() {
unsafe {
dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
//~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
//~| NOTE while parsing this parenthesized list of type arguments starting here
dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR `Trait(...)` syntax does not support named parameters
//~^ ERROR cannot find function `dealloc` in this scope [E0425]
//~| ERROR cannot find value `ptr2` in this scope [E0425]
//~| ERROR the `!` type is experimental [E0658]
//~| ERROR cannot find function, tuple struct or tuple variant `Layout` in this scope [E0425]
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:33
error: `Trait(...)` syntax does not support named parameters
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:32
|
LL | dealloc(ptr2, Layout::(x: !)(1, 1));
| --- ^ expected one of 7 possible tokens
| |
| while parsing this parenthesized list of type arguments starting here
| ^ help: remove the parameter name

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:43
error[E0425]: cannot find function `dealloc` in this scope
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:9
|
LL | dealloc(ptr2, Layout::(x: !)(1, 1));
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
| ^^^^^^^ not found in this scope
|
help: consider importing this function
|
LL + use std::alloc::dealloc;
|

error[E0425]: cannot find value `ptr2` in this scope
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:17
|
LL | dealloc(ptr2, Layout::(x: !)(1, 1));
| ^^^^ not found in this scope

error[E0658]: the `!` type is experimental
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:35
|
LL | dealloc(ptr2, Layout::(x: !)(1, 1));
| ^
|
= note: see issue #35121 <https://github.com/rust-lang/rust/issues/35121> for more information
= help: add `#![feature(never_type)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0425]: cannot find function, tuple struct or tuple variant `Layout` in this scope
--> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:23
|
LL | dealloc(ptr2, Layout::(x: !)(1, 1));
| ^^^^^^ not found in this scope

error: aborting due to 2 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0425, E0658.
For more information about an error, try `rustc --explain E0425`.
5 changes: 1 addition & 4 deletions tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@

struct Apple((Apple, Option(Banana ? Citron)));
//~^ ERROR invalid `?` in type
//~| ERROR expected one of `)` or `,`, found `Citron`
//~| ERROR cannot find type `Citron` in this scope [E0412]
//~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214]
//~| ERROR `Apple` has infinite size
//~| ERROR unexpected token: `Citron`
39 changes: 3 additions & 36 deletions tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,11 @@ LL - struct Apple((Apple, Option(Banana ? Citron)));
LL + struct Apple((Apple, Option(Option<Banana > Citron)));
|

error: expected one of `)` or `,`, found `Citron`
error: unexpected token: `Citron`
--> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
|
LL | struct Apple((Apple, Option(Banana ? Citron)));
| -^^^^^^ expected one of `)` or `,`
| |
| help: missing `,`
| ^^^^^^ unexpected token after this

error[E0412]: cannot find type `Citron` in this scope
--> $DIR/issue-103748-ICE-wrong-braces.rs:3:38
|
LL | struct Apple((Apple, Option(Banana ? Citron)));
| ^^^^^^ not found in this scope

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-103748-ICE-wrong-braces.rs:3:22
|
LL | struct Apple((Apple, Option(Banana ? Citron)));
| ^^^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
|
help: use angle brackets instead
|
LL - struct Apple((Apple, Option(Banana ? Citron)));
LL + struct Apple((Apple, Option<Banana ? Citron>));
|

error[E0072]: recursive type `Apple` has infinite size
--> $DIR/issue-103748-ICE-wrong-braces.rs:3:1
|
LL | struct Apple((Apple, Option(Banana ? Citron)));
| ^^^^^^^^^^^^ ----- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
LL | struct Apple((Box<Apple>, Option(Banana ? Citron)));
| ++++ +

error: aborting due to 5 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0072, E0214, E0412.
For more information about an error, try `rustc --explain E0072`.
Loading