Skip to content

Commit 3874c77

Browse files
committed
Recover from item trailing semicolon
1 parent c2d381d commit 3874c77

7 files changed

+113
-30
lines changed

Diff for: src/libsyntax/parse/parser.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -6408,41 +6408,52 @@ impl<'a> Parser<'a> {
64086408
}
64096409
}
64106410

6411+
fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
6412+
if self.eat(&token::Semi) {
6413+
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
6414+
err.span_suggestion_short_with_applicability(
6415+
self.prev_span,
6416+
"remove this semicolon",
6417+
String::new(),
6418+
Applicability::MachineApplicable,
6419+
);
6420+
if !items.is_empty() {
6421+
let previous_item = &items[items.len()-1];
6422+
let previous_item_kind_name = match previous_item.node {
6423+
// say "braced struct" because tuple-structs and
6424+
// braceless-empty-struct declarations do take a semicolon
6425+
ItemKind::Struct(..) => Some("braced struct"),
6426+
ItemKind::Enum(..) => Some("enum"),
6427+
ItemKind::Trait(..) => Some("trait"),
6428+
ItemKind::Union(..) => Some("union"),
6429+
_ => None,
6430+
};
6431+
if let Some(name) = previous_item_kind_name {
6432+
err.help(&format!("{} declarations are not followed by a semicolon", name));
6433+
}
6434+
}
6435+
err.emit();
6436+
true
6437+
} else {
6438+
false
6439+
}
6440+
}
6441+
64116442
/// Given a termination token, parse all of the items in a module
64126443
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
64136444
let mut items = vec![];
64146445
while let Some(item) = self.parse_item()? {
64156446
items.push(item);
6447+
self.maybe_consume_incorrect_semicolon(&items);
64166448
}
64176449

64186450
if !self.eat(term) {
64196451
let token_str = self.this_token_descr();
6420-
let mut err = self.fatal(&format!("expected item, found {}", token_str));
6421-
if self.token == token::Semi {
6422-
let msg = "consider removing this semicolon";
6423-
err.span_suggestion_short_with_applicability(
6424-
self.span, msg, String::new(), Applicability::MachineApplicable
6425-
);
6426-
if !items.is_empty() { // Issue #51603
6427-
let previous_item = &items[items.len()-1];
6428-
let previous_item_kind_name = match previous_item.node {
6429-
// say "braced struct" because tuple-structs and
6430-
// braceless-empty-struct declarations do take a semicolon
6431-
ItemKind::Struct(..) => Some("braced struct"),
6432-
ItemKind::Enum(..) => Some("enum"),
6433-
ItemKind::Trait(..) => Some("trait"),
6434-
ItemKind::Union(..) => Some("union"),
6435-
_ => None,
6436-
};
6437-
if let Some(name) = previous_item_kind_name {
6438-
err.help(&format!("{} declarations are not followed by a semicolon",
6439-
name));
6440-
}
6441-
}
6442-
} else {
6452+
if !self.maybe_consume_incorrect_semicolon(&items) {
6453+
let mut err = self.fatal(&format!("expected item, found {}", token_str));
64436454
err.span_label(self.span, "expected item");
6455+
return Err(err);
64446456
}
6445-
return Err(err);
64466457
}
64476458

64486459
let hi = if self.span.is_dummy() {

Diff for: src/test/ui/issues/issue-46186.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
struct Struct {
22
a: usize,
3-
}; //~ ERROR expected item, found `;`
3+
};
4+
//~^ ERROR expected item, found `;`
45

56
fn main() {}

Diff for: src/test/ui/issues/issue-46186.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: expected item, found `;`
22
--> $DIR/issue-46186.rs:3:2
33
|
4-
LL | }; //~ ERROR expected item, found `;`
5-
| ^ help: consider removing this semicolon
4+
LL | };
5+
| ^ help: remove this semicolon
66
|
77
= help: braced struct declarations are not followed by a semicolon
88

Diff for: src/test/ui/issues/issue-49040.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#![allow(unused_variables)]; //~ ERROR expected item, found `;`
2-
fn main() {}
2+
fn foo() {}

Diff for: src/test/ui/issues/issue-49040.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error: expected item, found `;`
22
--> $DIR/issue-49040.rs:1:28
33
|
44
LL | #![allow(unused_variables)]; //~ ERROR expected item, found `;`
5-
| ^ help: consider removing this semicolon
5+
| ^ help: remove this semicolon
66

7-
error: aborting due to previous error
7+
error[E0601]: `main` function not found in crate `issue_49040`
8+
|
9+
= note: consider adding a `main` function to `$DIR/issue-49040.rs`
10+
11+
error: aborting due to 2 previous errors
812

13+
For more information about this error, try `rustc --explain E0601`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// verify that after encountering a semicolon after an item the parser recovers
2+
mod M {};
3+
//~^ ERROR expected item, found `;`
4+
struct S {};
5+
//~^ ERROR expected item, found `;`
6+
fn foo(a: usize) {};
7+
//~^ ERROR expected item, found `;`
8+
fn main() {
9+
struct X {}; // ok
10+
let _: usize = S {};
11+
//~^ ERROR mismatched types
12+
let _: usize = X {};
13+
//~^ ERROR mismatched types
14+
foo("");
15+
//~^ ERROR mismatched types
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error: expected item, found `;`
2+
--> $DIR/recover-from-semicolon-trailing-item.rs:2:9
3+
|
4+
LL | mod M {};
5+
| ^ help: remove this semicolon
6+
7+
error: expected item, found `;`
8+
--> $DIR/recover-from-semicolon-trailing-item.rs:4:12
9+
|
10+
LL | struct S {};
11+
| ^ help: remove this semicolon
12+
|
13+
= help: braced struct declarations are not followed by a semicolon
14+
15+
error: expected item, found `;`
16+
--> $DIR/recover-from-semicolon-trailing-item.rs:6:20
17+
|
18+
LL | fn foo(a: usize) {};
19+
| ^ help: remove this semicolon
20+
21+
error[E0308]: mismatched types
22+
--> $DIR/recover-from-semicolon-trailing-item.rs:10:20
23+
|
24+
LL | let _: usize = S {};
25+
| ^^^^ expected usize, found struct `S`
26+
|
27+
= note: expected type `usize`
28+
found type `S`
29+
30+
error[E0308]: mismatched types
31+
--> $DIR/recover-from-semicolon-trailing-item.rs:12:20
32+
|
33+
LL | let _: usize = X {};
34+
| ^^^^ expected usize, found struct `main::X`
35+
|
36+
= note: expected type `usize`
37+
found type `main::X`
38+
39+
error[E0308]: mismatched types
40+
--> $DIR/recover-from-semicolon-trailing-item.rs:14:9
41+
|
42+
LL | foo("");
43+
| ^^ expected usize, found reference
44+
|
45+
= note: expected type `usize`
46+
found type `&'static str`
47+
48+
error: aborting due to 6 previous errors
49+
50+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)