Skip to content

Commit ea57134

Browse files
committed
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.
1 parent 3e6f30e commit ea57134

7 files changed

+152
-5
lines changed

src/libsyntax/parse/parser.rs

+36-1
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,11 @@ 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().map_err(|mut err| {
1831+
err.span_label(self.span, "expected argument name");
1832+
err
1833+
})?;
18011834

18021835
if let Err(mut err) = self.expect(&token::Colon) {
18031836
// If we find a pattern followed by an identifier, it could be an (incorrect)
@@ -1819,10 +1852,12 @@ impl<'a> Parser<'a> {
18191852
return Err(err);
18201853
}
18211854

1855+
self.eat_incorrect_doc_comment("a method argument's type");
18221856
(pat, self.parse_ty()?)
18231857
} else {
18241858
debug!("parse_arg_general ident_to_pat");
18251859
let parser_snapshot_before_ty = self.clone();
1860+
self.eat_incorrect_doc_comment("a method argument's type");
18261861
let mut ty = self.parse_ty();
18271862
if ty.is_ok() && self.token == token::Colon {
18281863
// This wasn't actually a type, but a pattern looking like a type,
+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.stderr

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

710
error: aborting due to previous error
811

src/test/ui/parser/lifetime-in-pattern.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: unexpected lifetime `'a` in pattern
22
--> $DIR/lifetime-in-pattern.rs:13:10
33
|
44
LL | fn test(&'a str) {
5-
| ^^ unexpected lifetime
5+
| ^^
6+
| |
7+
| unexpected lifetime
8+
| expected argument name
69

710
error: aborting due to previous error
811

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: expected pattern, found `+`
22
--> $DIR/removed-syntax-mode.rs:13:6
33
|
44
LL | fn f(+x: isize) {} //~ ERROR expected pattern, found `+`
5-
| ^ expected pattern
5+
| ^
6+
| |
7+
| expected pattern
8+
| expected argument name
69

710
error: aborting due to previous error
811

src/test/ui/self/self-vs-path-ambiguity.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: unexpected lifetime `'a` in pattern
22
--> $DIR/self-vs-path-ambiguity.rs:19:11
33
|
44
LL | fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern
5-
| ^^ unexpected lifetime
5+
| ^^
6+
| |
7+
| unexpected lifetime
8+
| expected argument name
69

710
error: aborting due to previous error
811

0 commit comments

Comments
 (0)