parse: recover default
on free items.
This commit is contained in:
parent
9ed4c09983
commit
a920a05603
@ -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)
|
||||
|
26
src/test/ui/parser/default-on-wrong-item-kind.rs
Normal file
26
src/test/ui/parser/default-on-wrong-item-kind.rs
Normal file
@ -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`
|
||||
}
|
122
src/test/ui/parser/default-on-wrong-item-kind.stderr
Normal file
122
src/test/ui/parser/default-on-wrong-item-kind.stderr
Normal file
@ -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
|
||||
|
6
src/test/ui/parser/default-unmatched.rs
Normal file
6
src/test/ui/parser/default-unmatched.rs
Normal file
@ -0,0 +1,6 @@
|
||||
mod foo {
|
||||
default!(); // OK.
|
||||
default do
|
||||
//~^ ERROR unmatched `default`
|
||||
//~| ERROR expected item, found reserved keyword `do`
|
||||
}
|
14
src/test/ui/parser/default-unmatched.stderr
Normal file
14
src/test/ui/parser/default-unmatched.stderr
Normal file
@ -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
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user