about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-01-14 20:31:58 +0100
committerGitHub <noreply@github.com>2019-01-14 20:31:58 +0100
commitb03d414e3c222a7f29259526fcdf95189e61fd0c (patch)
treebe340379624ea08f4c91342ba54a420889cd4cba /src
parentfeb48f334d29a22f2e3ae3b322af081b42fafc60 (diff)
parent3874c7755f292abc87fa2ce4fe82479ad063367e (diff)
downloadrust-b03d414e3c222a7f29259526fcdf95189e61fd0c.tar.gz
rust-b03d414e3c222a7f29259526fcdf95189e61fd0c.zip
Rollup merge of #57585 - estebank:trailing-semicolon, r=petrochenkov
Recover from item trailing semicolon

CC https://github.com/rust-lang/rfcs/pull/2479

r? @petrochenkov
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/parse/parser.rs59
-rw-r--r--src/test/ui/issues/issue-46186.rs3
-rw-r--r--src/test/ui/issues/issue-46186.stderr4
-rw-r--r--src/test/ui/issues/issue-49040.rs2
-rw-r--r--src/test/ui/issues/issue-49040.stderr9
-rw-r--r--src/test/ui/suggestions/recover-from-semicolon-trailing-item.rs16
-rw-r--r--src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr50
7 files changed, 113 insertions, 30 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 119bd6c107c..823c786bded 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6482,41 +6482,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() {
diff --git a/src/test/ui/issues/issue-46186.rs b/src/test/ui/issues/issue-46186.rs
index de7d13a2280..9dfd61fdf3f 100644
--- a/src/test/ui/issues/issue-46186.rs
+++ b/src/test/ui/issues/issue-46186.rs
@@ -1,5 +1,6 @@
 struct Struct {
     a: usize,
-}; //~ ERROR expected item, found `;`
+};
+//~^ ERROR expected item, found `;`
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-46186.stderr b/src/test/ui/issues/issue-46186.stderr
index 11a1fc072c9..eb0dbb8aa41 100644
--- a/src/test/ui/issues/issue-46186.stderr
+++ b/src/test/ui/issues/issue-46186.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-49040.rs b/src/test/ui/issues/issue-49040.rs
index 7c8d3d0ee69..a5f05d2824e 100644
--- a/src/test/ui/issues/issue-49040.rs
+++ b/src/test/ui/issues/issue-49040.rs
@@ -1,2 +1,2 @@
 #![allow(unused_variables)]; //~ ERROR expected item, found `;`
-fn main() {}
+fn foo() {}
diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr
index eec88f0c3f3..12e78e2f3bc 100644
--- a/src/test/ui/issues/issue-49040.stderr
+++ b/src/test/ui/issues/issue-49040.stderr
@@ -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`
+   |
+   = 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`.
diff --git a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.rs b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.rs
new file mode 100644
index 00000000000..82935af0a81
--- /dev/null
+++ b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.rs
@@ -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
+}
diff --git a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr
new file mode 100644
index 00000000000..9a47a1efb75
--- /dev/null
+++ b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr
@@ -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`.