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:
commit
1d9646228d
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
38
src/test/compile-fail/paths-in-macro-invocations.rs
Normal file
38
src/test/compile-fail/paths-in-macro-invocations.rs
Normal 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
|
||||
}
|
@ -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 } => (),
|
||||
|
@ -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() {
|
||||
|
@ -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 `=`
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user