about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-02-22 04:53:02 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-02-24 00:59:38 +0100
commita920a056035d3aa8f5e90ff174764a886366d379 (patch)
tree70359835dfc908a7f258c6e42f31c97548be5b77
parent9ed4c0998381901ac68c19c30c375f5760016759 (diff)
downloadrust-a920a056035d3aa8f5e90ff174764a886366d379.tar.gz
rust-a920a056035d3aa8f5e90ff174764a886366d379.zip
parse: recover `default` on free items.
-rw-r--r--src/librustc_parse/parser/item.rs59
-rw-r--r--src/test/ui/parser/default-on-wrong-item-kind.rs26
-rw-r--r--src/test/ui/parser/default-on-wrong-item-kind.stderr122
-rw-r--r--src/test/ui/parser/default-unmatched.rs6
-rw-r--r--src/test/ui/parser/default-unmatched.stderr14
-rw-r--r--src/test/ui/parser/impl-parsing.rs3
-rw-r--r--src/test/ui/parser/impl-parsing.stderr14
7 files changed, 226 insertions, 18 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 732bbdf1c54..184956e1065 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -81,17 +81,30 @@ impl<'a> Parser<'a> {
             Some(item)
         });
 
+        let item = self.parse_item_common(attrs, macros_allowed, attributes_allowed)?;
+        if let Some(ref item) = item {
+            self.error_on_illegal_default(item.defaultness);
+        }
+        Ok(item.map(P))
+    }
+
+    fn parse_item_common(
+        &mut self,
+        mut attrs: Vec<Attribute>,
+        macros_allowed: bool,
+        attributes_allowed: bool,
+    ) -> PResult<'a, Option<Item>> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
-
-        if let Some((ident, kind)) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? {
-            return Ok(Some(P(self.mk_item(lo, ident, kind, vis, Defaultness::Final, attrs))));
+        let mut def = self.parse_defaultness();
+        let kind = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis, &mut def)?;
+        if let Some((ident, kind)) = kind {
+            return Ok(Some(self.mk_item(lo, ident, kind, vis, def, attrs)));
         }
 
         // At this point, we have failed to parse an item.
-
         self.error_on_unmatched_vis(&vis);
-
+        self.error_on_unmatched_defaultness(def);
         if !attributes_allowed {
             self.recover_attrs_no_item(&attrs)?;
         }
@@ -111,6 +124,25 @@ impl<'a> Parser<'a> {
             .emit();
     }
 
+    /// Error in-case a `default` was parsed but no item followed.
+    fn error_on_unmatched_defaultness(&self, def: Defaultness) {
+        if let Defaultness::Default(span) = def {
+            self.struct_span_err(span, "unmatched `default`")
+                .span_label(span, "the unmatched `default`")
+                .emit();
+        }
+    }
+
+    /// Error in-case `default` was parsed in an in-appropriate context.
+    fn error_on_illegal_default(&self, def: Defaultness) {
+        if let Defaultness::Default(span) = def {
+            self.struct_span_err(span, "item cannot be `default`")
+                .span_label(span, "`default` because of this")
+                .note("only associated `fn`, `const`, and `type` items can be `default`")
+                .emit();
+        }
+    }
+
     /// Parses one of the items allowed by the flags.
     fn parse_item_kind(
         &mut self,
@@ -118,6 +150,7 @@ impl<'a> Parser<'a> {
         macros_allowed: bool,
         lo: Span,
         vis: &Visibility,
+        def: &mut Defaultness,
     ) -> PResult<'a, Option<ItemInfo>> {
         let info = if self.eat_keyword(kw::Use) {
             // USE ITEM
@@ -150,10 +183,9 @@ impl<'a> Parser<'a> {
             self.parse_item_trait(attrs, lo)?
         } else if self.check_keyword(kw::Impl)
             || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
-            || self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe])
         {
             // IMPL ITEM
-            self.parse_item_impl(attrs)?
+            self.parse_item_impl(attrs, mem::replace(def, Defaultness::Final))?
         } else if self.eat_keyword(kw::Mod) {
             // MODULE ITEM
             self.parse_item_mod(attrs)?
@@ -366,8 +398,11 @@ impl<'a> Parser<'a> {
     /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"
     /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"
     /// ```
-    fn parse_item_impl(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
-        let defaultness = self.parse_defaultness();
+    fn parse_item_impl(
+        &mut self,
+        attrs: &mut Vec<Attribute>,
+        defaultness: Defaultness,
+    ) -> PResult<'a, ItemInfo> {
         let unsafety = self.parse_unsafety();
         self.expect_keyword(kw::Impl)?;
 
@@ -531,13 +566,11 @@ impl<'a> Parser<'a> {
 
     /// Parses defaultness (i.e., `default` or nothing).
     fn parse_defaultness(&mut self) -> Defaultness {
-        // We are interested in `default` followed by another keyword.
+        // We are interested in `default` followed by another identifier.
         // However, we must avoid keywords that occur as binary operators.
         // Currently, the only applicable keyword is `as` (`default as Ty`).
         if self.check_keyword(kw::Default)
-            && self.look_ahead(1, |t| {
-                t.is_non_raw_ident_where(|i| i.is_reserved() && i.name != kw::As)
-            })
+            && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))
         {
             self.bump(); // `default`
             Defaultness::Default(self.prev_span)
diff --git a/src/test/ui/parser/default-on-wrong-item-kind.rs b/src/test/ui/parser/default-on-wrong-item-kind.rs
new file mode 100644
index 00000000000..f7d390eb8a2
--- /dev/null
+++ b/src/test/ui/parser/default-on-wrong-item-kind.rs
@@ -0,0 +1,26 @@
+// Test parsing for `default` where it doesn't belong.
+// Specifically, we are interested in kinds of items or items in certain contexts.
+
+fn main() {}
+
+#[cfg(FALSE)]
+mod free_items {
+    default extern crate foo; //~ ERROR item cannot be `default`
+    default use foo; //~ ERROR item cannot be `default`
+    default static foo: u8; //~ ERROR item cannot be `default`
+    default const foo: u8; //~ ERROR item cannot be `default`
+    default fn foo(); //~ ERROR item cannot be `default`
+    default mod foo {} //~ ERROR item cannot be `default`
+    default extern "C" {} //~ ERROR item cannot be `default`
+    default type foo = u8; //~ ERROR item cannot be `default`
+    default enum foo {} //~ ERROR item cannot be `default`
+    default struct foo {} //~ ERROR item cannot be `default`
+    default union foo {} //~ ERROR item cannot be `default`
+    default trait foo {} //~ ERROR item cannot be `default`
+    default trait foo = Ord; //~ ERROR item cannot be `default`
+    default impl foo {}
+    default!();
+    default::foo::bar!();
+    default macro foo {} //~ ERROR item cannot be `default`
+    default macro_rules! foo {} //~ ERROR item cannot be `default`
+}
diff --git a/src/test/ui/parser/default-on-wrong-item-kind.stderr b/src/test/ui/parser/default-on-wrong-item-kind.stderr
new file mode 100644
index 00000000000..d279fd962bb
--- /dev/null
+++ b/src/test/ui/parser/default-on-wrong-item-kind.stderr
@@ -0,0 +1,122 @@
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:8:5
+   |
+LL |     default extern crate foo;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:9:5
+   |
+LL |     default use foo;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:10:5
+   |
+LL |     default static foo: u8;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:11:5
+   |
+LL |     default const foo: u8;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:12:5
+   |
+LL |     default fn foo();
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:13:5
+   |
+LL |     default mod foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:14:5
+   |
+LL |     default extern "C" {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:15:5
+   |
+LL |     default type foo = u8;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:16:5
+   |
+LL |     default enum foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:17:5
+   |
+LL |     default struct foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:18:5
+   |
+LL |     default union foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:19:5
+   |
+LL |     default trait foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:20:5
+   |
+LL |     default trait foo = Ord;
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:24:5
+   |
+LL |     default macro foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: item cannot be `default`
+  --> $DIR/default-on-wrong-item-kind.rs:25:5
+   |
+LL |     default macro_rules! foo {}
+   |     ^^^^^^^ `default` because of this
+   |
+   = note: only associated `fn`, `const`, and `type` items can be `default`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/ui/parser/default-unmatched.rs b/src/test/ui/parser/default-unmatched.rs
new file mode 100644
index 00000000000..31696de0a5c
--- /dev/null
+++ b/src/test/ui/parser/default-unmatched.rs
@@ -0,0 +1,6 @@
+mod foo {
+    default!(); // OK.
+    default do
+    //~^ ERROR unmatched `default`
+    //~| ERROR expected item, found reserved keyword `do`
+}
diff --git a/src/test/ui/parser/default-unmatched.stderr b/src/test/ui/parser/default-unmatched.stderr
new file mode 100644
index 00000000000..6e4ef7b79fc
--- /dev/null
+++ b/src/test/ui/parser/default-unmatched.stderr
@@ -0,0 +1,14 @@
+error: unmatched `default`
+  --> $DIR/default-unmatched.rs:3:5
+   |
+LL |     default do
+   |     ^^^^^^^ the unmatched `default`
+
+error: expected item, found reserved keyword `do`
+  --> $DIR/default-unmatched.rs:3:13
+   |
+LL |     default do
+   |             ^^ expected item
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/impl-parsing.rs b/src/test/ui/parser/impl-parsing.rs
index 270c8b43dfd..662ed28f2f7 100644
--- a/src/test/ui/parser/impl-parsing.rs
+++ b/src/test/ui/parser/impl-parsing.rs
@@ -6,4 +6,5 @@ impl Trait .. {} //~ ERROR missing `for` in a trait impl
 impl ?Sized for Type {} //~ ERROR expected a trait, found type
 impl ?Sized for .. {} //~ ERROR expected a trait, found type
 
-default unsafe FAIL //~ ERROR expected `impl`, found `FAIL`
+default unsafe FAIL //~ ERROR expected item, found keyword `unsafe`
+//~^ ERROR unmatched `default`
diff --git a/src/test/ui/parser/impl-parsing.stderr b/src/test/ui/parser/impl-parsing.stderr
index 7c2a7937c5d..a5fc3e46896 100644
--- a/src/test/ui/parser/impl-parsing.stderr
+++ b/src/test/ui/parser/impl-parsing.stderr
@@ -22,11 +22,17 @@ error: expected a trait, found type
 LL | impl ?Sized for .. {}
    |      ^^^^^^
 
-error: expected `impl`, found `FAIL`
-  --> $DIR/impl-parsing.rs:9:16
+error: unmatched `default`
+  --> $DIR/impl-parsing.rs:9:1
    |
 LL | default unsafe FAIL
-   |                ^^^^ expected `impl`
+   | ^^^^^^^ the unmatched `default`
 
-error: aborting due to 5 previous errors
+error: expected item, found keyword `unsafe`
+  --> $DIR/impl-parsing.rs:9:9
+   |
+LL | default unsafe FAIL
+   |         ^^^^^^ expected item
+
+error: aborting due to 6 previous errors