Rollup merge of #36662 - jseyfried:parse_macro_invoc_paths, r=nrc

parser: support paths in bang macro invocations (e.g. `path::to::macro!()`)

r? @nrc
This commit is contained in:
Jonathan Turner 2016-09-26 17:29:47 -07:00 committed by GitHub
commit 1d9646228d
7 changed files with 269 additions and 264 deletions

View File

@ -542,11 +542,6 @@ impl<'a> Parser<'a> {
}
}
fn parse_ident_into_path(&mut self) -> PResult<'a, ast::Path> {
let ident = self.parse_ident()?;
Ok(ast::Path::from_ident(self.last_span, ident))
}
/// Check if the next token is `tok`, and return `true` if so.
///
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
@ -1202,94 +1197,87 @@ impl<'a> Parser<'a> {
None
};
(ident, TraitItemKind::Const(ty, default))
} else if !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
&& (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
// trait item macro.
// code copied from parse_macro_use_or_failure... abstraction!
let lo = self.span.lo;
let pth = self.parse_ident_into_path()?;
self.expect(&token::Not)?;
} else if self.token.is_path_start() {
// trait item macro.
// code copied from parse_macro_use_or_failure... abstraction!
let lo = self.span.lo;
let pth = self.parse_path(PathStyle::Mod)?;
self.expect(&token::Not)?;
// eat a matched-delimiter token tree:
let delim = self.expect_open_delim()?;
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|pp| pp.parse_token_tree())?;
let m_ = Mac_ { path: pth, tts: tts };
let m: ast::Mac = codemap::Spanned { node: m_,
span: mk_sp(lo,
self.last_span.hi) };
if delim != token::Brace {
self.expect(&token::Semi)?
}
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
} else {
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
Ok(cua) => cua,
Err(e) => {
loop {
match self.token {
token::Eof => break,
token::CloseDelim(token::Brace) |
token::Semi => {
self.bump();
break;
}
token::OpenDelim(token::Brace) => {
self.parse_token_tree()?;
break;
}
_ => self.bump()
// eat a matched-delimiter token tree:
let delim = self.expect_open_delim()?;
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|pp| pp.parse_token_tree())?;
if delim != token::Brace {
self.expect(&token::Semi)?
}
let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
} else {
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
Ok(cua) => cua,
Err(e) => {
loop {
match self.token {
token::Eof => break,
token::CloseDelim(token::Brace) |
token::Semi => {
self.bump();
break;
}
token::OpenDelim(token::Brace) => {
self.parse_token_tree()?;
break;
}
_ => self.bump(),
}
return Err(e);
}
};
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
// This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a
// definition...
p.parse_arg_general(false)
})?;
generics.where_clause = self.parse_where_clause()?;
let sig = ast::MethodSig {
unsafety: unsafety,
constness: constness,
decl: d,
generics: generics,
abi: abi,
};
let body = match self.token {
token::Semi => {
self.bump();
debug!("parse_trait_methods(): parsing required method");
None
}
token::OpenDelim(token::Brace) => {
debug!("parse_trait_methods(): parsing provided method");
let (inner_attrs, body) =
self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
_ => {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
token_str)[..]))
}
};
(ident, ast::TraitItemKind::Method(sig, body))
return Err(e);
}
};
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
// This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a
// definition...
p.parse_arg_general(false)
})?;
generics.where_clause = self.parse_where_clause()?;
let sig = ast::MethodSig {
unsafety: unsafety,
constness: constness,
decl: d,
generics: generics,
abi: abi,
};
let body = match self.token {
token::Semi => {
self.bump();
debug!("parse_trait_methods(): parsing required method");
None
}
token::OpenDelim(token::Brace) => {
debug!("parse_trait_methods(): parsing provided method");
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(inner_attrs.iter().cloned());
Some(body)
}
_ => {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
}
};
(ident, ast::TraitItemKind::Method(sig, body))
};
Ok(TraitItem {
id: ast::DUMMY_NODE_ID,
ident: name,
@ -1430,9 +1418,8 @@ impl<'a> Parser<'a> {
TyKind::Path(Some(qself), path)
} else if self.token.is_path_start() {
let path = self.parse_path(PathStyle::Type)?;
if self.check(&token::Not) {
if self.eat(&token::Not) {
// MACRO INVOCATION
self.bump();
let delim = self.expect_open_delim()?;
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
@ -2310,21 +2297,14 @@ impl<'a> Parser<'a> {
let pth = self.parse_path(PathStyle::Expr)?;
// `!`, as an operator, is prefix, so we know this isn't that
if self.check(&token::Not) {
if self.eat(&token::Not) {
// MACRO INVOCATION expression
self.bump();
let delim = self.expect_open_delim()?;
let tts = self.parse_seq_to_end(
&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree())?;
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree())?;
let hi = self.last_span.hi;
return Ok(self.mk_mac_expr(lo,
hi,
Mac_ { path: pth, tts: tts },
attrs));
return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
}
if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited
@ -2333,51 +2313,7 @@ impl<'a> Parser<'a> {
Restrictions::RESTRICTION_NO_STRUCT_LITERAL
);
if !prohibited {
// It's a struct literal.
self.bump();
let mut fields = Vec::new();
let mut base = None;
attrs.extend(self.parse_inner_attributes()?);
while self.token != token::CloseDelim(token::Brace) {
if self.eat(&token::DotDot) {
match self.parse_expr() {
Ok(e) => {
base = Some(e);
}
Err(mut e) => {
e.emit();
self.recover_stmt();
}
}
break;
}
match self.parse_field() {
Ok(f) => fields.push(f),
Err(mut e) => {
e.emit();
self.recover_stmt();
break;
}
}
match self.expect_one_of(&[token::Comma],
&[token::CloseDelim(token::Brace)]) {
Ok(()) => {}
Err(mut e) => {
e.emit();
self.recover_stmt();
break;
}
}
}
hi = self.span.hi;
self.expect(&token::CloseDelim(token::Brace))?;
ex = ExprKind::Struct(pth, fields, base);
return Ok(self.mk_expr(lo, hi, ex, attrs));
return self.parse_struct_expr(lo, pth, attrs);
}
}
@ -2403,6 +2339,53 @@ impl<'a> Parser<'a> {
return Ok(self.mk_expr(lo, hi, ex, attrs));
}
fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> {
self.bump();
let mut fields = Vec::new();
let mut base = None;
attrs.extend(self.parse_inner_attributes()?);
while self.token != token::CloseDelim(token::Brace) {
if self.eat(&token::DotDot) {
match self.parse_expr() {
Ok(e) => {
base = Some(e);
}
Err(mut e) => {
e.emit();
self.recover_stmt();
}
}
break;
}
match self.parse_field() {
Ok(f) => fields.push(f),
Err(mut e) => {
e.emit();
self.recover_stmt();
break;
}
}
match self.expect_one_of(&[token::Comma],
&[token::CloseDelim(token::Brace)]) {
Ok(()) => {}
Err(mut e) => {
e.emit();
self.recover_stmt();
break;
}
}
}
let hi = self.span.hi;
self.expect(&token::CloseDelim(token::Brace))?;
return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs));
}
fn parse_or_use_outer_attributes(&mut self,
already_parsed_attrs: Option<ThinVec<Attribute>>)
-> PResult<'a, ThinVec<Attribute>> {
@ -3577,39 +3560,37 @@ impl<'a> Parser<'a> {
let lo = self.span.lo;
let pat;
match self.token {
token::Underscore => {
// Parse _
self.bump();
pat = PatKind::Wild;
}
token::BinOp(token::And) | token::AndAnd => {
// Parse &pat / &mut pat
self.expect_and()?;
let mutbl = self.parse_mutability()?;
if let token::Lifetime(ident) = self.token {
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
token::Underscore => {
// Parse _
self.bump();
pat = PatKind::Wild;
}
token::BinOp(token::And) | token::AndAnd => {
// Parse &pat / &mut pat
self.expect_and()?;
let mutbl = self.parse_mutability()?;
if let token::Lifetime(ident) = self.token {
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
}
let subpat = self.parse_pat()?;
pat = PatKind::Ref(subpat, mutbl);
}
token::OpenDelim(token::Paren) => {
// Parse (pat,pat,pat,...) as tuple pattern
self.bump();
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::Tuple(fields, ddpos);
}
token::OpenDelim(token::Bracket) => {
// Parse [pat,pat,...] as slice pattern
self.bump();
let (before, slice, after) = self.parse_pat_vec_elements()?;
self.expect(&token::CloseDelim(token::Bracket))?;
pat = PatKind::Vec(before, slice, after);
}
let subpat = self.parse_pat()?;
pat = PatKind::Ref(subpat, mutbl);
}
token::OpenDelim(token::Paren) => {
// Parse (pat,pat,pat,...) as tuple pattern
self.bump();
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::Tuple(fields, ddpos);
}
token::OpenDelim(token::Bracket) => {
// Parse [pat,pat,...] as slice pattern
self.bump();
let (before, slice, after) = self.parse_pat_vec_elements()?;
self.expect(&token::CloseDelim(token::Bracket))?;
pat = PatKind::Vec(before, slice, after);
}
_ => {
// At this point, token != _, &, &&, (, [
if self.eat_keyword(keywords::Mut) {
_ => if self.eat_keyword(keywords::Mut) {
// Parse mut ident @ pat
pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?;
} else if self.eat_keyword(keywords::Ref) {
@ -3620,43 +3601,39 @@ impl<'a> Parser<'a> {
// Parse box pat
let subpat = self.parse_pat()?;
pat = PatKind::Box(subpat);
} else if self.token.is_ident() && self.token.is_path_start() &&
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => false,
_ => true,
}) {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve
let binding_mode = BindingMode::ByValue(Mutability::Immutable);
pat = self.parse_pat_ident(binding_mode)?;
} else if self.token.is_path_start() {
// Parse pattern starting with a path
if self.token.is_ident() && self.look_ahead(1, |t| *t != token::DotDotDot &&
*t != token::OpenDelim(token::Brace) &&
*t != token::OpenDelim(token::Paren) &&
*t != token::ModSep) {
// Plain idents have some extra abilities here compared to general paths
if self.look_ahead(1, |t| *t == token::Not) {
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?;
(Some(qself), path)
} else {
// Parse an unqualified path
(None, self.parse_path(PathStyle::Expr)?)
};
match self.token {
token::Not if qself.is_none() => {
// Parse macro invocation
let path = self.parse_ident_into_path()?;
self.bump();
let delim = self.expect_open_delim()?;
let tts = self.parse_seq_to_end(
&token::CloseDelim(delim),
SeqSep::none(), |p| p.parse_token_tree())?;
let mac = Mac_ { path: path, tts: tts };
pat = PatKind::Mac(codemap::Spanned {node: mac,
span: mk_sp(lo, self.last_span.hi)});
} else {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve
let binding_mode = BindingMode::ByValue(Mutability::Immutable);
pat = self.parse_pat_ident(binding_mode)?;
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree())?;
let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts });
pat = PatKind::Mac(mac);
}
} else {
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
let (qself, path) =
self.parse_qualified_path(PathStyle::Expr)?;
(Some(qself), path)
} else {
// Parse an unqualified path
(None, self.parse_path(PathStyle::Expr)?)
};
match self.token {
token::DotDotDot => {
token::DotDotDot => {
// Parse range
let hi = self.last_span.hi;
let begin =
@ -3664,9 +3641,9 @@ impl<'a> Parser<'a> {
self.bump();
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end);
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
return Err(self.fatal("unexpected `{` after qualified path"));
}
// Parse struct pattern
@ -3678,8 +3655,8 @@ impl<'a> Parser<'a> {
});
self.bump();
pat = PatKind::Struct(path, fields, etc);
}
token::OpenDelim(token::Paren) => {
}
token::OpenDelim(token::Paren) => {
if qself.is_some() {
return Err(self.fatal("unexpected `(` after qualified path"));
}
@ -3688,11 +3665,8 @@ impl<'a> Parser<'a> {
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::TupleStruct(path, fields, ddpos)
}
_ => {
pat = PatKind::Path(qself, path);
}
}
_ => pat = PatKind::Path(qself, path),
}
} else {
// Try to parse everything else as literal with optional minus
@ -3712,7 +3686,6 @@ impl<'a> Parser<'a> {
}
}
}
}
}
let hi = self.last_span.hi;
@ -3894,16 +3867,33 @@ impl<'a> Parser<'a> {
node: StmtKind::Local(self.parse_local(attrs.into())?),
span: mk_sp(lo, self.last_span.hi),
}
} else if self.token.is_ident()
&& !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not) {
// it's a macro invocation:
} else if self.token.is_path_start() && self.token != token::Lt && {
!self.check_keyword(keywords::Union) ||
self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
} {
let pth = self.parse_path(PathStyle::Expr)?;
// Potential trouble: if we allow macros with paths instead of
// idents, we'd need to look ahead past the whole path here...
let pth = self.parse_ident_into_path()?;
self.bump();
if !self.eat(&token::Not) {
let expr = if self.check(&token::OpenDelim(token::Brace)) {
self.parse_struct_expr(lo, pth, ThinVec::new())?
} else {
let hi = self.last_span.hi;
self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new())
};
let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
})?;
return Ok(Some(Stmt {
id: ast::DUMMY_NODE_ID,
node: StmtKind::Expr(expr),
span: mk_sp(lo, self.last_span.hi),
}));
}
// it's a macro invocation
let id = match self.token {
token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
_ => self.parse_ident()?,
@ -4857,17 +4847,14 @@ impl<'a> Parser<'a> {
fn parse_impl_method(&mut self, vis: &Visibility)
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
// code copied from parse_macro_use_or_failure... abstraction!
if !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
&& (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
if self.token.is_path_start() {
// method macro.
let last_span = self.last_span;
self.complain_if_pub_macro(&vis, last_span);
let lo = self.span.lo;
let pth = self.parse_ident_into_path()?;
let pth = self.parse_path(PathStyle::Mod)?;
self.expect(&token::Not)?;
// eat a matched-delimiter token tree:
@ -4875,14 +4862,12 @@ impl<'a> Parser<'a> {
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree())?;
let m_ = Mac_ { path: pth, tts: tts };
let m: ast::Mac = codemap::Spanned { node: m_,
span: mk_sp(lo,
self.last_span.hi) };
if delim != token::Brace {
self.expect(&token::Semi)?
}
Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(m)))
let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
} else {
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
@ -5979,11 +5964,7 @@ impl<'a> Parser<'a> {
lo: BytePos,
visibility: Visibility
) -> PResult<'a, Option<P<Item>>> {
if macros_allowed && !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
&& (self.look_ahead(2, |t| t.is_ident())
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
if macros_allowed && self.token.is_path_start() {
// MACRO INVOCATION ITEM
let last_span = self.last_span;
@ -5992,7 +5973,7 @@ impl<'a> Parser<'a> {
let mac_lo = self.span.lo;
// item macro.
let pth = self.parse_ident_into_path()?;
let pth = self.parse_path(PathStyle::Mod)?;
self.expect(&token::Not)?;
// a 'special' identifier (like what `macro_rules!` uses)
@ -6008,12 +5989,6 @@ impl<'a> Parser<'a> {
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
SeqSep::none(),
|p| p.parse_token_tree())?;
// single-variant-enum... :
let m = Mac_ { path: pth, tts: tts };
let m: ast::Mac = codemap::Spanned { node: m,
span: mk_sp(mac_lo,
self.last_span.hi) };
if delim != token::Brace {
if !self.eat(&token::Semi) {
let last_span = self.last_span;
@ -6024,14 +5999,9 @@ impl<'a> Parser<'a> {
}
}
let item_ = ItemKind::Mac(m);
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
id,
item_,
visibility,
attrs);
let hi = self.last_span.hi;
let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
return Ok(Some(item));
}

View File

@ -8,6 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: expected item, found `parse_error`
// error-pattern: expected one of `!` or `::`, found `<eof>`
include!("auxiliary/issue-21146-inc.rs");
fn main() {}

View File

@ -14,11 +14,8 @@ macro_rules! m {
//~| ERROR macro expansion ignores token `typeof`
//~| ERROR macro expansion ignores token `;`
//~| ERROR macro expansion ignores token `;`
//~| ERROR macro expansion ignores token `i`
}
m!(); //~ NOTE the usage of `m!` is likely invalid in item context
fn main() {
let a: m!(); //~ NOTE the usage of `m!` is likely invalid in type context
let i = m!(); //~ NOTE the usage of `m!` is likely invalid in expression context

View File

@ -0,0 +1,38 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
::foo::bar!(); //~ ERROR expected macro name without module separators
foo::bar!(); //~ ERROR expected macro name without module separators
trait T {
foo::bar!(); //~ ERROR expected macro name without module separators
::foo::bar!(); //~ ERROR expected macro name without module separators
}
struct S {
x: foo::bar!(), //~ ERROR expected macro name without module separators
y: ::foo::bar!(), //~ ERROR expected macro name without module separators
}
impl S {
foo::bar!(); //~ ERROR expected macro name without module separators
::foo::bar!(); //~ ERROR expected macro name without module separators
}
fn main() {
foo::bar!(); //~ ERROR expected macro name without module separators
::foo::bar!(); //~ ERROR expected macro name without module separators
let _ = foo::bar!(); //~ ERROR expected macro name without module separators
let _ = ::foo::bar!(); //~ ERROR expected macro name without module separators
let foo::bar!() = 0; //~ ERROR expected macro name without module separators
let ::foo::bar!() = 0; //~ ERROR expected macro name without module separators
}

View File

@ -30,8 +30,7 @@ pub fn main() {
ref mut Self => (),
//~^ ERROR expected identifier, found keyword `Self`
Self!() => (),
//~^ ERROR expected identifier, found keyword `Self`
//~^^ ERROR macro undefined: 'Self!'
//~^ ERROR macro undefined: 'Self!'
Foo { x: Self } => (),
//~^ ERROR expected identifier, found keyword `Self`
Foo { Self } => (),

View File

@ -11,7 +11,7 @@
// compile-flags: -Z parse-only
extern {
f(); //~ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `f`
f(); //~ ERROR expected one of `!` or `::`, found `(`
}
fn main() {

View File

@ -11,5 +11,6 @@
// compile-flags: -Z parse-only
trait MyTrait<T>: Iterator {
Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
Item = T; //~ ERROR expected one of `!` or `::`, found `=`
//~| ERROR expected item, found `=`
}