From ea57134607b31733d507bc9289033064fa8b6cb5 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 28 Oct 2018 11:38:50 -0700 Subject: Produce targeted diagnostic when using doc comments on fn args Before parsing argument names and types, try to consume an incorrectly included doc comment or attribute in order to recover and continue parsing the rest of the fn definition. --- src/libsyntax/parse/parser.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 589b3e30fcf..3056d1c545c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1789,6 +1789,35 @@ impl<'a> Parser<'a> { self.look_ahead(offset + 1, |t| t == &token::Colon) } + /// Skip unexpected attributes and doc comments in this position and emit an appropriate error. + fn eat_incorrect_doc_comment(&mut self, applied_to: &str) { + if let token::DocComment(_) = self.token { + let mut err = self.diagnostic().struct_span_err( + self.span, + &format!("documentation comments cannot be applied to {}", applied_to), + ); + err.span_label(self.span, "doc comments are not allowed here"); + err.emit(); + self.bump(); + } else if self.token == token::Pound && self.look_ahead(1, |t| { + *t == token::OpenDelim(token::Bracket) + }) { + let lo = self.span; + // Skip every token until next possible arg. + while self.token != token::CloseDelim(token::Bracket) { + self.bump(); + } + let sp = lo.to(self.span); + self.bump(); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("attributes cannot be applied to {}", applied_to), + ); + err.span_label(sp, "attributes are not allowed here"); + err.emit(); + } + } + /// This version of parse arg doesn't necessarily require /// identifier names. fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { @@ -1797,7 +1826,11 @@ impl<'a> Parser<'a> { let (pat, ty) = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{})", require_name); - let pat = self.parse_pat()?; + self.eat_incorrect_doc_comment("method arguments"); + let pat = self.parse_pat().map_err(|mut err| { + err.span_label(self.span, "expected argument name"); + err + })?; if let Err(mut err) = self.expect(&token::Colon) { // If we find a pattern followed by an identifier, it could be an (incorrect) @@ -1819,10 +1852,12 @@ impl<'a> Parser<'a> { return Err(err); } + self.eat_incorrect_doc_comment("a method argument's type"); (pat, self.parse_ty()?) } else { debug!("parse_arg_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); + self.eat_incorrect_doc_comment("a method argument's type"); let mut ty = self.parse_ty(); if ty.is_ok() && self.token == token::Colon { // This wasn't actually a type, but a pattern looking like a type, -- cgit 1.4.1-3-g733a5 From d491734b15692038b963fd1bfeaaf39be393b638 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 28 Oct 2018 11:41:23 -0700 Subject: Point at `match` when a parse failure ocurrs inside of it --- src/libsyntax/parse/parser.rs | 6 +++++- src/test/ui/label/label_break_value_illegal_uses.stderr | 4 +++- src/test/ui/parser/match-refactor-to-expr.rs | 2 +- src/test/ui/parser/match-refactor-to-expr.stderr | 7 +++++-- src/test/ui/try-block/try-block-in-match.stderr | 4 +++- 5 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3056d1c545c..5ab0d8166b0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2474,7 +2474,11 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } if self.eat_keyword(keywords::Match) { - return self.parse_match_expr(attrs); + let match_sp = self.prev_span; + return self.parse_match_expr(attrs).map_err(|mut err| { + err.span_label(match_sp, "while parsing this match expression"); + err + }); } if self.eat_keyword(keywords::Unsafe) { return self.parse_block_expr( diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index 0ab1ad2c242..7711b51a5c9 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -25,7 +25,9 @@ error: expected one of `.`, `?`, `{`, or an operator, found `'b` --> $DIR/label_break_value_illegal_uses.rs:28:17 | LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator - | ^^ expected one of `.`, `?`, `{`, or an operator here + | ----- ^^ expected one of `.`, `?`, `{`, or an operator here + | | + | while parsing this match expression error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/match-refactor-to-expr.rs b/src/test/ui/parser/match-refactor-to-expr.rs index 3c88608697a..014dba3d4d0 100644 --- a/src/test/ui/parser/match-refactor-to-expr.rs +++ b/src/test/ui/parser/match-refactor-to-expr.rs @@ -12,7 +12,7 @@ fn main() { let foo = - match + match //~ NOTE while parsing this match expression Some(4).unwrap_or_else(5) //~^ NOTE expected one of `.`, `?`, `{`, or an operator here ; //~ NOTE unexpected token diff --git a/src/test/ui/parser/match-refactor-to-expr.stderr b/src/test/ui/parser/match-refactor-to-expr.stderr index ecca781684c..2ffbddd570f 100644 --- a/src/test/ui/parser/match-refactor-to-expr.stderr +++ b/src/test/ui/parser/match-refactor-to-expr.stderr @@ -1,8 +1,11 @@ error: expected one of `.`, `?`, `{`, or an operator, found `;` --> $DIR/match-refactor-to-expr.rs:18:9 | -LL | match - | ----- help: try removing this `match` +LL | match //~ NOTE while parsing this match expression + | ----- + | | + | while parsing this match expression + | help: try removing this `match` LL | Some(4).unwrap_or_else(5) | - expected one of `.`, `?`, `{`, or an operator here LL | //~^ NOTE expected one of `.`, `?`, `{`, or an operator here diff --git a/src/test/ui/try-block/try-block-in-match.stderr b/src/test/ui/try-block/try-block-in-match.stderr index f07d23885ac..c9b43000877 100644 --- a/src/test/ui/try-block/try-block-in-match.stderr +++ b/src/test/ui/try-block/try-block-in-match.stderr @@ -2,7 +2,9 @@ error: expected expression, found reserved keyword `try` --> $DIR/try-block-in-match.rs:16:11 | LL | match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try` - | ^^^ expected expression + | ----- ^^^ expected expression + | | + | while parsing this match expression error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From adb96ec64b8d5e8cff191315668a5bfe0480909c Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 28 Oct 2018 11:54:31 -0700 Subject: Provide specific label for patern parsing error --- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 42 +++++++++++++++----------- src/libsyntax/util/parser_testing.rs | 2 +- src/test/ui/parser/issue-33413.rs | 3 +- src/test/ui/parser/issue-33413.stderr | 9 ++---- src/test/ui/parser/lifetime-in-pattern.stderr | 5 +-- src/test/ui/parser/removed-syntax-mode.rs | 3 +- src/test/ui/parser/removed-syntax-mode.stderr | 9 ++---- src/test/ui/self/self-vs-path-ambiguity.stderr | 5 +-- 11 files changed, 40 insertions(+), 44 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 33b651e1b38..84e40a7e403 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1030,7 +1030,7 @@ impl<'a> Parser<'a> { } }, AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?), - AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?), + AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?), }) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 62bc9fae3b5..37800a334c6 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -419,7 +419,7 @@ pub fn parse_item_panic(parser: &mut Parser) -> Option> { } pub fn parse_pat_panic(parser: &mut Parser) -> P { - panictry!(parser.parse_pat()) + panictry!(parser.parse_pat(None)) } pub fn parse_arm_panic(parser: &mut Parser) -> Arm { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 03a8376e763..d6c95a3d7c8 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -881,7 +881,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { FatalError.raise(); } }, - "pat" => token::NtPat(panictry!(p.parse_pat())), + "pat" => token::NtPat(panictry!(p.parse_pat(None))), "expr" => token::NtExpr(panictry!(p.parse_expr())), "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())), "ty" => token::NtTy(panictry!(p.parse_ty())), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5ab0d8166b0..d700e6066cb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1827,10 +1827,7 @@ impl<'a> Parser<'a> { debug!("parse_arg_general parse_pat (require_name:{})", require_name); self.eat_incorrect_doc_comment("method arguments"); - let pat = self.parse_pat().map_err(|mut err| { - err.span_label(self.span, "expected argument name"); - err - })?; + let pat = self.parse_pat(Some("argument name"))?; if let Err(mut err) = self.expect(&token::Colon) { // If we find a pattern followed by an identifier, it could be an (incorrect) @@ -1879,7 +1876,7 @@ impl<'a> Parser<'a> { // Recover from attempting to parse the argument as a type without pattern. err.cancel(); mem::replace(self, parser_snapshot_before_ty); - let pat = self.parse_pat()?; + let pat = self.parse_pat(Some("argument name"))?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1917,7 +1914,7 @@ impl<'a> Parser<'a> { /// Parse an argument in a lambda header e.g. |arg, arg| fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { - let pat = self.parse_pat()?; + let pat = self.parse_pat(Some("argument name"))?; let t = if self.eat(&token::Colon) { self.parse_ty()? } else { @@ -3784,7 +3781,7 @@ impl<'a> Parser<'a> { "`..` can only be used once per tuple or tuple struct pattern"); } } else if !self.check(&token::CloseDelim(token::Paren)) { - fields.push(self.parse_pat()?); + fields.push(self.parse_pat(None)?); } else { break } @@ -3840,7 +3837,7 @@ impl<'a> Parser<'a> { } } - let subpat = self.parse_pat()?; + let subpat = self.parse_pat(None)?; if before_slice && self.eat(&token::DotDot) { slice = Some(subpat); before_slice = false; @@ -3865,7 +3862,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat()?; + let pat = self.parse_pat(None)?; hi = pat.span; (pat, fieldname, false) } else { @@ -4067,7 +4064,7 @@ impl<'a> Parser<'a> { /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast /// to subpatterns within such). fn parse_top_level_pat(&mut self) -> PResult<'a, P> { - let pat = self.parse_pat()?; + let pat = self.parse_pat(None)?; if self.token == token::Comma { // An unexpected comma after a top-level pattern is a clue that the // user (perhaps more accustomed to some other language) forgot the @@ -4099,13 +4096,17 @@ impl<'a> Parser<'a> { } /// Parse a pattern. - pub fn parse_pat(&mut self) -> PResult<'a, P> { - self.parse_pat_with_range_pat(true) + pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P> { + self.parse_pat_with_range_pat(true, expected) } /// Parse a pattern, with a setting whether modern range patterns e.g. `a..=b`, `a..b` are /// allowed. - fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P> { + fn parse_pat_with_range_pat( + &mut self, + allow_range_pat: bool, + expected: Option<&'static str>, + ) -> PResult<'a, P> { maybe_whole!(self, NtPat, |x| x); let lo = self.span; @@ -4121,7 +4122,7 @@ impl<'a> Parser<'a> { err.span_label(self.span, "unexpected lifetime"); return Err(err); } - let subpat = self.parse_pat_with_range_pat(false)?; + let subpat = self.parse_pat_with_range_pat(false, expected)?; pat = PatKind::Ref(subpat, mutbl); } token::OpenDelim(token::Paren) => { @@ -4167,7 +4168,7 @@ impl<'a> Parser<'a> { pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; } else if self.eat_keyword(keywords::Box) { // Parse box pat - let subpat = self.parse_pat_with_range_pat(false)?; + let subpat = self.parse_pat_with_range_pat(false, None)?; pat = PatKind::Box(subpat); } else if self.token.is_ident() && !self.token.is_reserved_ident() && self.parse_as_ident() { @@ -4267,9 +4268,14 @@ impl<'a> Parser<'a> { } Err(mut err) => { self.cancel(&mut err); - let msg = format!("expected pattern, found {}", self.this_token_descr()); + let expected = expected.unwrap_or("pattern"); + let msg = format!( + "expected {}, found {}", + expected, + self.this_token_descr(), + ); let mut err = self.fatal(&msg); - err.span_label(self.span, "expected pattern"); + err.span_label(self.span, format!("expected {}", expected)); return Err(err); } } @@ -4313,7 +4319,7 @@ impl<'a> Parser<'a> { -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { - Some(self.parse_pat()?) + Some(self.parse_pat(Some("binding pattern"))?) } else { None }; diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index 374154e6333..98e9272e6d8 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -68,7 +68,7 @@ pub fn string_to_item (source_str : String) -> Option> { pub fn string_to_pat(source_str: String) -> P { let ps = ParseSess::new(FilePathMapping::empty()); with_error_checking_parse(source_str, &ps, |p| { - p.parse_pat() + p.parse_pat(None) }) } diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 25ae7b4c55a..7c3b84a5185 100644 --- a/src/test/ui/parser/issue-33413.rs +++ b/src/test/ui/parser/issue-33413.rs @@ -11,5 +11,6 @@ // compile-flags: -Z parse-only impl S { - fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*` + fn f(*, a: u8) -> u8 {} + //~^ ERROR expected argument name, found `*` } diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr index 4cdd14a3e27..e0d69e596f2 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -1,11 +1,8 @@ -error: expected pattern, found `*` +error: expected argument name, found `*` --> $DIR/issue-33413.rs:14:10 | -LL | fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*` - | ^ - | | - | expected pattern - | expected argument name +LL | fn f(*, a: u8) -> u8 {} + | ^ expected argument name error: aborting due to previous error diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr index 83ca1b0ba26..86cc3c5b0cb 100644 --- a/src/test/ui/parser/lifetime-in-pattern.stderr +++ b/src/test/ui/parser/lifetime-in-pattern.stderr @@ -2,10 +2,7 @@ error: unexpected lifetime `'a` in pattern --> $DIR/lifetime-in-pattern.rs:13:10 | LL | fn test(&'a str) { - | ^^ - | | - | unexpected lifetime - | expected argument name + | ^^ unexpected lifetime error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-mode.rs b/src/test/ui/parser/removed-syntax-mode.rs index 6e99f8b3eea..c2f87d8afce 100644 --- a/src/test/ui/parser/removed-syntax-mode.rs +++ b/src/test/ui/parser/removed-syntax-mode.rs @@ -10,4 +10,5 @@ // compile-flags: -Z parse-only -fn f(+x: isize) {} //~ ERROR expected pattern, found `+` +fn f(+x: isize) {} +//~^ ERROR expected argument name, found `+` diff --git a/src/test/ui/parser/removed-syntax-mode.stderr b/src/test/ui/parser/removed-syntax-mode.stderr index c5bc92e37b5..7ad88471d5a 100644 --- a/src/test/ui/parser/removed-syntax-mode.stderr +++ b/src/test/ui/parser/removed-syntax-mode.stderr @@ -1,11 +1,8 @@ -error: expected pattern, found `+` +error: expected argument name, found `+` --> $DIR/removed-syntax-mode.rs:13:6 | -LL | fn f(+x: isize) {} //~ ERROR expected pattern, found `+` - | ^ - | | - | expected pattern - | expected argument name +LL | fn f(+x: isize) {} + | ^ expected argument name error: aborting due to previous error diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr index 4cad8401f23..76517433170 100644 --- a/src/test/ui/self/self-vs-path-ambiguity.stderr +++ b/src/test/ui/self/self-vs-path-ambiguity.stderr @@ -2,10 +2,7 @@ error: unexpected lifetime `'a` in pattern --> $DIR/self-vs-path-ambiguity.rs:19:11 | LL | fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern - | ^^ - | | - | unexpected lifetime - | expected argument name + | ^^ unexpected lifetime error: aborting due to previous error -- cgit 1.4.1-3-g733a5