Skip to content

Commit b03d414

Browse files
authored
Rollup merge of #57585 - estebank:trailing-semicolon, r=petrochenkov
Recover from item trailing semicolon CC rust-lang/rfcs#2479 r? @petrochenkov
2 parents feb48f3 + 3874c77 commit b03d414

7 files changed

+113
-30
lines changed

src/libsyntax/parse/parser.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -6482,41 +6482,52 @@ impl<'a> Parser<'a> {
64826482
}
64836483
}
64846484

6485+
fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
6486+
if self.eat(&token::Semi) {
6487+
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
6488+
err.span_suggestion_short_with_applicability(
6489+
self.prev_span,
6490+
"remove this semicolon",
6491+
String::new(),
6492+
Applicability::MachineApplicable,
6493+
);
6494+
if !items.is_empty() {
6495+
let previous_item = &items[items.len()-1];
6496+
let previous_item_kind_name = match previous_item.node {
6497+
// say "braced struct" because tuple-structs and
6498+
// braceless-empty-struct declarations do take a semicolon
6499+
ItemKind::Struct(..) => Some("braced struct"),
6500+
ItemKind::Enum(..) => Some("enum"),
6501+
ItemKind::Trait(..) => Some("trait"),
6502+
ItemKind::Union(..) => Some("union"),
6503+
_ => None,
6504+
};
6505+
if let Some(name) = previous_item_kind_name {
6506+
err.help(&format!("{} declarations are not followed by a semicolon", name));
6507+
}
6508+
}
6509+
err.emit();
6510+
true
6511+
} else {
6512+
false
6513+
}
6514+
}
6515+
64856516
/// Given a termination token, parse all of the items in a module
64866517
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
64876518
let mut items = vec![];
64886519
while let Some(item) = self.parse_item()? {
64896520
items.push(item);
6521+
self.maybe_consume_incorrect_semicolon(&items);
64906522
}
64916523

64926524
if !self.eat(term) {
64936525
let token_str = self.this_token_descr();
6494-
let mut err = self.fatal(&format!("expected item, found {}", token_str));
6495-
if self.token == token::Semi {
6496-
let msg = "consider removing this semicolon";
6497-
err.span_suggestion_short_with_applicability(
6498-
self.span, msg, String::new(), Applicability::MachineApplicable
6499-
);
6500-
if !items.is_empty() { // Issue #51603
6501-
let previous_item = &items[items.len()-1];
6502-
let previous_item_kind_name = match previous_item.node {
6503-
// say "braced struct" because tuple-structs and
6504-
// braceless-empty-struct declarations do take a semicolon
6505-
ItemKind::Struct(..) => Some("braced struct"),
6506-
ItemKind::Enum(..) => Some("enum"),
6507-
ItemKind::Trait(..) => Some("trait"),
6508-
ItemKind::Union(..) => Some("union"),
6509-
_ => None,
6510-
};
6511-
if let Some(name) = previous_item_kind_name {
6512-
err.help(&format!("{} declarations are not followed by a semicolon",
6513-
name));
6514-
}
6515-
}
6516-
} else {
6526+
if !self.maybe_consume_incorrect_semicolon(&items) {
6527+
let mut err = self.fatal(&format!("expected item, found {}", token_str));
65176528
err.span_label(self.span, "expected item");
6529+
return Err(err);
65186530
}
6519-
return Err(err);
65206531
}
65216532

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

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() {}

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

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() {}

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)