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
7 changed files with 269 additions and 264 deletions
|
@ -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.
|
/// 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
|
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
|
||||||
|
@ -1202,94 +1197,87 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
(ident, TraitItemKind::Const(ty, default))
|
(ident, TraitItemKind::Const(ty, default))
|
||||||
} else if !self.token.is_any_keyword()
|
} else if self.token.is_path_start() {
|
||||||
&& self.look_ahead(1, |t| *t == token::Not)
|
// trait item macro.
|
||||||
&& (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
|
// code copied from parse_macro_use_or_failure... abstraction!
|
||||||
|| self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
|
let lo = self.span.lo;
|
||||||
// trait item macro.
|
let pth = self.parse_path(PathStyle::Mod)?;
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
self.expect(&token::Not)?;
|
||||||
let lo = self.span.lo;
|
|
||||||
let pth = self.parse_ident_into_path()?;
|
|
||||||
self.expect(&token::Not)?;
|
|
||||||
|
|
||||||
// eat a matched-delimiter token tree:
|
// eat a matched-delimiter token tree:
|
||||||
let delim = self.expect_open_delim()?;
|
let delim = self.expect_open_delim()?;
|
||||||
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
SeqSep::none(),
|
SeqSep::none(),
|
||||||
|pp| pp.parse_token_tree())?;
|
|pp| pp.parse_token_tree())?;
|
||||||
let m_ = Mac_ { path: pth, tts: tts };
|
if delim != token::Brace {
|
||||||
let m: ast::Mac = codemap::Spanned { node: m_,
|
self.expect(&token::Semi)?
|
||||||
span: mk_sp(lo,
|
}
|
||||||
self.last_span.hi) };
|
|
||||||
if delim != token::Brace {
|
let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
|
||||||
self.expect(&token::Semi)?
|
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
|
||||||
}
|
} else {
|
||||||
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
|
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
|
||||||
} else {
|
Ok(cua) => cua,
|
||||||
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
|
Err(e) => {
|
||||||
Ok(cua) => cua,
|
loop {
|
||||||
Err(e) => {
|
match self.token {
|
||||||
loop {
|
token::Eof => break,
|
||||||
match self.token {
|
token::CloseDelim(token::Brace) |
|
||||||
token::Eof => break,
|
token::Semi => {
|
||||||
token::CloseDelim(token::Brace) |
|
self.bump();
|
||||||
token::Semi => {
|
break;
|
||||||
self.bump();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token::OpenDelim(token::Brace) => {
|
|
||||||
self.parse_token_tree()?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => self.bump()
|
|
||||||
}
|
}
|
||||||
|
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
return Err(e);
|
||||||
let token_str = self.this_token_to_string();
|
}
|
||||||
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
|
|
||||||
token_str)[..]))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(ident, ast::TraitItemKind::Method(sig, body))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 {
|
Ok(TraitItem {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
ident: name,
|
ident: name,
|
||||||
|
@ -1430,9 +1418,8 @@ impl<'a> Parser<'a> {
|
||||||
TyKind::Path(Some(qself), path)
|
TyKind::Path(Some(qself), path)
|
||||||
} else if self.token.is_path_start() {
|
} else if self.token.is_path_start() {
|
||||||
let path = self.parse_path(PathStyle::Type)?;
|
let path = self.parse_path(PathStyle::Type)?;
|
||||||
if self.check(&token::Not) {
|
if self.eat(&token::Not) {
|
||||||
// MACRO INVOCATION
|
// MACRO INVOCATION
|
||||||
self.bump();
|
|
||||||
let delim = self.expect_open_delim()?;
|
let delim = self.expect_open_delim()?;
|
||||||
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
SeqSep::none(),
|
SeqSep::none(),
|
||||||
|
@ -2310,21 +2297,14 @@ impl<'a> Parser<'a> {
|
||||||
let pth = self.parse_path(PathStyle::Expr)?;
|
let pth = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
// `!`, as an operator, is prefix, so we know this isn't that
|
// `!`, 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
|
// MACRO INVOCATION expression
|
||||||
self.bump();
|
|
||||||
|
|
||||||
let delim = self.expect_open_delim()?;
|
let delim = self.expect_open_delim()?;
|
||||||
let tts = self.parse_seq_to_end(
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
&token::CloseDelim(delim),
|
SeqSep::none(),
|
||||||
SeqSep::none(),
|
|p| p.parse_token_tree())?;
|
||||||
|p| p.parse_token_tree())?;
|
|
||||||
let hi = self.last_span.hi;
|
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)) {
|
if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
// This is a struct literal, unless we're prohibited
|
// This is a struct literal, unless we're prohibited
|
||||||
|
@ -2333,51 +2313,7 @@ impl<'a> Parser<'a> {
|
||||||
Restrictions::RESTRICTION_NO_STRUCT_LITERAL
|
Restrictions::RESTRICTION_NO_STRUCT_LITERAL
|
||||||
);
|
);
|
||||||
if !prohibited {
|
if !prohibited {
|
||||||
// It's a struct literal.
|
return self.parse_struct_expr(lo, pth, attrs);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2403,6 +2339,53 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(self.mk_expr(lo, hi, ex, attrs));
|
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,
|
fn parse_or_use_outer_attributes(&mut self,
|
||||||
already_parsed_attrs: Option<ThinVec<Attribute>>)
|
already_parsed_attrs: Option<ThinVec<Attribute>>)
|
||||||
-> PResult<'a, ThinVec<Attribute>> {
|
-> PResult<'a, ThinVec<Attribute>> {
|
||||||
|
@ -3577,39 +3560,37 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let pat;
|
let pat;
|
||||||
match self.token {
|
match self.token {
|
||||||
token::Underscore => {
|
token::Underscore => {
|
||||||
// Parse _
|
// Parse _
|
||||||
self.bump();
|
self.bump();
|
||||||
pat = PatKind::Wild;
|
pat = PatKind::Wild;
|
||||||
}
|
}
|
||||||
token::BinOp(token::And) | token::AndAnd => {
|
token::BinOp(token::And) | token::AndAnd => {
|
||||||
// Parse &pat / &mut pat
|
// Parse &pat / &mut pat
|
||||||
self.expect_and()?;
|
self.expect_and()?;
|
||||||
let mutbl = self.parse_mutability()?;
|
let mutbl = self.parse_mutability()?;
|
||||||
if let token::Lifetime(ident) = self.token {
|
if let token::Lifetime(ident) = self.token {
|
||||||
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
|
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 != _, &, &&, (, [
|
// At this point, token != _, &, &&, (, [
|
||||||
if self.eat_keyword(keywords::Mut) {
|
_ => if self.eat_keyword(keywords::Mut) {
|
||||||
// Parse mut ident @ pat
|
// Parse mut ident @ pat
|
||||||
pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?;
|
pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?;
|
||||||
} else if self.eat_keyword(keywords::Ref) {
|
} else if self.eat_keyword(keywords::Ref) {
|
||||||
|
@ -3620,43 +3601,39 @@ impl<'a> Parser<'a> {
|
||||||
// Parse box pat
|
// Parse box pat
|
||||||
let subpat = self.parse_pat()?;
|
let subpat = self.parse_pat()?;
|
||||||
pat = PatKind::Box(subpat);
|
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() {
|
} else if self.token.is_path_start() {
|
||||||
// Parse pattern starting with a path
|
// Parse pattern starting with a path
|
||||||
if self.token.is_ident() && self.look_ahead(1, |t| *t != token::DotDotDot &&
|
let (qself, path) = if self.eat_lt() {
|
||||||
*t != token::OpenDelim(token::Brace) &&
|
// Parse a qualified path
|
||||||
*t != token::OpenDelim(token::Paren) &&
|
let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?;
|
||||||
*t != token::ModSep) {
|
(Some(qself), path)
|
||||||
// Plain idents have some extra abilities here compared to general paths
|
} else {
|
||||||
if self.look_ahead(1, |t| *t == token::Not) {
|
// Parse an unqualified path
|
||||||
|
(None, self.parse_path(PathStyle::Expr)?)
|
||||||
|
};
|
||||||
|
match self.token {
|
||||||
|
token::Not if qself.is_none() => {
|
||||||
// Parse macro invocation
|
// Parse macro invocation
|
||||||
let path = self.parse_ident_into_path()?;
|
|
||||||
self.bump();
|
self.bump();
|
||||||
let delim = self.expect_open_delim()?;
|
let delim = self.expect_open_delim()?;
|
||||||
let tts = self.parse_seq_to_end(
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
&token::CloseDelim(delim),
|
SeqSep::none(),
|
||||||
SeqSep::none(), |p| p.parse_token_tree())?;
|
|p| p.parse_token_tree())?;
|
||||||
let mac = Mac_ { path: path, tts: tts };
|
let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts });
|
||||||
pat = PatKind::Mac(codemap::Spanned {node: mac,
|
pat = PatKind::Mac(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)?;
|
|
||||||
}
|
}
|
||||||
} else {
|
token::DotDotDot => {
|
||||||
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 => {
|
|
||||||
// Parse range
|
// Parse range
|
||||||
let hi = self.last_span.hi;
|
let hi = self.last_span.hi;
|
||||||
let begin =
|
let begin =
|
||||||
|
@ -3664,9 +3641,9 @@ impl<'a> Parser<'a> {
|
||||||
self.bump();
|
self.bump();
|
||||||
let end = self.parse_pat_range_end()?;
|
let end = self.parse_pat_range_end()?;
|
||||||
pat = PatKind::Range(begin, end);
|
pat = PatKind::Range(begin, end);
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Brace) => {
|
token::OpenDelim(token::Brace) => {
|
||||||
if qself.is_some() {
|
if qself.is_some() {
|
||||||
return Err(self.fatal("unexpected `{` after qualified path"));
|
return Err(self.fatal("unexpected `{` after qualified path"));
|
||||||
}
|
}
|
||||||
// Parse struct pattern
|
// Parse struct pattern
|
||||||
|
@ -3678,8 +3655,8 @@ impl<'a> Parser<'a> {
|
||||||
});
|
});
|
||||||
self.bump();
|
self.bump();
|
||||||
pat = PatKind::Struct(path, fields, etc);
|
pat = PatKind::Struct(path, fields, etc);
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Paren) => {
|
token::OpenDelim(token::Paren) => {
|
||||||
if qself.is_some() {
|
if qself.is_some() {
|
||||||
return Err(self.fatal("unexpected `(` after qualified path"));
|
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)?;
|
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
pat = PatKind::TupleStruct(path, fields, ddpos)
|
pat = PatKind::TupleStruct(path, fields, ddpos)
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
pat = PatKind::Path(qself, path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_ => pat = PatKind::Path(qself, path),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Try to parse everything else as literal with optional minus
|
// Try to parse everything else as literal with optional minus
|
||||||
|
@ -3712,7 +3686,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let hi = self.last_span.hi;
|
let hi = self.last_span.hi;
|
||||||
|
@ -3894,16 +3867,33 @@ impl<'a> Parser<'a> {
|
||||||
node: StmtKind::Local(self.parse_local(attrs.into())?),
|
node: StmtKind::Local(self.parse_local(attrs.into())?),
|
||||||
span: mk_sp(lo, self.last_span.hi),
|
span: mk_sp(lo, self.last_span.hi),
|
||||||
}
|
}
|
||||||
} else if self.token.is_ident()
|
} else if self.token.is_path_start() && self.token != token::Lt && {
|
||||||
&& !self.token.is_any_keyword()
|
!self.check_keyword(keywords::Union) ||
|
||||||
&& self.look_ahead(1, |t| *t == token::Not) {
|
self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
|
||||||
// it's a macro invocation:
|
} {
|
||||||
|
let pth = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
// Potential trouble: if we allow macros with paths instead of
|
if !self.eat(&token::Not) {
|
||||||
// idents, we'd need to look ahead past the whole path here...
|
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
let pth = self.parse_ident_into_path()?;
|
self.parse_struct_expr(lo, pth, ThinVec::new())?
|
||||||
self.bump();
|
} 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 {
|
let id = match self.token {
|
||||||
token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
|
token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
|
||||||
_ => self.parse_ident()?,
|
_ => self.parse_ident()?,
|
||||||
|
@ -4857,17 +4847,14 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_impl_method(&mut self, vis: &Visibility)
|
fn parse_impl_method(&mut self, vis: &Visibility)
|
||||||
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
|
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
// code copied from parse_macro_use_or_failure... abstraction!
|
||||||
if !self.token.is_any_keyword()
|
if self.token.is_path_start() {
|
||||||
&& 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))) {
|
|
||||||
// method macro.
|
// method macro.
|
||||||
|
|
||||||
let last_span = self.last_span;
|
let last_span = self.last_span;
|
||||||
self.complain_if_pub_macro(&vis, last_span);
|
self.complain_if_pub_macro(&vis, last_span);
|
||||||
|
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let pth = self.parse_ident_into_path()?;
|
let pth = self.parse_path(PathStyle::Mod)?;
|
||||||
self.expect(&token::Not)?;
|
self.expect(&token::Not)?;
|
||||||
|
|
||||||
// eat a matched-delimiter token tree:
|
// eat a matched-delimiter token tree:
|
||||||
|
@ -4875,14 +4862,12 @@ impl<'a> Parser<'a> {
|
||||||
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
SeqSep::none(),
|
SeqSep::none(),
|
||||||
|p| p.parse_token_tree())?;
|
|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 {
|
if delim != token::Brace {
|
||||||
self.expect(&token::Semi)?
|
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 {
|
} else {
|
||||||
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
|
@ -5979,11 +5964,7 @@ impl<'a> Parser<'a> {
|
||||||
lo: BytePos,
|
lo: BytePos,
|
||||||
visibility: Visibility
|
visibility: Visibility
|
||||||
) -> PResult<'a, Option<P<Item>>> {
|
) -> PResult<'a, Option<P<Item>>> {
|
||||||
if macros_allowed && !self.token.is_any_keyword()
|
if macros_allowed && self.token.is_path_start() {
|
||||||
&& 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))) {
|
|
||||||
// MACRO INVOCATION ITEM
|
// MACRO INVOCATION ITEM
|
||||||
|
|
||||||
let last_span = self.last_span;
|
let last_span = self.last_span;
|
||||||
|
@ -5992,7 +5973,7 @@ impl<'a> Parser<'a> {
|
||||||
let mac_lo = self.span.lo;
|
let mac_lo = self.span.lo;
|
||||||
|
|
||||||
// item macro.
|
// item macro.
|
||||||
let pth = self.parse_ident_into_path()?;
|
let pth = self.parse_path(PathStyle::Mod)?;
|
||||||
self.expect(&token::Not)?;
|
self.expect(&token::Not)?;
|
||||||
|
|
||||||
// a 'special' identifier (like what `macro_rules!` uses)
|
// 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),
|
let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
|
||||||
SeqSep::none(),
|
SeqSep::none(),
|
||||||
|p| p.parse_token_tree())?;
|
|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 delim != token::Brace {
|
||||||
if !self.eat(&token::Semi) {
|
if !self.eat(&token::Semi) {
|
||||||
let last_span = self.last_span;
|
let last_span = self.last_span;
|
||||||
|
@ -6024,14 +5999,9 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_ = ItemKind::Mac(m);
|
let hi = self.last_span.hi;
|
||||||
let last_span = self.last_span;
|
let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
|
||||||
let item = self.mk_item(lo,
|
let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
|
||||||
last_span.hi,
|
|
||||||
id,
|
|
||||||
item_,
|
|
||||||
visibility,
|
|
||||||
attrs);
|
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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");
|
include!("auxiliary/issue-21146-inc.rs");
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -14,11 +14,8 @@ macro_rules! m {
|
||||||
//~| ERROR macro expansion ignores token `typeof`
|
//~| ERROR macro expansion ignores token `typeof`
|
||||||
//~| ERROR macro expansion ignores token `;`
|
//~| ERROR macro expansion ignores token `;`
|
||||||
//~| 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() {
|
fn main() {
|
||||||
let a: m!(); //~ NOTE the usage of `m!` is likely invalid in type context
|
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
|
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 => (),
|
ref mut Self => (),
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
Self!() => (),
|
Self!() => (),
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR macro undefined: 'Self!'
|
||||||
//~^^ ERROR macro undefined: 'Self!'
|
|
||||||
Foo { x: Self } => (),
|
Foo { x: Self } => (),
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
Foo { Self } => (),
|
Foo { Self } => (),
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
f(); //~ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `f`
|
f(); //~ ERROR expected one of `!` or `::`, found `(`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -11,5 +11,6 @@
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
trait MyTrait<T>: Iterator {
|
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…
Add table
Add a link
Reference in a new issue