parser: unify item list parsing.
as a consequence, `trait X { #![attr] }` becomes legal.
This commit is contained in:
parent
9fed2d587c
commit
7737d0ffde
12 changed files with 80 additions and 71 deletions
|
@ -1269,6 +1269,7 @@ impl<'a> State<'a> {
|
||||||
self.print_where_clause(&generics.where_clause);
|
self.print_where_clause(&generics.where_clause);
|
||||||
self.s.word(" ");
|
self.s.word(" ");
|
||||||
self.bopen();
|
self.bopen();
|
||||||
|
self.print_inner_attributes(&item.attrs);
|
||||||
for trait_item in trait_items {
|
for trait_item in trait_items {
|
||||||
self.print_assoc_item(trait_item);
|
self.print_assoc_item(trait_item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -867,7 +867,7 @@ pub fn parse_ast_fragment<'a>(
|
||||||
AstFragmentKind::ForeignItems => {
|
AstFragmentKind::ForeignItems => {
|
||||||
let mut items = SmallVec::new();
|
let mut items = SmallVec::new();
|
||||||
while this.token != token::Eof {
|
while this.token != token::Eof {
|
||||||
items.push(this.parse_foreign_item()?);
|
items.push(this.parse_foreign_item(&mut false)?);
|
||||||
}
|
}
|
||||||
AstFragment::ForeignItems(items)
|
AstFragment::ForeignItems(items)
|
||||||
}
|
}
|
||||||
|
|
|
@ -515,7 +515,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
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 {
|
let item_kind = match ty_second {
|
||||||
Some(ty_second) => {
|
Some(ty_second) => {
|
||||||
|
@ -571,15 +571,21 @@ impl<'a> Parser<'a> {
|
||||||
Ok((Ident::invalid(), item_kind, Some(attrs)))
|
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))?;
|
self.expect(&token::OpenDelim(token::Brace))?;
|
||||||
let attrs = self.parse_inner_attributes()?;
|
let attrs = self.parse_inner_attributes()?;
|
||||||
|
|
||||||
let mut impl_items = Vec::new();
|
let mut items = Vec::new();
|
||||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||||
|
if self.recover_doc_comment_before_brace() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mut at_end = false;
|
let mut at_end = false;
|
||||||
match self.parse_impl_item(&mut at_end) {
|
match parse_item(self, &mut at_end) {
|
||||||
Ok(impl_item) => impl_items.push(impl_item),
|
Ok(item) => items.push(item),
|
||||||
Err(mut err) => {
|
Err(mut err) => {
|
||||||
err.emit();
|
err.emit();
|
||||||
if !at_end {
|
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).
|
/// Parses defaultness (i.e., `default` or nothing).
|
||||||
|
@ -660,39 +689,8 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
// It's a normal trait.
|
// It's a normal trait.
|
||||||
tps.where_clause = self.parse_where_clause()?;
|
tps.where_clause = self.parse_where_clause()?;
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_trait_item(at_end))?;
|
||||||
let mut trait_items = vec![];
|
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items), Some(attrs)))
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,26 +940,18 @@ impl<'a> Parser<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
abi: Option<StrLit>,
|
abi: Option<StrLit>,
|
||||||
visibility: Visibility,
|
vis: Visibility,
|
||||||
mut attrs: Vec<Attribute>,
|
mut attrs: Vec<Attribute>,
|
||||||
) -> PResult<'a, P<Item>> {
|
) -> PResult<'a, P<Item>> {
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
let (items, iattrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?;
|
||||||
|
attrs.extend(iattrs);
|
||||||
attrs.extend(self.parse_inner_attributes()?);
|
let span = lo.to(self.prev_span);
|
||||||
|
let m = ast::ForeignMod { abi, items };
|
||||||
let mut foreign_items = vec![];
|
Ok(self.mk_item(span, Ident::invalid(), ItemKind::ForeignMod(m), vis, attrs))
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a foreign item (one in an `extern { ... }` block).
|
/// 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);
|
maybe_whole!(self, NtForeignItem, |ni| ni);
|
||||||
|
|
||||||
let mut attrs = self.parse_outer_attributes()?;
|
let mut attrs = self.parse_outer_attributes()?;
|
||||||
|
@ -973,7 +963,7 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_item_foreign_type()?
|
self.parse_item_foreign_type()?
|
||||||
} else if self.check_fn_front_matter() {
|
} else if self.check_fn_front_matter() {
|
||||||
// FOREIGN FUNCTION ITEM
|
// 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))
|
(ident, ForeignItemKind::Fn(sig, generics, body))
|
||||||
} else if self.is_static_global() {
|
} else if self.is_static_global() {
|
||||||
// FOREIGN STATIC ITEM
|
// FOREIGN STATIC ITEM
|
||||||
|
@ -991,7 +981,7 @@ impl<'a> Parser<'a> {
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
self.parse_item_foreign_static()?
|
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))
|
(Ident::invalid(), ForeignItemKind::Macro(mac))
|
||||||
} else {
|
} else {
|
||||||
if !attrs.is_empty() {
|
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
|
// Make sure there's an error when given `extern { ... #[attr] }`.
|
||||||
// statics cannot. This ensures that there's some form of error if this is
|
|
||||||
// attempted.
|
|
||||||
|
|
||||||
extern crate libc;
|
fn main() {}
|
||||||
|
|
||||||
extern {
|
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
|
#[cfg(stage37)] //~ ERROR expected item after attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: expected item after attributes
|
error: expected item after attributes
|
||||||
--> $DIR/attrs-after-extern-mod.rs:10:19
|
--> $DIR/attrs-after-extern-mod.rs:6:19
|
||||||
|
|
|
|
||||||
LL | #[cfg(stage37)]
|
LL | #[cfg(stage37)]
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
/// hi
|
/// 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
|
error[E0584]: found a documentation comment that doesn't document anything
|
||||||
--> $DIR/doc-before-extern-rbrace.rs:2:5
|
--> $DIR/doc-before-extern-rbrace.rs:4:5
|
||||||
|
|
|
|
||||||
LL | /// hi
|
LL | /// hi
|
||||||
| ^^^^^^ this doc comment doesn't document anything
|
| ^^^^^^ 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
|
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
|
--> $DIR/doc-inside-trait-item.rs:3:5
|
||||||
|
|
|
|
||||||
LL | /// empty doc
|
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 `//`?
|
= 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`
|
// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn`
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
pub pub fn foo();
|
pub pub fn foo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub`
|
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();
|
LL | pub pub fn foo();
|
||||||
| ^^^ expected one of 8 possible tokens
|
| ^^^ 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…
Add table
Add a link
Reference in a new issue