Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recover from item trailing semicolon #57585

Merged
merged 1 commit into from
Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 35 additions & 24 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6408,41 +6408,52 @@ impl<'a> Parser<'a> {
}
}

fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
if self.eat(&token::Semi) {
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
err.span_suggestion_short_with_applicability(
self.prev_span,
"remove this semicolon",
String::new(),
Applicability::MachineApplicable,
);
if !items.is_empty() {
let previous_item = &items[items.len()-1];
let previous_item_kind_name = match previous_item.node {
// say "braced struct" because tuple-structs and
// braceless-empty-struct declarations do take a semicolon
ItemKind::Struct(..) => Some("braced struct"),
ItemKind::Enum(..) => Some("enum"),
ItemKind::Trait(..) => Some("trait"),
ItemKind::Union(..) => Some("union"),
_ => None,
};
if let Some(name) = previous_item_kind_name {
err.help(&format!("{} declarations are not followed by a semicolon", name));
}
}
err.emit();
true
} else {
false
}
}

/// Given a termination token, parse all of the items in a module
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
let mut items = vec![];
while let Some(item) = self.parse_item()? {
items.push(item);
self.maybe_consume_incorrect_semicolon(&items);
}

if !self.eat(term) {
let token_str = self.this_token_descr();
let mut err = self.fatal(&format!("expected item, found {}", token_str));
if self.token == token::Semi {
let msg = "consider removing this semicolon";
err.span_suggestion_short_with_applicability(
self.span, msg, String::new(), Applicability::MachineApplicable
);
if !items.is_empty() { // Issue #51603
let previous_item = &items[items.len()-1];
let previous_item_kind_name = match previous_item.node {
// say "braced struct" because tuple-structs and
// braceless-empty-struct declarations do take a semicolon
ItemKind::Struct(..) => Some("braced struct"),
ItemKind::Enum(..) => Some("enum"),
ItemKind::Trait(..) => Some("trait"),
ItemKind::Union(..) => Some("union"),
_ => None,
};
if let Some(name) = previous_item_kind_name {
err.help(&format!("{} declarations are not followed by a semicolon",
name));
}
}
} else {
if !self.maybe_consume_incorrect_semicolon(&items) {
let mut err = self.fatal(&format!("expected item, found {}", token_str));
err.span_label(self.span, "expected item");
return Err(err);
}
return Err(err);
}

let hi = if self.span.is_dummy() {
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/issues/issue-46186.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
struct Struct {
a: usize,
}; //~ ERROR expected item, found `;`
};
//~^ ERROR expected item, found `;`

fn main() {}
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-46186.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected item, found `;`
--> $DIR/issue-46186.rs:3:2
|
LL | }; //~ ERROR expected item, found `;`
| ^ help: consider removing this semicolon
LL | };
| ^ help: remove this semicolon
|
= help: braced struct declarations are not followed by a semicolon

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-49040.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#![allow(unused_variables)]; //~ ERROR expected item, found `;`
fn main() {}
fn foo() {}
9 changes: 7 additions & 2 deletions src/test/ui/issues/issue-49040.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ error: expected item, found `;`
--> $DIR/issue-49040.rs:1:28
|
LL | #![allow(unused_variables)]; //~ ERROR expected item, found `;`
| ^ help: consider removing this semicolon
| ^ help: remove this semicolon

error: aborting due to previous error
error[E0601]: `main` function not found in crate `issue_49040`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could you use something less "accidental" and more obviously intentional than missing main.

|
= note: consider adding a `main` function to `$DIR/issue-49040.rs`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0601`.
16 changes: 16 additions & 0 deletions src/test/ui/suggestions/recover-from-semicolon-trailing-item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// verify that after encountering a semicolon after an item the parser recovers
mod M {};
//~^ ERROR expected item, found `;`
struct S {};
//~^ ERROR expected item, found `;`
fn foo(a: usize) {};
//~^ ERROR expected item, found `;`
fn main() {
struct X {}; // ok
let _: usize = S {};
//~^ ERROR mismatched types
let _: usize = X {};
//~^ ERROR mismatched types
foo("");
//~^ ERROR mismatched types
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
error: expected item, found `;`
--> $DIR/recover-from-semicolon-trailing-item.rs:2:9
|
LL | mod M {};
| ^ help: remove this semicolon

error: expected item, found `;`
--> $DIR/recover-from-semicolon-trailing-item.rs:4:12
|
LL | struct S {};
| ^ help: remove this semicolon
|
= help: braced struct declarations are not followed by a semicolon

error: expected item, found `;`
--> $DIR/recover-from-semicolon-trailing-item.rs:6:20
|
LL | fn foo(a: usize) {};
| ^ help: remove this semicolon

error[E0308]: mismatched types
--> $DIR/recover-from-semicolon-trailing-item.rs:10:20
|
LL | let _: usize = S {};
| ^^^^ expected usize, found struct `S`
|
= note: expected type `usize`
found type `S`

error[E0308]: mismatched types
--> $DIR/recover-from-semicolon-trailing-item.rs:12:20
|
LL | let _: usize = X {};
| ^^^^ expected usize, found struct `main::X`
|
= note: expected type `usize`
found type `main::X`

error[E0308]: mismatched types
--> $DIR/recover-from-semicolon-trailing-item.rs:14:9
|
LL | foo("");
| ^^ expected usize, found reference
|
= note: expected type `usize`
found type `&'static str`

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0308`.