about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-09-25 22:20:01 +0000
committerMichael Goulet <michael@errs.io>2022-09-25 22:34:25 +0000
commit4d0d688a3cfd3d58cbd5d8065a7af774a7bb82b6 (patch)
treec72acae92de5d053ca511c65197ace59d0e3a9d0
parentf3fafbb006ee98635874f73e480655912b465e65 (diff)
downloadrust-4d0d688a3cfd3d58cbd5d8065a7af774a7bb82b6.tar.gz
rust-4d0d688a3cfd3d58cbd5d8065a7af774a7bb82b6.zip
Recover some items that expect braces and don't take semicolons
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl3
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs29
-rw-r--r--src/test/ui/parser/empty-impl-semicolon.rs5
-rw-r--r--src/test/ui/parser/empty-impl-semicolon.stderr8
-rw-r--r--src/test/ui/parser/item-needs-block.rs10
-rw-r--r--src/test/ui/parser/item-needs-block.stderr26
7 files changed, 78 insertions, 11 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 9459cfebde9..07dd03e6e50 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -158,3 +158,6 @@ parser_remove_let = expected pattern, found `let`
 
 parser_use_eq_instead = unexpected `==`
     .suggestion = try using `=` instead
+
+parser_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+    .suggestion = try using { "`{}`" } instead
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index dcea11eadcb..8750873c3a4 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -745,6 +745,14 @@ pub(crate) struct UseEqInstead {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parser::use_empty_block_not_semi)]
+pub(crate) struct UseEmptyBlockNotSemi {
+    #[primary_span]
+    #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e55b5ce71cd..802dfc048f8 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,4 +1,4 @@
-use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
+use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error, UseEmptyBlockNotSemi};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
 
@@ -664,6 +664,14 @@ impl<'a> Parser<'a> {
         mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
     ) -> PResult<'a, Vec<T>> {
         let open_brace_span = self.token.span;
+
+        // Recover `impl Ty;` instead of `impl Ty {}`
+        if self.token == TokenKind::Semi {
+            self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+            self.bump();
+            return Ok(vec![]);
+        }
+
         self.expect(&token::OpenDelim(Delimiter::Brace))?;
         attrs.extend(self.parse_inner_attributes()?);
 
@@ -1305,12 +1313,19 @@ impl<'a> Parser<'a> {
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
 
-        let (variants, _) = self
-            .parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant())
-            .map_err(|e| {
-                self.recover_stmt();
-                e
-            })?;
+        // Possibly recover `enum Foo;` instead of `enum Foo {}`
+        let (variants, _) = if self.token == TokenKind::Semi {
+            self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+            self.bump();
+            (vec![], false)
+        } else {
+            self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
+                |e| {
+                    self.recover_stmt();
+                    e
+                },
+            )?
+        };
 
         let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
         Ok((id, ItemKind::Enum(enum_definition, generics)))
diff --git a/src/test/ui/parser/empty-impl-semicolon.rs b/src/test/ui/parser/empty-impl-semicolon.rs
index 207ebef642b..2485f5b8552 100644
--- a/src/test/ui/parser/empty-impl-semicolon.rs
+++ b/src/test/ui/parser/empty-impl-semicolon.rs
@@ -1 +1,4 @@
-impl Foo; //~ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`
+struct Foo;
+impl Foo; //~ ERROR expected `{}`, found `;`
+
+fn main() {}
diff --git a/src/test/ui/parser/empty-impl-semicolon.stderr b/src/test/ui/parser/empty-impl-semicolon.stderr
index 398eb5c898c..6ed309eba93 100644
--- a/src/test/ui/parser/empty-impl-semicolon.stderr
+++ b/src/test/ui/parser/empty-impl-semicolon.stderr
@@ -1,8 +1,10 @@
-error: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`
-  --> $DIR/empty-impl-semicolon.rs:1:9
+error: expected `{}`, found `;`
+  --> $DIR/empty-impl-semicolon.rs:2:9
    |
 LL | impl Foo;
-   |         ^ expected one of 8 possible tokens
+   |         ^
+   |
+   = help: try using `{}` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/item-needs-block.rs b/src/test/ui/parser/item-needs-block.rs
new file mode 100644
index 00000000000..4edac588eee
--- /dev/null
+++ b/src/test/ui/parser/item-needs-block.rs
@@ -0,0 +1,10 @@
+trait Trait;
+//~^ ERROR expected `{}`, found `;`
+
+impl Trait for ();
+//~^ ERROR expected `{}`, found `;`
+
+enum Enum;
+//~^ ERROR expected `{}`, found `;`
+
+fn main() {}
diff --git a/src/test/ui/parser/item-needs-block.stderr b/src/test/ui/parser/item-needs-block.stderr
new file mode 100644
index 00000000000..3cabd0c73a3
--- /dev/null
+++ b/src/test/ui/parser/item-needs-block.stderr
@@ -0,0 +1,26 @@
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:1:12
+   |
+LL | trait Trait;
+   |            ^
+   |
+   = help: try using `{}` instead
+
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:4:18
+   |
+LL | impl Trait for ();
+   |                  ^
+   |
+   = help: try using `{}` instead
+
+error: expected `{}`, found `;`
+  --> $DIR/item-needs-block.rs:7:10
+   |
+LL | enum Enum;
+   |          ^
+   |
+   = help: try using `{}` instead
+
+error: aborting due to 3 previous errors
+