diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-22 04:53:02 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-24 00:59:38 +0100 |
| commit | a920a056035d3aa8f5e90ff174764a886366d379 (patch) | |
| tree | 70359835dfc908a7f258c6e42f31c97548be5b77 | |
| parent | 9ed4c0998381901ac68c19c30c375f5760016759 (diff) | |
| download | rust-a920a056035d3aa8f5e90ff174764a886366d379.tar.gz rust-a920a056035d3aa8f5e90ff174764a886366d379.zip | |
parse: recover `default` on free items.
| -rw-r--r-- | src/librustc_parse/parser/item.rs | 59 | ||||
| -rw-r--r-- | src/test/ui/parser/default-on-wrong-item-kind.rs | 26 | ||||
| -rw-r--r-- | src/test/ui/parser/default-on-wrong-item-kind.stderr | 122 | ||||
| -rw-r--r-- | src/test/ui/parser/default-unmatched.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/parser/default-unmatched.stderr | 14 | ||||
| -rw-r--r-- | src/test/ui/parser/impl-parsing.rs | 3 | ||||
| -rw-r--r-- | src/test/ui/parser/impl-parsing.stderr | 14 |
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 |
