Skip to content

Commit 94d9b43

Browse files
committed
Auto merge of #55451 - estebank:arg-doc, r=<try>
Custom diagnostic when trying to doc comment argument When writing ``` pub fn f( /// Comment id: u8, ) {} ``` Produce a targeted diagnostic ``` 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 ``` Fix #54801.
2 parents d586d5d + adb96ec commit 94d9b43

15 files changed

+187
-33
lines changed

src/libsyntax/ext/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ impl<'a> Parser<'a> {
10301030
}
10311031
},
10321032
AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
1033-
AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?),
1033+
AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
10341034
})
10351035
}
10361036

src/libsyntax/ext/quote.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
419419
}
420420

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

425425
pub fn parse_arm_panic(parser: &mut Parser) -> Arm {

src/libsyntax/ext/tt/macro_parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
881881
FatalError.raise();
882882
}
883883
},
884-
"pat" => token::NtPat(panictry!(p.parse_pat())),
884+
"pat" => token::NtPat(panictry!(p.parse_pat(None))),
885885
"expr" => token::NtExpr(panictry!(p.parse_expr())),
886886
"literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
887887
"ty" => token::NtTy(panictry!(p.parse_ty())),

src/libsyntax/parse/parser.rs

+61-16
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,35 @@ impl<'a> Parser<'a> {
17891789
self.look_ahead(offset + 1, |t| t == &token::Colon)
17901790
}
17911791

1792+
/// Skip unexpected attributes and doc comments in this position and emit an appropriate error.
1793+
fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
1794+
if let token::DocComment(_) = self.token {
1795+
let mut err = self.diagnostic().struct_span_err(
1796+
self.span,
1797+
&format!("documentation comments cannot be applied to {}", applied_to),
1798+
);
1799+
err.span_label(self.span, "doc comments are not allowed here");
1800+
err.emit();
1801+
self.bump();
1802+
} else if self.token == token::Pound && self.look_ahead(1, |t| {
1803+
*t == token::OpenDelim(token::Bracket)
1804+
}) {
1805+
let lo = self.span;
1806+
// Skip every token until next possible arg.
1807+
while self.token != token::CloseDelim(token::Bracket) {
1808+
self.bump();
1809+
}
1810+
let sp = lo.to(self.span);
1811+
self.bump();
1812+
let mut err = self.diagnostic().struct_span_err(
1813+
sp,
1814+
&format!("attributes cannot be applied to {}", applied_to),
1815+
);
1816+
err.span_label(sp, "attributes are not allowed here");
1817+
err.emit();
1818+
}
1819+
}
1820+
17921821
/// This version of parse arg doesn't necessarily require
17931822
/// identifier names.
17941823
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
@@ -1797,7 +1826,8 @@ impl<'a> Parser<'a> {
17971826
let (pat, ty) = if require_name || self.is_named_argument() {
17981827
debug!("parse_arg_general parse_pat (require_name:{})",
17991828
require_name);
1800-
let pat = self.parse_pat()?;
1829+
self.eat_incorrect_doc_comment("method arguments");
1830+
let pat = self.parse_pat(Some("argument name"))?;
18011831

18021832
if let Err(mut err) = self.expect(&token::Colon) {
18031833
// If we find a pattern followed by an identifier, it could be an (incorrect)
@@ -1819,10 +1849,12 @@ impl<'a> Parser<'a> {
18191849
return Err(err);
18201850
}
18211851

1852+
self.eat_incorrect_doc_comment("a method argument's type");
18221853
(pat, self.parse_ty()?)
18231854
} else {
18241855
debug!("parse_arg_general ident_to_pat");
18251856
let parser_snapshot_before_ty = self.clone();
1857+
self.eat_incorrect_doc_comment("a method argument's type");
18261858
let mut ty = self.parse_ty();
18271859
if ty.is_ok() && self.token == token::Colon {
18281860
// This wasn't actually a type, but a pattern looking like a type,
@@ -1844,7 +1876,7 @@ impl<'a> Parser<'a> {
18441876
// Recover from attempting to parse the argument as a type without pattern.
18451877
err.cancel();
18461878
mem::replace(self, parser_snapshot_before_ty);
1847-
let pat = self.parse_pat()?;
1879+
let pat = self.parse_pat(Some("argument name"))?;
18481880
self.expect(&token::Colon)?;
18491881
let ty = self.parse_ty()?;
18501882

@@ -1882,7 +1914,7 @@ impl<'a> Parser<'a> {
18821914

18831915
/// Parse an argument in a lambda header e.g. |arg, arg|
18841916
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
1885-
let pat = self.parse_pat()?;
1917+
let pat = self.parse_pat(Some("argument name"))?;
18861918
let t = if self.eat(&token::Colon) {
18871919
self.parse_ty()?
18881920
} else {
@@ -2439,7 +2471,11 @@ impl<'a> Parser<'a> {
24392471
return Ok(self.mk_expr(lo.to(hi), ex, attrs));
24402472
}
24412473
if self.eat_keyword(keywords::Match) {
2442-
return self.parse_match_expr(attrs);
2474+
let match_sp = self.prev_span;
2475+
return self.parse_match_expr(attrs).map_err(|mut err| {
2476+
err.span_label(match_sp, "while parsing this match expression");
2477+
err
2478+
});
24432479
}
24442480
if self.eat_keyword(keywords::Unsafe) {
24452481
return self.parse_block_expr(
@@ -3745,7 +3781,7 @@ impl<'a> Parser<'a> {
37453781
"`..` can only be used once per tuple or tuple struct pattern");
37463782
}
37473783
} else if !self.check(&token::CloseDelim(token::Paren)) {
3748-
fields.push(self.parse_pat()?);
3784+
fields.push(self.parse_pat(None)?);
37493785
} else {
37503786
break
37513787
}
@@ -3801,7 +3837,7 @@ impl<'a> Parser<'a> {
38013837
}
38023838
}
38033839

3804-
let subpat = self.parse_pat()?;
3840+
let subpat = self.parse_pat(None)?;
38053841
if before_slice && self.eat(&token::DotDot) {
38063842
slice = Some(subpat);
38073843
before_slice = false;
@@ -3826,7 +3862,7 @@ impl<'a> Parser<'a> {
38263862
// Parsing a pattern of the form "fieldname: pat"
38273863
let fieldname = self.parse_field_name()?;
38283864
self.bump();
3829-
let pat = self.parse_pat()?;
3865+
let pat = self.parse_pat(None)?;
38303866
hi = pat.span;
38313867
(pat, fieldname, false)
38323868
} else {
@@ -4028,7 +4064,7 @@ impl<'a> Parser<'a> {
40284064
/// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
40294065
/// to subpatterns within such).
40304066
fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
4031-
let pat = self.parse_pat()?;
4067+
let pat = self.parse_pat(None)?;
40324068
if self.token == token::Comma {
40334069
// An unexpected comma after a top-level pattern is a clue that the
40344070
// user (perhaps more accustomed to some other language) forgot the
@@ -4060,13 +4096,17 @@ impl<'a> Parser<'a> {
40604096
}
40614097

40624098
/// Parse a pattern.
4063-
pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
4064-
self.parse_pat_with_range_pat(true)
4099+
pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
4100+
self.parse_pat_with_range_pat(true, expected)
40654101
}
40664102

40674103
/// Parse a pattern, with a setting whether modern range patterns e.g. `a..=b`, `a..b` are
40684104
/// allowed.
4069-
fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<Pat>> {
4105+
fn parse_pat_with_range_pat(
4106+
&mut self,
4107+
allow_range_pat: bool,
4108+
expected: Option<&'static str>,
4109+
) -> PResult<'a, P<Pat>> {
40704110
maybe_whole!(self, NtPat, |x| x);
40714111

40724112
let lo = self.span;
@@ -4082,7 +4122,7 @@ impl<'a> Parser<'a> {
40824122
err.span_label(self.span, "unexpected lifetime");
40834123
return Err(err);
40844124
}
4085-
let subpat = self.parse_pat_with_range_pat(false)?;
4125+
let subpat = self.parse_pat_with_range_pat(false, expected)?;
40864126
pat = PatKind::Ref(subpat, mutbl);
40874127
}
40884128
token::OpenDelim(token::Paren) => {
@@ -4128,7 +4168,7 @@ impl<'a> Parser<'a> {
41284168
pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?;
41294169
} else if self.eat_keyword(keywords::Box) {
41304170
// Parse box pat
4131-
let subpat = self.parse_pat_with_range_pat(false)?;
4171+
let subpat = self.parse_pat_with_range_pat(false, None)?;
41324172
pat = PatKind::Box(subpat);
41334173
} else if self.token.is_ident() && !self.token.is_reserved_ident() &&
41344174
self.parse_as_ident() {
@@ -4228,9 +4268,14 @@ impl<'a> Parser<'a> {
42284268
}
42294269
Err(mut err) => {
42304270
self.cancel(&mut err);
4231-
let msg = format!("expected pattern, found {}", self.this_token_descr());
4271+
let expected = expected.unwrap_or("pattern");
4272+
let msg = format!(
4273+
"expected {}, found {}",
4274+
expected,
4275+
self.this_token_descr(),
4276+
);
42324277
let mut err = self.fatal(&msg);
4233-
err.span_label(self.span, "expected pattern");
4278+
err.span_label(self.span, format!("expected {}", expected));
42344279
return Err(err);
42354280
}
42364281
}
@@ -4274,7 +4319,7 @@ impl<'a> Parser<'a> {
42744319
-> PResult<'a, PatKind> {
42754320
let ident = self.parse_ident()?;
42764321
let sub = if self.eat(&token::At) {
4277-
Some(self.parse_pat()?)
4322+
Some(self.parse_pat(Some("binding pattern"))?)
42784323
} else {
42794324
None
42804325
};

src/libsyntax/util/parser_testing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
6868
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
6969
let ps = ParseSess::new(FilePathMapping::empty());
7070
with_error_checking_parse(source_str, &ps, |p| {
71-
p.parse_pat()
71+
p.parse_pat(None)
7272
})
7373
}
7474

src/test/ui/label/label_break_value_illegal_uses.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ error: expected one of `.`, `?`, `{`, or an operator, found `'b`
2525
--> $DIR/label_break_value_illegal_uses.rs:28:17
2626
|
2727
LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
28-
| ^^ expected one of `.`, `?`, `{`, or an operator here
28+
| ----- ^^ expected one of `.`, `?`, `{`, or an operator here
29+
| |
30+
| while parsing this match expression
2931

3032
error: aborting due to 4 previous errors
3133

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
pub fn f(
2+
/// Comment
3+
//~^ ERROR documentation comments cannot be applied to method arguments
4+
//~| NOTE doc comments are not allowed here
5+
id: u8,
6+
/// Other
7+
//~^ ERROR documentation comments cannot be applied to method arguments
8+
//~| NOTE doc comments are not allowed here
9+
a: u8,
10+
) {}
11+
12+
fn foo(#[allow(dead_code)] id: i32) {}
13+
//~^ ERROR attributes cannot be applied to method arguments
14+
//~| NOTE attributes are not allowed here
15+
16+
fn bar(id: #[allow(dead_code)] i32) {}
17+
//~^ ERROR attributes cannot be applied to a method argument's type
18+
//~| NOTE attributes are not allowed here
19+
20+
fn main() {
21+
// verify that the parser recovered and properly typechecked the args
22+
f("", "");
23+
//~^ ERROR mismatched types
24+
//~| NOTE expected u8, found reference
25+
//~| NOTE expected
26+
//~| ERROR mismatched types
27+
//~| NOTE expected u8, found reference
28+
//~| NOTE expected
29+
foo("");
30+
//~^ ERROR mismatched types
31+
//~| NOTE expected i32, found reference
32+
//~| NOTE expected
33+
bar("");
34+
//~^ ERROR mismatched types
35+
//~| NOTE expected i32, found reference
36+
//~| NOTE expected
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error: documentation comments cannot be applied to method arguments
2+
--> $DIR/fn-arg-doc-comment.rs:2:5
3+
|
4+
LL | /// Comment
5+
| ^^^^^^^^^^^ doc comments are not allowed here
6+
7+
error: documentation comments cannot be applied to method arguments
8+
--> $DIR/fn-arg-doc-comment.rs:6:5
9+
|
10+
LL | /// Other
11+
| ^^^^^^^^^ doc comments are not allowed here
12+
13+
error: attributes cannot be applied to method arguments
14+
--> $DIR/fn-arg-doc-comment.rs:12:8
15+
|
16+
LL | fn foo(#[allow(dead_code)] id: i32) {}
17+
| ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
18+
19+
error: attributes cannot be applied to a method argument's type
20+
--> $DIR/fn-arg-doc-comment.rs:16:12
21+
|
22+
LL | fn bar(id: #[allow(dead_code)] i32) {}
23+
| ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/fn-arg-doc-comment.rs:22:7
27+
|
28+
LL | f("", "");
29+
| ^^ expected u8, found reference
30+
|
31+
= note: expected type `u8`
32+
found type `&'static str`
33+
34+
error[E0308]: mismatched types
35+
--> $DIR/fn-arg-doc-comment.rs:22:11
36+
|
37+
LL | f("", "");
38+
| ^^ expected u8, found reference
39+
|
40+
= note: expected type `u8`
41+
found type `&'static str`
42+
43+
error[E0308]: mismatched types
44+
--> $DIR/fn-arg-doc-comment.rs:29:9
45+
|
46+
LL | foo("");
47+
| ^^ expected i32, found reference
48+
|
49+
= note: expected type `i32`
50+
found type `&'static str`
51+
52+
error[E0308]: mismatched types
53+
--> $DIR/fn-arg-doc-comment.rs:33:9
54+
|
55+
LL | bar("");
56+
| ^^ expected i32, found reference
57+
|
58+
= note: expected type `i32`
59+
found type `&'static str`
60+
61+
error: aborting due to 8 previous errors
62+
63+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/issue-33413.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
// compile-flags: -Z parse-only
1212

1313
impl S {
14-
fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*`
14+
fn f(*, a: u8) -> u8 {}
15+
//~^ ERROR expected argument name, found `*`
1516
}

src/test/ui/parser/issue-33413.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected pattern, found `*`
1+
error: expected argument name, found `*`
22
--> $DIR/issue-33413.rs:14:10
33
|
4-
LL | fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*`
5-
| ^ expected pattern
4+
LL | fn f(*, a: u8) -> u8 {}
5+
| ^ expected argument name
66

77
error: aborting due to previous error
88

src/test/ui/parser/match-refactor-to-expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
fn main() {
1414
let foo =
15-
match
15+
match //~ NOTE while parsing this match expression
1616
Some(4).unwrap_or_else(5)
1717
//~^ NOTE expected one of `.`, `?`, `{`, or an operator here
1818
; //~ NOTE unexpected token

src/test/ui/parser/match-refactor-to-expr.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
error: expected one of `.`, `?`, `{`, or an operator, found `;`
22
--> $DIR/match-refactor-to-expr.rs:18:9
33
|
4-
LL | match
5-
| ----- help: try removing this `match`
4+
LL | match //~ NOTE while parsing this match expression
5+
| -----
6+
| |
7+
| while parsing this match expression
8+
| help: try removing this `match`
69
LL | Some(4).unwrap_or_else(5)
710
| - expected one of `.`, `?`, `{`, or an operator here
811
LL | //~^ NOTE expected one of `.`, `?`, `{`, or an operator here

src/test/ui/parser/removed-syntax-mode.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010

1111
// compile-flags: -Z parse-only
1212

13-
fn f(+x: isize) {} //~ ERROR expected pattern, found `+`
13+
fn f(+x: isize) {}
14+
//~^ ERROR expected argument name, found `+`

0 commit comments

Comments
 (0)