Use NonterminalKind for MetaVarDecl
This is more type safe and allows us to remove a few dead branches
This commit is contained in:
parent
2595d75ea9
commit
7fdffe183d
@ -760,7 +760,7 @@ pub enum Nonterminal {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
rustc_data_structures::static_assert_size!(Nonterminal, 40);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum NonterminalKind {
|
||||
Item,
|
||||
Block,
|
||||
@ -796,6 +796,29 @@ impl NonterminalKind {
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
fn symbol(self) -> Symbol {
|
||||
match self {
|
||||
NonterminalKind::Item => sym::item,
|
||||
NonterminalKind::Block => sym::block,
|
||||
NonterminalKind::Stmt => sym::stmt,
|
||||
NonterminalKind::Pat => sym::pat,
|
||||
NonterminalKind::Expr => sym::expr,
|
||||
NonterminalKind::Ty => sym::ty,
|
||||
NonterminalKind::Ident => sym::ident,
|
||||
NonterminalKind::Lifetime => sym::lifetime,
|
||||
NonterminalKind::Literal => sym::literal,
|
||||
NonterminalKind::Meta => sym::meta,
|
||||
NonterminalKind::Path => sym::path,
|
||||
NonterminalKind::Vis => sym::vis,
|
||||
NonterminalKind::TT => sym::tt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NonterminalKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.symbol())
|
||||
}
|
||||
}
|
||||
|
||||
impl Nonterminal {
|
||||
|
@ -9,7 +9,7 @@ crate mod macro_rules;
|
||||
crate mod quoted;
|
||||
crate mod transcribe;
|
||||
|
||||
use rustc_ast::token::{self, Token, TokenKind};
|
||||
use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::DelimSpan;
|
||||
|
||||
use rustc_span::symbol::Ident;
|
||||
@ -84,7 +84,7 @@ enum TokenTree {
|
||||
/// e.g., `$var`
|
||||
MetaVar(Span, Ident),
|
||||
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
|
||||
MetaVarDecl(Span, Ident /* name to bind */, Ident /* kind of nonterminal */),
|
||||
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
||||
}
|
||||
|
||||
impl TokenTree {
|
||||
|
@ -76,10 +76,10 @@ use TokenTreeOrTokenTreeSlice::*;
|
||||
|
||||
use crate::mbe::{self, TokenTree};
|
||||
|
||||
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
|
||||
use rustc_ast::token::{self, DocComment, Nonterminal, Token};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::{kw, MacroRulesNormalizedIdent};
|
||||
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
@ -378,7 +378,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
|
||||
n_rec(sess, next_m, res.by_ref(), ret_val)?;
|
||||
}
|
||||
}
|
||||
TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => {
|
||||
TokenTree::MetaVarDecl(span, _, None) => {
|
||||
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
|
||||
return Err((span, "missing fragment specifier".to_string()));
|
||||
}
|
||||
@ -561,7 +561,7 @@ fn inner_parse_loop<'root, 'tt>(
|
||||
}
|
||||
|
||||
// We need to match a metavar (but the identifier is invalid)... this is an error
|
||||
TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => {
|
||||
TokenTree::MetaVarDecl(span, _, None) => {
|
||||
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
|
||||
return Error(span, "missing fragment specifier".to_string());
|
||||
}
|
||||
@ -569,10 +569,9 @@ fn inner_parse_loop<'root, 'tt>(
|
||||
|
||||
// We need to match a metavar with a valid ident... call out to the black-box
|
||||
// parser by adding an item to `bb_items`.
|
||||
TokenTree::MetaVarDecl(_, _, id) => {
|
||||
TokenTree::MetaVarDecl(_, _, Some(kind)) => {
|
||||
// Built-in nonterminals never start with these tokens,
|
||||
// so we can eliminate them from consideration.
|
||||
let kind = NonterminalKind::from_symbol(id.name).unwrap();
|
||||
if Parser::nonterminal_may_begin_with(kind, token) {
|
||||
bb_items.push(item);
|
||||
}
|
||||
@ -703,7 +702,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
||||
let nts = bb_items
|
||||
.iter()
|
||||
.map(|item| match item.top_elts.get_tt(item.idx) {
|
||||
TokenTree::MetaVarDecl(_, bind, name) => format!("{} ('{}')", name, bind),
|
||||
TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
|
||||
_ => panic!(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
@ -733,17 +732,13 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
||||
assert_eq!(bb_items.len(), 1);
|
||||
|
||||
let mut item = bb_items.pop().unwrap();
|
||||
if let TokenTree::MetaVarDecl(span, _, ident) = item.top_elts.get_tt(item.idx) {
|
||||
if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
|
||||
let match_cur = item.match_cur;
|
||||
let kind = NonterminalKind::from_symbol(ident.name).unwrap();
|
||||
let nt = match parser.to_mut().parse_nonterminal(kind) {
|
||||
Err(mut err) => {
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"while parsing argument for this `{}` macro fragment",
|
||||
ident.name
|
||||
),
|
||||
format!("while parsing argument for this `{}` macro fragment", kind),
|
||||
)
|
||||
.emit();
|
||||
return ErrorReported;
|
||||
|
@ -21,7 +21,7 @@ use rustc_parse::parser::Parser;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent, Symbol};
|
||||
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
|
||||
use rustc_span::Span;
|
||||
|
||||
use log::debug;
|
||||
@ -29,10 +29,6 @@ use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{mem, slice};
|
||||
|
||||
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
||||
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
|
||||
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
|
||||
|
||||
crate struct ParserAnyMacro<'a> {
|
||||
parser: Parser<'a>,
|
||||
|
||||
@ -403,7 +399,7 @@ pub fn compile_declarative_macro(
|
||||
let diag = &sess.span_diagnostic;
|
||||
let lhs_nm = Ident::new(sym::lhs, def.span);
|
||||
let rhs_nm = Ident::new(sym::rhs, def.span);
|
||||
let tt_spec = Ident::new(sym::tt, def.span);
|
||||
let tt_spec = Some(NonterminalKind::TT);
|
||||
|
||||
// Parse the macro_rules! invocation
|
||||
let (macro_rules, body) = match &def.kind {
|
||||
@ -571,7 +567,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
||||
TokenTree::Sequence(span, ref seq) => {
|
||||
if seq.separator.is_none()
|
||||
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
|
||||
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
|
||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
|
||||
TokenTree::Sequence(_, ref sub_seq) => {
|
||||
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
||||
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
|
||||
@ -890,21 +886,7 @@ fn check_matcher_core(
|
||||
// of NT tokens that might end the sequence `... token`.
|
||||
match *token {
|
||||
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
|
||||
let can_be_followed_by_any;
|
||||
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) {
|
||||
let msg = format!("invalid fragment specifier `{}`", bad_frag);
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(token.span(), &msg)
|
||||
.help(VALID_FRAGMENT_NAMES_MSG)
|
||||
.emit();
|
||||
// (This eliminates false positives and duplicates
|
||||
// from error messages.)
|
||||
can_be_followed_by_any = true;
|
||||
} else {
|
||||
can_be_followed_by_any = token_can_be_followed_by_any(token);
|
||||
}
|
||||
|
||||
if can_be_followed_by_any {
|
||||
if token_can_be_followed_by_any(token) {
|
||||
// don't need to track tokens that work with any,
|
||||
last.replace_with_irrelevant();
|
||||
// ... and don't need to check tokens that can be
|
||||
@ -967,19 +949,10 @@ fn check_matcher_core(
|
||||
|
||||
// Now `last` holds the complete set of NT tokens that could
|
||||
// end the sequence before SUFFIX. Check that every one works with `suffix`.
|
||||
'each_last: for token in &last.tokens {
|
||||
if let TokenTree::MetaVarDecl(_, name, frag_spec) = *token {
|
||||
for token in &last.tokens {
|
||||
if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token {
|
||||
for next_token in &suffix_first.tokens {
|
||||
match is_in_follow(next_token, frag_spec.name) {
|
||||
IsInFollow::Invalid(msg, help) => {
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(next_token.span(), &msg)
|
||||
.help(help)
|
||||
.emit();
|
||||
// don't bother reporting every source of
|
||||
// conflict for a particular element of `last`.
|
||||
continue 'each_last;
|
||||
}
|
||||
match is_in_follow(next_token, kind) {
|
||||
IsInFollow::Yes => {}
|
||||
IsInFollow::No(possible) => {
|
||||
let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1
|
||||
@ -996,22 +969,19 @@ fn check_matcher_core(
|
||||
"`${name}:{frag}` {may_be} followed by `{next}`, which \
|
||||
is not allowed for `{frag}` fragments",
|
||||
name = name,
|
||||
frag = frag_spec,
|
||||
frag = kind,
|
||||
next = quoted_tt_to_string(next_token),
|
||||
may_be = may_be
|
||||
),
|
||||
);
|
||||
err.span_label(
|
||||
sp,
|
||||
format!("not allowed after `{}` fragments", frag_spec),
|
||||
);
|
||||
err.span_label(sp, format!("not allowed after `{}` fragments", kind));
|
||||
let msg = "allowed there are: ";
|
||||
match possible {
|
||||
&[] => {}
|
||||
&[t] => {
|
||||
err.note(&format!(
|
||||
"only {} is allowed after `{}` fragments",
|
||||
t, frag_spec,
|
||||
t, kind,
|
||||
));
|
||||
}
|
||||
ts => {
|
||||
@ -1038,8 +1008,8 @@ fn check_matcher_core(
|
||||
}
|
||||
|
||||
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
|
||||
if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
|
||||
frag_can_be_followed_by_any(frag_spec.name)
|
||||
if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
|
||||
frag_can_be_followed_by_any(kind)
|
||||
} else {
|
||||
// (Non NT's can always be followed by anything in matchers.)
|
||||
true
|
||||
@ -1054,26 +1024,23 @@ fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
|
||||
/// specifier which consumes at most one token tree can be followed by
|
||||
/// a fragment specifier (indeed, these fragments can be followed by
|
||||
/// ANYTHING without fear of future compatibility hazards).
|
||||
fn frag_can_be_followed_by_any(frag: Symbol) -> bool {
|
||||
match frag {
|
||||
sym::item | // always terminated by `}` or `;`
|
||||
sym::block | // exactly one token tree
|
||||
sym::ident | // exactly one token tree
|
||||
sym::literal | // exactly one token tree
|
||||
sym::meta | // exactly one token tree
|
||||
sym::lifetime | // exactly one token tree
|
||||
sym::tt => // exactly one token tree
|
||||
true,
|
||||
fn frag_can_be_followed_by_any(kind: NonterminalKind) -> bool {
|
||||
match kind {
|
||||
NonterminalKind::Item // always terminated by `}` or `;`
|
||||
| NonterminalKind::Block // exactly one token tree
|
||||
| NonterminalKind::Ident // exactly one token tree
|
||||
| NonterminalKind::Literal // exactly one token tree
|
||||
| NonterminalKind::Meta // exactly one token tree
|
||||
| NonterminalKind::Lifetime // exactly one token tree
|
||||
| NonterminalKind::TT => true, // exactly one token tree
|
||||
|
||||
_ =>
|
||||
false,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
enum IsInFollow {
|
||||
Yes,
|
||||
No(&'static [&'static str]),
|
||||
Invalid(String, &'static str),
|
||||
}
|
||||
|
||||
/// Returns `true` if `frag` can legally be followed by the token `tok`. For
|
||||
@ -1084,7 +1051,7 @@ enum IsInFollow {
|
||||
/// break macros that were relying on that binary operator as a
|
||||
/// separator.
|
||||
// when changing this do not forget to update doc/book/macros.md!
|
||||
fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
||||
use mbe::TokenTree;
|
||||
|
||||
if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
|
||||
@ -1092,18 +1059,18 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
// iow, we always require that `(` and `)` match, etc.
|
||||
IsInFollow::Yes
|
||||
} else {
|
||||
match frag {
|
||||
sym::item => {
|
||||
match kind {
|
||||
NonterminalKind::Item => {
|
||||
// since items *must* be followed by either a `;` or a `}`, we can
|
||||
// accept anything after them
|
||||
IsInFollow::Yes
|
||||
}
|
||||
sym::block => {
|
||||
NonterminalKind::Block => {
|
||||
// anything can follow block, the braces provide an easy boundary to
|
||||
// maintain
|
||||
IsInFollow::Yes
|
||||
}
|
||||
sym::stmt | sym::expr => {
|
||||
NonterminalKind::Stmt | NonterminalKind::Expr => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
@ -1113,7 +1080,7 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
sym::pat => {
|
||||
NonterminalKind::Pat => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
@ -1124,7 +1091,7 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
sym::path | sym::ty => {
|
||||
NonterminalKind::Path | NonterminalKind::Ty => {
|
||||
const TOKENS: &[&str] = &[
|
||||
"`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
|
||||
"`where`",
|
||||
@ -1146,26 +1113,24 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
}
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
},
|
||||
TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => {
|
||||
IsInFollow::Yes
|
||||
}
|
||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
sym::ident | sym::lifetime => {
|
||||
NonterminalKind::Ident | NonterminalKind::Lifetime => {
|
||||
// being a single token, idents and lifetimes are harmless
|
||||
IsInFollow::Yes
|
||||
}
|
||||
sym::literal => {
|
||||
NonterminalKind::Literal => {
|
||||
// literals may be of a single token, or two tokens (negative numbers)
|
||||
IsInFollow::Yes
|
||||
}
|
||||
sym::meta | sym::tt => {
|
||||
NonterminalKind::Meta | NonterminalKind::TT => {
|
||||
// being either a single token or a delimited sequence, tt is
|
||||
// harmless
|
||||
IsInFollow::Yes
|
||||
}
|
||||
sym::vis => {
|
||||
NonterminalKind::Vis => {
|
||||
// Explicitly disallow `priv`, on the off chance it comes back.
|
||||
const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
|
||||
match tok {
|
||||
@ -1180,62 +1145,24 @@ fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow {
|
||||
}
|
||||
}
|
||||
},
|
||||
TokenTree::MetaVarDecl(_, _, frag)
|
||||
if frag.name == sym::ident
|
||||
|| frag.name == sym::ty
|
||||
|| frag.name == sym::path =>
|
||||
{
|
||||
IsInFollow::Yes
|
||||
}
|
||||
TokenTree::MetaVarDecl(
|
||||
_,
|
||||
_,
|
||||
Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
|
||||
) => IsInFollow::Yes,
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
kw::Invalid => IsInFollow::Yes,
|
||||
_ => IsInFollow::Invalid(
|
||||
format!("invalid fragment specifier `{}`", frag),
|
||||
VALID_FRAGMENT_NAMES_MSG,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_legal_fragment_specifier(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
tok: &mbe::TokenTree,
|
||||
) -> Result<(), String> {
|
||||
debug!("has_legal_fragment_specifier({:?})", tok);
|
||||
if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
|
||||
let frag_span = tok.span();
|
||||
if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) {
|
||||
return Err(frag_spec.to_string());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_legal_fragment_specifier(
|
||||
_sess: &ParseSess,
|
||||
_features: &Features,
|
||||
_attrs: &[ast::Attribute],
|
||||
frag_name: Symbol,
|
||||
_frag_span: Span,
|
||||
) -> bool {
|
||||
/*
|
||||
* If new fragment specifiers are invented in nightly, `_sess`,
|
||||
* `_features`, `_attrs`, and `_frag_span` will be useful here
|
||||
* for checking against feature gates. See past versions of
|
||||
* this function.
|
||||
*/
|
||||
NonterminalKind::from_symbol(frag_name).is_some() || frag_name == kw::Invalid
|
||||
}
|
||||
|
||||
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
|
||||
match *tt {
|
||||
mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
|
||||
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
|
||||
_ => panic!(
|
||||
"unexpected mbe::TokenTree::{{Sequence or Delimited}} \
|
||||
in follow set checker"
|
||||
|
@ -12,6 +12,10 @@ use rustc_span::Span;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
||||
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
|
||||
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
|
||||
|
||||
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
|
||||
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
|
||||
/// collection of `TokenTree` for use in parsing a macro.
|
||||
@ -55,9 +59,21 @@ pub(super) fn parse(
|
||||
Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
|
||||
match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
|
||||
Some((kind, _)) => {
|
||||
Some((frag, _)) => {
|
||||
let span = token.span.with_lo(start_sp.lo());
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, kind));
|
||||
let kind = token::NonterminalKind::from_symbol(frag.name)
|
||||
.unwrap_or_else(|| {
|
||||
let msg = format!(
|
||||
"invalid fragment specifier `{}`",
|
||||
frag.name
|
||||
);
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(span, &msg)
|
||||
.help(VALID_FRAGMENT_NAMES_MSG)
|
||||
.emit();
|
||||
token::NonterminalKind::Ident
|
||||
});
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
|
||||
continue;
|
||||
}
|
||||
_ => token.span,
|
||||
@ -71,7 +87,7 @@ pub(super) fn parse(
|
||||
// Macros loaded from other crates have dummy node ids.
|
||||
sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
|
||||
}
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, Ident::invalid()));
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
||||
}
|
||||
|
||||
// Not a metavar or no matchers allowed, so just return the tree
|
||||
|
Loading…
x
Reference in New Issue
Block a user