parser: unify item list parsing.
as a consequence, `trait X { #![attr] }` becomes legal.
This commit is contained in:
parent
9fed2d587c
commit
7737d0ffde
@ -1269,6 +1269,7 @@ impl<'a> State<'a> {
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.s.word(" ");
|
||||
self.bopen();
|
||||
self.print_inner_attributes(&item.attrs);
|
||||
for trait_item in trait_items {
|
||||
self.print_assoc_item(trait_item);
|
||||
}
|
||||
|
@ -867,7 +867,7 @@ pub fn parse_ast_fragment<'a>(
|
||||
AstFragmentKind::ForeignItems => {
|
||||
let mut items = SmallVec::new();
|
||||
while this.token != token::Eof {
|
||||
items.push(this.parse_foreign_item()?);
|
||||
items.push(this.parse_foreign_item(&mut false)?);
|
||||
}
|
||||
AstFragment::ForeignItems(items)
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
|
||||
let (impl_items, attrs) = self.parse_impl_body()?;
|
||||
let (impl_items, attrs) = self.parse_item_list(|p, at_end| p.parse_impl_item(at_end))?;
|
||||
|
||||
let item_kind = match ty_second {
|
||||
Some(ty_second) => {
|
||||
@ -571,15 +571,21 @@ impl<'a> Parser<'a> {
|
||||
Ok((Ident::invalid(), item_kind, Some(attrs)))
|
||||
}
|
||||
|
||||
fn parse_impl_body(&mut self) -> PResult<'a, (Vec<P<AssocItem>>, Vec<Attribute>)> {
|
||||
fn parse_item_list<T>(
|
||||
&mut self,
|
||||
mut parse_item: impl FnMut(&mut Parser<'a>, &mut bool) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (Vec<T>, Vec<Attribute>)> {
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
let attrs = self.parse_inner_attributes()?;
|
||||
|
||||
let mut impl_items = Vec::new();
|
||||
let mut items = Vec::new();
|
||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||
if self.recover_doc_comment_before_brace() {
|
||||
continue;
|
||||
}
|
||||
let mut at_end = false;
|
||||
match self.parse_impl_item(&mut at_end) {
|
||||
Ok(impl_item) => impl_items.push(impl_item),
|
||||
match parse_item(self, &mut at_end) {
|
||||
Ok(item) => items.push(item),
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
if !at_end {
|
||||
@ -589,7 +595,30 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((impl_items, attrs))
|
||||
Ok((items, attrs))
|
||||
}
|
||||
|
||||
/// Recover on a doc comment before `}`.
|
||||
fn recover_doc_comment_before_brace(&mut self) -> bool {
|
||||
if let token::DocComment(_) = self.token.kind {
|
||||
if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
|
||||
struct_span_err!(
|
||||
self.diagnostic(),
|
||||
self.token.span,
|
||||
E0584,
|
||||
"found a documentation comment that doesn't document anything",
|
||||
)
|
||||
.span_label(self.token.span, "this doc comment doesn't document anything")
|
||||
.help(
|
||||
"doc comments must come before what they document, maybe a \
|
||||
comment was intended with `//`?",
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Parses defaultness (i.e., `default` or nothing).
|
||||
@ -660,39 +689,8 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
// It's a normal trait.
|
||||
tps.where_clause = self.parse_where_clause()?;
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
let mut trait_items = vec![];
|
||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||
if let token::DocComment(_) = self.token.kind {
|
||||
if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
|
||||
struct_span_err!(
|
||||
self.diagnostic(),
|
||||
self.token.span,
|
||||
E0584,
|
||||
"found a documentation comment that doesn't document anything",
|
||||
)
|
||||
.help(
|
||||
"doc comments must come before what they document, maybe a \
|
||||
comment was intended with `//`?",
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut at_end = false;
|
||||
match self.parse_trait_item(&mut at_end) {
|
||||
Ok(item) => trait_items.push(item),
|
||||
Err(mut e) => {
|
||||
e.emit();
|
||||
if !at_end {
|
||||
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
|
||||
let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_trait_item(at_end))?;
|
||||
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items), Some(attrs)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -942,26 +940,18 @@ impl<'a> Parser<'a> {
|
||||
&mut self,
|
||||
lo: Span,
|
||||
abi: Option<StrLit>,
|
||||
visibility: Visibility,
|
||||
vis: Visibility,
|
||||
mut attrs: Vec<Attribute>,
|
||||
) -> PResult<'a, P<Item>> {
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
|
||||
attrs.extend(self.parse_inner_attributes()?);
|
||||
|
||||
let mut foreign_items = vec![];
|
||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||
foreign_items.push(self.parse_foreign_item()?);
|
||||
}
|
||||
|
||||
let prev_span = self.prev_span;
|
||||
let m = ast::ForeignMod { abi, items: foreign_items };
|
||||
let invalid = Ident::invalid();
|
||||
Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
|
||||
let (items, iattrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?;
|
||||
attrs.extend(iattrs);
|
||||
let span = lo.to(self.prev_span);
|
||||
let m = ast::ForeignMod { abi, items };
|
||||
Ok(self.mk_item(span, Ident::invalid(), ItemKind::ForeignMod(m), vis, attrs))
|
||||
}
|
||||
|
||||
/// Parses a foreign item (one in an `extern { ... }` block).
|
||||
pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> {
|
||||
pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<ForeignItem>> {
|
||||
maybe_whole!(self, NtForeignItem, |ni| ni);
|
||||
|
||||
let mut attrs = self.parse_outer_attributes()?;
|
||||
@ -973,7 +963,7 @@ impl<'a> Parser<'a> {
|
||||
self.parse_item_foreign_type()?
|
||||
} else if self.check_fn_front_matter() {
|
||||
// FOREIGN FUNCTION ITEM
|
||||
let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?;
|
||||
let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, |_| true)?;
|
||||
(ident, ForeignItemKind::Fn(sig, generics, body))
|
||||
} else if self.is_static_global() {
|
||||
// FOREIGN STATIC ITEM
|
||||
@ -991,7 +981,7 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
.emit();
|
||||
self.parse_item_foreign_static()?
|
||||
} else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? {
|
||||
} else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), at_end)? {
|
||||
(Ident::invalid(), ForeignItemKind::Macro(mac))
|
||||
} else {
|
||||
if !attrs.is_empty() {
|
||||
|
7
src/test/pretty/trait-inner-attr.rs
Normal file
7
src/test/pretty/trait-inner-attr.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// pp-exact
|
||||
|
||||
trait Foo {
|
||||
#![allow(bar)]
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -1,13 +1,7 @@
|
||||
// Constants (static variables) can be used to match in patterns, but mutable
|
||||
// statics cannot. This ensures that there's some form of error if this is
|
||||
// attempted.
|
||||
// Make sure there's an error when given `extern { ... #[attr] }`.
|
||||
|
||||
extern crate libc;
|
||||
fn main() {}
|
||||
|
||||
extern {
|
||||
static mut rust_dbg_static_mut: libc::c_int;
|
||||
pub fn rust_dbg_static_mut_check_four();
|
||||
#[cfg(stage37)] //~ ERROR expected item after attributes
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expected item after attributes
|
||||
--> $DIR/attrs-after-extern-mod.rs:10:19
|
||||
--> $DIR/attrs-after-extern-mod.rs:6:19
|
||||
|
|
||||
LL | #[cfg(stage37)]
|
||||
| ^
|
||||
|
@ -1,4 +1,6 @@
|
||||
fn main() {}
|
||||
|
||||
extern {
|
||||
/// hi
|
||||
//~^ ERROR expected item after doc comment
|
||||
//~^ ERROR found a documentation comment that doesn't document anything
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
error: expected item after doc comment
|
||||
--> $DIR/doc-before-extern-rbrace.rs:2:5
|
||||
error[E0584]: found a documentation comment that doesn't document anything
|
||||
--> $DIR/doc-before-extern-rbrace.rs:4:5
|
||||
|
|
||||
LL | /// hi
|
||||
| ^^^^^^ this doc comment doesn't document anything
|
||||
|
|
||||
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0584`.
|
||||
|
@ -2,7 +2,7 @@ error[E0584]: found a documentation comment that doesn't document anything
|
||||
--> $DIR/doc-inside-trait-item.rs:3:5
|
||||
|
|
||||
LL | /// empty doc
|
||||
| ^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^ this doc comment doesn't document anything
|
||||
|
|
||||
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn`
|
||||
|
||||
fn main() {}
|
||||
|
||||
extern {
|
||||
pub pub fn foo();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub`
|
||||
--> $DIR/duplicate-visibility.rs:3:9
|
||||
--> $DIR/duplicate-visibility.rs:6:9
|
||||
|
|
||||
LL | pub pub fn foo();
|
||||
| ^^^ expected one of 8 possible tokens
|
||||
|
9
src/test/ui/parser/inner-attr-in-trait-def.rs
Normal file
9
src/test/ui/parser/inner-attr-in-trait-def.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// check-pass
|
||||
|
||||
#![deny(non_camel_case_types)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
trait foo_bar {
|
||||
#![allow(non_camel_case_types)]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user