Skip to content

Commit a920a05

Browse files
committed
parse: recover default on free items.
1 parent 9ed4c09 commit a920a05

File tree

7 files changed

+226
-18
lines changed

7 files changed

+226
-18
lines changed

src/librustc_parse/parser/item.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,30 @@ impl<'a> Parser<'a> {
8181
Some(item)
8282
});
8383

84+
let item = self.parse_item_common(attrs, macros_allowed, attributes_allowed)?;
85+
if let Some(ref item) = item {
86+
self.error_on_illegal_default(item.defaultness);
87+
}
88+
Ok(item.map(P))
89+
}
90+
91+
fn parse_item_common(
92+
&mut self,
93+
mut attrs: Vec<Attribute>,
94+
macros_allowed: bool,
95+
attributes_allowed: bool,
96+
) -> PResult<'a, Option<Item>> {
8497
let lo = self.token.span;
8598
let vis = self.parse_visibility(FollowedByType::No)?;
86-
87-
if let Some((ident, kind)) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? {
88-
return Ok(Some(P(self.mk_item(lo, ident, kind, vis, Defaultness::Final, attrs))));
99+
let mut def = self.parse_defaultness();
100+
let kind = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis, &mut def)?;
101+
if let Some((ident, kind)) = kind {
102+
return Ok(Some(self.mk_item(lo, ident, kind, vis, def, attrs)));
89103
}
90104

91105
// At this point, we have failed to parse an item.
92-
93106
self.error_on_unmatched_vis(&vis);
94-
107+
self.error_on_unmatched_defaultness(def);
95108
if !attributes_allowed {
96109
self.recover_attrs_no_item(&attrs)?;
97110
}
@@ -111,13 +124,33 @@ impl<'a> Parser<'a> {
111124
.emit();
112125
}
113126

127+
/// Error in-case a `default` was parsed but no item followed.
128+
fn error_on_unmatched_defaultness(&self, def: Defaultness) {
129+
if let Defaultness::Default(span) = def {
130+
self.struct_span_err(span, "unmatched `default`")
131+
.span_label(span, "the unmatched `default`")
132+
.emit();
133+
}
134+
}
135+
136+
/// Error in-case `default` was parsed in an in-appropriate context.
137+
fn error_on_illegal_default(&self, def: Defaultness) {
138+
if let Defaultness::Default(span) = def {
139+
self.struct_span_err(span, "item cannot be `default`")
140+
.span_label(span, "`default` because of this")
141+
.note("only associated `fn`, `const`, and `type` items can be `default`")
142+
.emit();
143+
}
144+
}
145+
114146
/// Parses one of the items allowed by the flags.
115147
fn parse_item_kind(
116148
&mut self,
117149
attrs: &mut Vec<Attribute>,
118150
macros_allowed: bool,
119151
lo: Span,
120152
vis: &Visibility,
153+
def: &mut Defaultness,
121154
) -> PResult<'a, Option<ItemInfo>> {
122155
let info = if self.eat_keyword(kw::Use) {
123156
// USE ITEM
@@ -150,10 +183,9 @@ impl<'a> Parser<'a> {
150183
self.parse_item_trait(attrs, lo)?
151184
} else if self.check_keyword(kw::Impl)
152185
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
153-
|| self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe])
154186
{
155187
// IMPL ITEM
156-
self.parse_item_impl(attrs)?
188+
self.parse_item_impl(attrs, mem::replace(def, Defaultness::Final))?
157189
} else if self.eat_keyword(kw::Mod) {
158190
// MODULE ITEM
159191
self.parse_item_mod(attrs)?
@@ -366,8 +398,11 @@ impl<'a> Parser<'a> {
366398
/// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"
367399
/// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"
368400
/// ```
369-
fn parse_item_impl(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
370-
let defaultness = self.parse_defaultness();
401+
fn parse_item_impl(
402+
&mut self,
403+
attrs: &mut Vec<Attribute>,
404+
defaultness: Defaultness,
405+
) -> PResult<'a, ItemInfo> {
371406
let unsafety = self.parse_unsafety();
372407
self.expect_keyword(kw::Impl)?;
373408

@@ -531,13 +566,11 @@ impl<'a> Parser<'a> {
531566

532567
/// Parses defaultness (i.e., `default` or nothing).
533568
fn parse_defaultness(&mut self) -> Defaultness {
534-
// We are interested in `default` followed by another keyword.
569+
// We are interested in `default` followed by another identifier.
535570
// However, we must avoid keywords that occur as binary operators.
536571
// Currently, the only applicable keyword is `as` (`default as Ty`).
537572
if self.check_keyword(kw::Default)
538-
&& self.look_ahead(1, |t| {
539-
t.is_non_raw_ident_where(|i| i.is_reserved() && i.name != kw::As)
540-
})
573+
&& self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))
541574
{
542575
self.bump(); // `default`
543576
Defaultness::Default(self.prev_span)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Test parsing for `default` where it doesn't belong.
2+
// Specifically, we are interested in kinds of items or items in certain contexts.
3+
4+
fn main() {}
5+
6+
#[cfg(FALSE)]
7+
mod free_items {
8+
default extern crate foo; //~ ERROR item cannot be `default`
9+
default use foo; //~ ERROR item cannot be `default`
10+
default static foo: u8; //~ ERROR item cannot be `default`
11+
default const foo: u8; //~ ERROR item cannot be `default`
12+
default fn foo(); //~ ERROR item cannot be `default`
13+
default mod foo {} //~ ERROR item cannot be `default`
14+
default extern "C" {} //~ ERROR item cannot be `default`
15+
default type foo = u8; //~ ERROR item cannot be `default`
16+
default enum foo {} //~ ERROR item cannot be `default`
17+
default struct foo {} //~ ERROR item cannot be `default`
18+
default union foo {} //~ ERROR item cannot be `default`
19+
default trait foo {} //~ ERROR item cannot be `default`
20+
default trait foo = Ord; //~ ERROR item cannot be `default`
21+
default impl foo {}
22+
default!();
23+
default::foo::bar!();
24+
default macro foo {} //~ ERROR item cannot be `default`
25+
default macro_rules! foo {} //~ ERROR item cannot be `default`
26+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
error: item cannot be `default`
2+
--> $DIR/default-on-wrong-item-kind.rs:8:5
3+
|
4+
LL | default extern crate foo;
5+
| ^^^^^^^ `default` because of this
6+
|
7+
= note: only associated `fn`, `const`, and `type` items can be `default`
8+
9+
error: item cannot be `default`
10+
--> $DIR/default-on-wrong-item-kind.rs:9:5
11+
|
12+
LL | default use foo;
13+
| ^^^^^^^ `default` because of this
14+
|
15+
= note: only associated `fn`, `const`, and `type` items can be `default`
16+
17+
error: item cannot be `default`
18+
--> $DIR/default-on-wrong-item-kind.rs:10:5
19+
|
20+
LL | default static foo: u8;
21+
| ^^^^^^^ `default` because of this
22+
|
23+
= note: only associated `fn`, `const`, and `type` items can be `default`
24+
25+
error: item cannot be `default`
26+
--> $DIR/default-on-wrong-item-kind.rs:11:5
27+
|
28+
LL | default const foo: u8;
29+
| ^^^^^^^ `default` because of this
30+
|
31+
= note: only associated `fn`, `const`, and `type` items can be `default`
32+
33+
error: item cannot be `default`
34+
--> $DIR/default-on-wrong-item-kind.rs:12:5
35+
|
36+
LL | default fn foo();
37+
| ^^^^^^^ `default` because of this
38+
|
39+
= note: only associated `fn`, `const`, and `type` items can be `default`
40+
41+
error: item cannot be `default`
42+
--> $DIR/default-on-wrong-item-kind.rs:13:5
43+
|
44+
LL | default mod foo {}
45+
| ^^^^^^^ `default` because of this
46+
|
47+
= note: only associated `fn`, `const`, and `type` items can be `default`
48+
49+
error: item cannot be `default`
50+
--> $DIR/default-on-wrong-item-kind.rs:14:5
51+
|
52+
LL | default extern "C" {}
53+
| ^^^^^^^ `default` because of this
54+
|
55+
= note: only associated `fn`, `const`, and `type` items can be `default`
56+
57+
error: item cannot be `default`
58+
--> $DIR/default-on-wrong-item-kind.rs:15:5
59+
|
60+
LL | default type foo = u8;
61+
| ^^^^^^^ `default` because of this
62+
|
63+
= note: only associated `fn`, `const`, and `type` items can be `default`
64+
65+
error: item cannot be `default`
66+
--> $DIR/default-on-wrong-item-kind.rs:16:5
67+
|
68+
LL | default enum foo {}
69+
| ^^^^^^^ `default` because of this
70+
|
71+
= note: only associated `fn`, `const`, and `type` items can be `default`
72+
73+
error: item cannot be `default`
74+
--> $DIR/default-on-wrong-item-kind.rs:17:5
75+
|
76+
LL | default struct foo {}
77+
| ^^^^^^^ `default` because of this
78+
|
79+
= note: only associated `fn`, `const`, and `type` items can be `default`
80+
81+
error: item cannot be `default`
82+
--> $DIR/default-on-wrong-item-kind.rs:18:5
83+
|
84+
LL | default union foo {}
85+
| ^^^^^^^ `default` because of this
86+
|
87+
= note: only associated `fn`, `const`, and `type` items can be `default`
88+
89+
error: item cannot be `default`
90+
--> $DIR/default-on-wrong-item-kind.rs:19:5
91+
|
92+
LL | default trait foo {}
93+
| ^^^^^^^ `default` because of this
94+
|
95+
= note: only associated `fn`, `const`, and `type` items can be `default`
96+
97+
error: item cannot be `default`
98+
--> $DIR/default-on-wrong-item-kind.rs:20:5
99+
|
100+
LL | default trait foo = Ord;
101+
| ^^^^^^^ `default` because of this
102+
|
103+
= note: only associated `fn`, `const`, and `type` items can be `default`
104+
105+
error: item cannot be `default`
106+
--> $DIR/default-on-wrong-item-kind.rs:24:5
107+
|
108+
LL | default macro foo {}
109+
| ^^^^^^^ `default` because of this
110+
|
111+
= note: only associated `fn`, `const`, and `type` items can be `default`
112+
113+
error: item cannot be `default`
114+
--> $DIR/default-on-wrong-item-kind.rs:25:5
115+
|
116+
LL | default macro_rules! foo {}
117+
| ^^^^^^^ `default` because of this
118+
|
119+
= note: only associated `fn`, `const`, and `type` items can be `default`
120+
121+
error: aborting due to 15 previous errors
122+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod foo {
2+
default!(); // OK.
3+
default do
4+
//~^ ERROR unmatched `default`
5+
//~| ERROR expected item, found reserved keyword `do`
6+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unmatched `default`
2+
--> $DIR/default-unmatched.rs:3:5
3+
|
4+
LL | default do
5+
| ^^^^^^^ the unmatched `default`
6+
7+
error: expected item, found reserved keyword `do`
8+
--> $DIR/default-unmatched.rs:3:13
9+
|
10+
LL | default do
11+
| ^^ expected item
12+
13+
error: aborting due to 2 previous errors
14+

src/test/ui/parser/impl-parsing.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ impl Trait .. {} //~ ERROR missing `for` in a trait impl
66
impl ?Sized for Type {} //~ ERROR expected a trait, found type
77
impl ?Sized for .. {} //~ ERROR expected a trait, found type
88

9-
default unsafe FAIL //~ ERROR expected `impl`, found `FAIL`
9+
default unsafe FAIL //~ ERROR expected item, found keyword `unsafe`
10+
//~^ ERROR unmatched `default`

src/test/ui/parser/impl-parsing.stderr

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ error: expected a trait, found type
2222
LL | impl ?Sized for .. {}
2323
| ^^^^^^
2424

25-
error: expected `impl`, found `FAIL`
26-
--> $DIR/impl-parsing.rs:9:16
25+
error: unmatched `default`
26+
--> $DIR/impl-parsing.rs:9:1
2727
|
2828
LL | default unsafe FAIL
29-
| ^^^^ expected `impl`
29+
| ^^^^^^^ the unmatched `default`
3030

31-
error: aborting due to 5 previous errors
31+
error: expected item, found keyword `unsafe`
32+
--> $DIR/impl-parsing.rs:9:9
33+
|
34+
LL | default unsafe FAIL
35+
| ^^^^^^ expected item
36+
37+
error: aborting due to 6 previous errors
3238

0 commit comments

Comments
 (0)