Skip to content

Commit af791bb

Browse files
committed
Auto merge of #55451 - estebank:arg-doc, r=pnkfelix
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 6cfc603 + adb96ec commit af791bb

15 files changed

+187
-33
lines changed

src/libsyntax/ext/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ impl<'a> Parser<'a> {
10321032
}
10331033
},
10341034
AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
1035-
AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?),
1035+
AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
10361036
})
10371037
}
10381038

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
@@ -888,7 +888,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
888888
FatalError.raise();
889889
}
890890
},
891-
"pat" => token::NtPat(panictry!(p.parse_pat())),
891+
"pat" => token::NtPat(panictry!(p.parse_pat(None))),
892892
"expr" => token::NtExpr(panictry!(p.parse_expr())),
893893
"literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
894894
"ty" => token::NtTy(panictry!(p.parse_ty())),

src/libsyntax/parse/parser.rs

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

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

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

1853+
self.eat_incorrect_doc_comment("a method argument's type");
18231854
(pat, self.parse_ty()?)
18241855
} else {
18251856
debug!("parse_arg_general ident_to_pat");
18261857
let parser_snapshot_before_ty = self.clone();
1858+
self.eat_incorrect_doc_comment("a method argument's type");
18271859
let mut ty = self.parse_ty();
18281860
if ty.is_ok() && self.token == token::Colon {
18291861
// This wasn't actually a type, but a pattern looking like a type,
@@ -1845,7 +1877,7 @@ impl<'a> Parser<'a> {
18451877
// Recover from attempting to parse the argument as a type without pattern.
18461878
err.cancel();
18471879
mem::replace(self, parser_snapshot_before_ty);
1848-
let pat = self.parse_pat()?;
1880+
let pat = self.parse_pat(Some("argument name"))?;
18491881
self.expect(&token::Colon)?;
18501882
let ty = self.parse_ty()?;
18511883

@@ -1883,7 +1915,7 @@ impl<'a> Parser<'a> {
18831915

18841916
/// Parse an argument in a lambda header e.g. |arg, arg|
18851917
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
1886-
let pat = self.parse_pat()?;
1918+
let pat = self.parse_pat(Some("argument name"))?;
18871919
let t = if self.eat(&token::Colon) {
18881920
self.parse_ty()?
18891921
} else {
@@ -2440,7 +2472,11 @@ impl<'a> Parser<'a> {
24402472
return Ok(self.mk_expr(lo.to(hi), ex, attrs));
24412473
}
24422474
if self.eat_keyword(keywords::Match) {
2443-
return self.parse_match_expr(attrs);
2475+
let match_sp = self.prev_span;
2476+
return self.parse_match_expr(attrs).map_err(|mut err| {
2477+
err.span_label(match_sp, "while parsing this match expression");
2478+
err
2479+
});
24442480
}
24452481
if self.eat_keyword(keywords::Unsafe) {
24462482
return self.parse_block_expr(
@@ -3746,7 +3782,7 @@ impl<'a> Parser<'a> {
37463782
"`..` can only be used once per tuple or tuple struct pattern");
37473783
}
37483784
} else if !self.check(&token::CloseDelim(token::Paren)) {
3749-
fields.push(self.parse_pat()?);
3785+
fields.push(self.parse_pat(None)?);
37503786
} else {
37513787
break
37523788
}
@@ -3802,7 +3838,7 @@ impl<'a> Parser<'a> {
38023838
}
38033839
}
38043840

3805-
let subpat = self.parse_pat()?;
3841+
let subpat = self.parse_pat(None)?;
38063842
if before_slice && self.eat(&token::DotDot) {
38073843
slice = Some(subpat);
38083844
before_slice = false;
@@ -3827,7 +3863,7 @@ impl<'a> Parser<'a> {
38273863
// Parsing a pattern of the form "fieldname: pat"
38283864
let fieldname = self.parse_field_name()?;
38293865
self.bump();
3830-
let pat = self.parse_pat()?;
3866+
let pat = self.parse_pat(None)?;
38313867
hi = pat.span;
38323868
(pat, fieldname, false)
38333869
} else {
@@ -4029,7 +4065,7 @@ impl<'a> Parser<'a> {
40294065
/// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
40304066
/// to subpatterns within such).
40314067
fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
4032-
let pat = self.parse_pat()?;
4068+
let pat = self.parse_pat(None)?;
40334069
if self.token == token::Comma {
40344070
// An unexpected comma after a top-level pattern is a clue that the
40354071
// user (perhaps more accustomed to some other language) forgot the
@@ -4061,13 +4097,17 @@ impl<'a> Parser<'a> {
40614097
}
40624098

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

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

40734113
let lo = self.span;
@@ -4083,7 +4123,7 @@ impl<'a> Parser<'a> {
40834123
err.span_label(self.span, "unexpected lifetime");
40844124
return Err(err);
40854125
}
4086-
let subpat = self.parse_pat_with_range_pat(false)?;
4126+
let subpat = self.parse_pat_with_range_pat(false, expected)?;
40874127
pat = PatKind::Ref(subpat, mutbl);
40884128
}
40894129
token::OpenDelim(token::Paren) => {
@@ -4129,7 +4169,7 @@ impl<'a> Parser<'a> {
41294169
pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?;
41304170
} else if self.eat_keyword(keywords::Box) {
41314171
// Parse box pat
4132-
let subpat = self.parse_pat_with_range_pat(false)?;
4172+
let subpat = self.parse_pat_with_range_pat(false, None)?;
41334173
pat = PatKind::Box(subpat);
41344174
} else if self.token.is_ident() && !self.token.is_reserved_ident() &&
41354175
self.parse_as_ident() {
@@ -4229,9 +4269,14 @@ impl<'a> Parser<'a> {
42294269
}
42304270
Err(mut err) => {
42314271
self.cancel(&mut err);
4232-
let msg = format!("expected pattern, found {}", self.this_token_descr());
4272+
let expected = expected.unwrap_or("pattern");
4273+
let msg = format!(
4274+
"expected {}, found {}",
4275+
expected,
4276+
self.this_token_descr(),
4277+
);
42334278
let mut err = self.fatal(&msg);
4234-
err.span_label(self.span, "expected pattern");
4279+
err.span_label(self.span, format!("expected {}", expected));
42354280
return Err(err);
42364281
}
42374282
}
@@ -4275,7 +4320,7 @@ impl<'a> Parser<'a> {
42754320
-> PResult<'a, PatKind> {
42764321
let ident = self.parse_ident()?;
42774322
let sub = if self.eat(&token::At) {
4278-
Some(self.parse_pat()?)
4323+
Some(self.parse_pat(Some("binding pattern"))?)
42794324
} else {
42804325
None
42814326
};

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
@@ -27,7 +27,9 @@ error: expected one of `.`, `?`, `{`, or an operator, found `'b`
2727
--> $DIR/label_break_value_illegal_uses.rs:28:17
2828
|
2929
LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
30-
| ^^ expected one of `.`, `?`, `{`, or an operator here
30+
| ----- ^^ expected one of `.`, `?`, `{`, or an operator here
31+
| |
32+
| while parsing this match expression
3133

3234
error: aborting due to 4 previous errors
3335

+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)