Skip to content

Custom diagnostic when trying to doc comment argument #55451

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

Merged
merged 3 commits into from
Nov 5, 2018
Merged
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
2 changes: 1 addition & 1 deletion src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?),
})
}

Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
}

pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
panictry!(parser.parse_pat())
panictry!(parser.parse_pat(None))
}

pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/tt/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())),
Expand Down
77 changes: 61 additions & 16 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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()?;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Pat>> {
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
Expand Down Expand Up @@ -4060,13 +4096,17 @@ impl<'a> Parser<'a> {
}

/// Parse a pattern.
pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
self.parse_pat_with_range_pat(true)
pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
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<Pat>> {
fn parse_pat_with_range_pat(
&mut self,
allow_range_pat: bool,
expected: Option<&'static str>,
) -> PResult<'a, P<Pat>> {
maybe_whole!(self, NtPat, |x| x);

let lo = self.span;
Expand All @@ -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) => {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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
};
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/util/parser_testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_pat()
p.parse_pat(None)
})
}

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/label/label_break_value_illegal_uses.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

37 changes: 37 additions & 0 deletions src/test/ui/parser/fn-arg-doc-comment.rs
Original file line number Diff line number Diff line change
@@ -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
}
63 changes: 63 additions & 0 deletions src/test/ui/parser/fn-arg-doc-comment.stderr
Original file line number Diff line number Diff line change
@@ -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`.
3 changes: 2 additions & 1 deletion src/test/ui/parser/issue-33413.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `*`
}
6 changes: 3 additions & 3 deletions src/test/ui/parser/issue-33413.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/test/ui/parser/match-refactor-to-expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/parser/match-refactor-to-expr.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/parser/removed-syntax-mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `+`
Loading