diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 33b651e1b3854..84e40a7e4033d 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 62bc9fae3b59a..37800a334c6da 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 03a8376e76361..d6c95a3d7c8ec 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 589b3e30fcfbc..d700e6066cb0d 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,8 @@ 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(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) @@ -1819,10 +1849,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, @@ -1844,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()?; @@ -1882,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 { @@ -2439,7 +2471,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( @@ -3745,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 } @@ -3801,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; @@ -3826,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 { @@ -4028,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 @@ -4060,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; @@ -4082,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) => { @@ -4128,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() { @@ -4228,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); } } @@ -4274,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 374154e63333d..98e9272e6d8e5 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/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index 0ab1ad2c24200..7711b51a5c975 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/fn-arg-doc-comment.rs b/src/test/ui/parser/fn-arg-doc-comment.rs new file mode 100644 index 0000000000000..22af94b628452 --- /dev/null +++ b/src/test/ui/parser/fn-arg-doc-comment.rs @@ -0,0 +1,37 @@ +pub fn f( + /// Comment + //~^ ERROR documentation comments cannot be applied to method arguments + //~| NOTE doc comments are not allowed here + id: u8, + /// Other + //~^ ERROR documentation comments cannot be applied to method arguments + //~| NOTE doc comments are not allowed here + a: u8, +) {} + +fn foo(#[allow(dead_code)] id: i32) {} +//~^ ERROR attributes cannot be applied to method arguments +//~| NOTE attributes are not allowed here + +fn bar(id: #[allow(dead_code)] i32) {} +//~^ ERROR attributes cannot be applied to a method argument's type +//~| NOTE attributes are not allowed here + +fn main() { + // verify that the parser recovered and properly typechecked the args + f("", ""); + //~^ ERROR mismatched types + //~| NOTE expected u8, found reference + //~| NOTE expected + //~| ERROR mismatched types + //~| NOTE expected u8, found reference + //~| NOTE expected + foo(""); + //~^ ERROR mismatched types + //~| NOTE expected i32, found reference + //~| NOTE expected + bar(""); + //~^ ERROR mismatched types + //~| NOTE expected i32, found reference + //~| NOTE expected +} diff --git a/src/test/ui/parser/fn-arg-doc-comment.stderr b/src/test/ui/parser/fn-arg-doc-comment.stderr new file mode 100644 index 0000000000000..73a24eebb3f12 --- /dev/null +++ b/src/test/ui/parser/fn-arg-doc-comment.stderr @@ -0,0 +1,63 @@ +error: documentation comments cannot be applied to method arguments + --> $DIR/fn-arg-doc-comment.rs:2:5 + | +LL | /// Comment + | ^^^^^^^^^^^ doc comments are not allowed here + +error: documentation comments cannot be applied to method arguments + --> $DIR/fn-arg-doc-comment.rs:6:5 + | +LL | /// Other + | ^^^^^^^^^ doc comments are not allowed here + +error: attributes cannot be applied to method arguments + --> $DIR/fn-arg-doc-comment.rs:12:8 + | +LL | fn foo(#[allow(dead_code)] id: i32) {} + | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here + +error: attributes cannot be applied to a method argument's type + --> $DIR/fn-arg-doc-comment.rs:16:12 + | +LL | fn bar(id: #[allow(dead_code)] i32) {} + | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here + +error[E0308]: mismatched types + --> $DIR/fn-arg-doc-comment.rs:22:7 + | +LL | f("", ""); + | ^^ expected u8, found reference + | + = note: expected type `u8` + found type `&'static str` + +error[E0308]: mismatched types + --> $DIR/fn-arg-doc-comment.rs:22:11 + | +LL | f("", ""); + | ^^ expected u8, found reference + | + = note: expected type `u8` + found type `&'static str` + +error[E0308]: mismatched types + --> $DIR/fn-arg-doc-comment.rs:29:9 + | +LL | foo(""); + | ^^ expected i32, found reference + | + = note: expected type `i32` + found type `&'static str` + +error[E0308]: mismatched types + --> $DIR/fn-arg-doc-comment.rs:33:9 + | +LL | bar(""); + | ^^ expected i32, found reference + | + = note: expected type `i32` + found type `&'static str` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 25ae7b4c55a2b..7c3b84a5185d3 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 189ace74b9c6a..e0d69e596f24e 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -1,8 +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 +LL | fn f(*, a: u8) -> u8 {} + | ^ expected argument name error: aborting due to previous error diff --git a/src/test/ui/parser/match-refactor-to-expr.rs b/src/test/ui/parser/match-refactor-to-expr.rs index 3c88608697aad..014dba3d4d0e7 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 ecca781684cec..2ffbddd570ff6 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/parser/removed-syntax-mode.rs b/src/test/ui/parser/removed-syntax-mode.rs index 6e99f8b3eeadc..c2f87d8afce0e 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 7a274553d5766..7ad88471d5a9a 100644 --- a/src/test/ui/parser/removed-syntax-mode.stderr +++ b/src/test/ui/parser/removed-syntax-mode.stderr @@ -1,8 +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 +LL | fn f(+x: isize) {} + | ^ expected argument name error: aborting due to previous error 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 f07d23885aca1..c9b43000877cf 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