Rollup merge of #142657 - tgross35:nonoptional-fragment-specifiers-cleanup, r=petrochenkov
mbe: Clean up code with non-optional `NonterminalKind` Since [rust-lang/rust#128425], the fragment specifier is unconditionally required in all editions. This means `NonTerminalKind` no longer needs to be optional, as we can reject this code during the expansion of `macro_rules!` rather than handling it throughout the code. Do this cleanup here. [rust-lang/rust#128425]: https://github.com/rust-lang/rust/pull/128425
This commit is contained in:
@@ -1085,6 +1085,7 @@ pub enum NtExprKind {
|
||||
Expr2021 { inferred: bool },
|
||||
}
|
||||
|
||||
/// A macro nonterminal, known in documentation as a fragment specifier.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||
pub enum NonterminalKind {
|
||||
Item,
|
||||
|
||||
@@ -444,7 +444,7 @@ pub(crate) struct InvalidFragmentSpecifier {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub fragment: Ident,
|
||||
pub help: String,
|
||||
pub help: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -78,7 +78,13 @@ enum TokenTree {
|
||||
/// only covers the ident, e.g. `var`.)
|
||||
MetaVar(Span, Ident),
|
||||
/// e.g., `$var:expr`. Only appears on the LHS.
|
||||
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
||||
MetaVarDecl {
|
||||
span: Span,
|
||||
/// Name to bind.
|
||||
name: Ident,
|
||||
/// The fragment specifier.
|
||||
kind: NonterminalKind,
|
||||
},
|
||||
/// A meta-variable expression inside `${...}`.
|
||||
MetaVarExpr(DelimSpan, MetaVarExpr),
|
||||
}
|
||||
@@ -102,7 +108,7 @@ impl TokenTree {
|
||||
match *self {
|
||||
TokenTree::Token(Token { span, .. })
|
||||
| TokenTree::MetaVar(span, _)
|
||||
| TokenTree::MetaVarDecl(span, _, _) => span,
|
||||
| TokenTree::MetaVarDecl { span, .. } => span,
|
||||
TokenTree::Delimited(span, ..)
|
||||
| TokenTree::MetaVarExpr(span, _)
|
||||
| TokenTree::Sequence(span, _) => span.entire(),
|
||||
|
||||
@@ -24,6 +24,7 @@ pub(super) fn failed_to_match_macro(
|
||||
arg: TokenStream,
|
||||
lhses: &[Vec<MatcherLoc>],
|
||||
) -> (Span, ErrorGuaranteed) {
|
||||
debug!("failed to match macro");
|
||||
// An error occurred, try the expansion again, tracking the expansion closely for better
|
||||
// diagnostics.
|
||||
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
|
||||
|
||||
@@ -117,7 +117,6 @@ use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::quoted::VALID_FRAGMENT_NAMES_MSG;
|
||||
use crate::errors;
|
||||
use crate::mbe::{KleeneToken, TokenTree};
|
||||
|
||||
@@ -263,14 +262,7 @@ fn check_binders(
|
||||
}
|
||||
}
|
||||
// Similarly, this can only happen when checking a toplevel macro.
|
||||
TokenTree::MetaVarDecl(span, name, kind) => {
|
||||
if kind.is_none() && node_id != DUMMY_NODE_ID {
|
||||
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
|
||||
span,
|
||||
add_span: span.shrink_to_hi(),
|
||||
valid: VALID_FRAGMENT_NAMES_MSG,
|
||||
});
|
||||
}
|
||||
TokenTree::MetaVarDecl { span, name, .. } => {
|
||||
if !macros.is_empty() {
|
||||
psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
|
||||
}
|
||||
@@ -339,7 +331,7 @@ fn check_occurrences(
|
||||
) {
|
||||
match *rhs {
|
||||
TokenTree::Token(..) => {}
|
||||
TokenTree::MetaVarDecl(span, _name, _kind) => {
|
||||
TokenTree::MetaVarDecl { span, .. } => {
|
||||
psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs")
|
||||
}
|
||||
TokenTree::MetaVar(span, name) => {
|
||||
|
||||
@@ -122,7 +122,7 @@ pub(crate) enum MatcherLoc {
|
||||
MetaVarDecl {
|
||||
span: Span,
|
||||
bind: Ident,
|
||||
kind: Option<NonterminalKind>,
|
||||
kind: NonterminalKind,
|
||||
next_metavar: usize,
|
||||
seq_depth: usize,
|
||||
},
|
||||
@@ -151,12 +151,7 @@ impl Display for MatcherLoc {
|
||||
write!(f, "{}", token_descr(token))
|
||||
}
|
||||
MatcherLoc::MetaVarDecl { bind, kind, .. } => {
|
||||
write!(f, "meta-variable `${bind}")?;
|
||||
if let Some(kind) = kind {
|
||||
write!(f, ":{kind}")?;
|
||||
}
|
||||
write!(f, "`")?;
|
||||
Ok(())
|
||||
write!(f, "meta-variable `${bind}:{kind}`")
|
||||
}
|
||||
MatcherLoc::Eof => f.write_str("end of macro"),
|
||||
|
||||
@@ -220,7 +215,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
|
||||
seq_depth,
|
||||
};
|
||||
}
|
||||
&TokenTree::MetaVarDecl(span, bind, kind) => {
|
||||
&TokenTree::MetaVarDecl { span, name: bind, kind } => {
|
||||
locs.push(MatcherLoc::MetaVarDecl {
|
||||
span,
|
||||
bind,
|
||||
@@ -330,7 +325,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
|
||||
matcher
|
||||
.iter()
|
||||
.map(|tt| match tt {
|
||||
TokenTree::MetaVarDecl(..) => 1,
|
||||
TokenTree::MetaVarDecl { .. } => 1,
|
||||
TokenTree::Sequence(_, seq) => seq.num_captures,
|
||||
TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts),
|
||||
TokenTree::Token(..) => 0,
|
||||
@@ -551,19 +546,13 @@ impl TtParser {
|
||||
mp.idx = idx_first;
|
||||
self.cur_mps.push(mp);
|
||||
}
|
||||
&MatcherLoc::MetaVarDecl { span, kind, .. } => {
|
||||
&MatcherLoc::MetaVarDecl { kind, .. } => {
|
||||
// Built-in nonterminals never start with these tokens, so we can eliminate
|
||||
// them from consideration. We use the span of the metavariable declaration
|
||||
// to determine any edition-specific matching behavior for non-terminals.
|
||||
if let Some(kind) = kind {
|
||||
if Parser::nonterminal_may_begin_with(kind, token) {
|
||||
self.bb_mps.push(mp);
|
||||
}
|
||||
} else {
|
||||
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
|
||||
// Both this check and the one in `nameize` are necessary, surprisingly.
|
||||
return Some(Error(span, "missing fragment specifier".to_string()));
|
||||
}
|
||||
}
|
||||
MatcherLoc::Eof => {
|
||||
// We are past the matcher's end, and not in a sequence. Try to end things.
|
||||
@@ -666,11 +655,7 @@ impl TtParser {
|
||||
let mut mp = self.bb_mps.pop().unwrap();
|
||||
let loc = &matcher[mp.idx];
|
||||
if let &MatcherLoc::MetaVarDecl {
|
||||
span,
|
||||
kind: Some(kind),
|
||||
next_metavar,
|
||||
seq_depth,
|
||||
..
|
||||
span, kind, next_metavar, seq_depth, ..
|
||||
} = loc
|
||||
{
|
||||
// We use the span of the metavariable declaration to determine any
|
||||
@@ -715,7 +700,7 @@ impl TtParser {
|
||||
.bb_mps
|
||||
.iter()
|
||||
.map(|mp| match &matcher[mp.idx] {
|
||||
MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
|
||||
MatcherLoc::MetaVarDecl { bind, kind, .. } => {
|
||||
format!("{kind} ('{bind}')")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -745,19 +730,13 @@ impl TtParser {
|
||||
// `NamedParseResult`. Otherwise, it's an error.
|
||||
let mut ret_val = FxHashMap::default();
|
||||
for loc in matcher {
|
||||
if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
|
||||
if kind.is_some() {
|
||||
if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc {
|
||||
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
|
||||
Vacant(spot) => spot.insert(res.next().unwrap()),
|
||||
Occupied(..) => {
|
||||
return Error(span, format!("duplicated bind name: {bind}"));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
|
||||
// Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
|
||||
return Error(span, "missing fragment specifier".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Success(ret_val)
|
||||
|
||||
@@ -392,7 +392,7 @@ pub fn compile_declarative_macro(
|
||||
|
||||
let lhs_nm = Ident::new(sym::lhs, span);
|
||||
let rhs_nm = Ident::new(sym::rhs, span);
|
||||
let tt_spec = Some(NonterminalKind::TT);
|
||||
let tt_spec = NonterminalKind::TT;
|
||||
let macro_rules = macro_def.macro_rules;
|
||||
|
||||
// Parse the macro_rules! invocation
|
||||
@@ -407,9 +407,9 @@ pub fn compile_declarative_macro(
|
||||
DelimSpan::dummy(),
|
||||
mbe::SequenceRepetition {
|
||||
tts: vec![
|
||||
mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
|
||||
mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec },
|
||||
mbe::TokenTree::token(token::FatArrow, span),
|
||||
mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
|
||||
mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec },
|
||||
],
|
||||
separator: Some(Token::new(
|
||||
if macro_rules { token::Semi } else { token::Comma },
|
||||
@@ -448,6 +448,7 @@ pub fn compile_declarative_macro(
|
||||
match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
|
||||
Success(m) => m,
|
||||
Failure(()) => {
|
||||
debug!("failed to parse macro tt");
|
||||
// The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
|
||||
// with another one that gives us the information we need.
|
||||
// For this we need to reclone the macro body as the previous parser consumed it.
|
||||
@@ -616,7 +617,7 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
|
||||
let mut iter = seq.tts.iter().peekable();
|
||||
while let Some(tt) = iter.next() {
|
||||
match tt {
|
||||
mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
|
||||
mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. } => {}
|
||||
mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
|
||||
let mut now = t;
|
||||
while let Some(&mbe::TokenTree::Token(
|
||||
@@ -651,7 +652,7 @@ fn check_redundant_vis_repetition(
|
||||
) {
|
||||
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
|
||||
let is_vis = seq.tts.first().map_or(false, |tt| {
|
||||
matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
|
||||
matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
|
||||
});
|
||||
|
||||
if is_vis && is_zero_or_one {
|
||||
@@ -678,7 +679,7 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarDecl { .. }
|
||||
| TokenTree::MetaVarExpr(..) => (),
|
||||
TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?,
|
||||
TokenTree::Sequence(span, seq) => {
|
||||
@@ -777,7 +778,7 @@ impl<'tt> FirstSets<'tt> {
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarDecl { .. }
|
||||
| TokenTree::MetaVarExpr(..) => {
|
||||
first.replace_with(TtHandle::TtRef(tt));
|
||||
}
|
||||
@@ -845,7 +846,7 @@ impl<'tt> FirstSets<'tt> {
|
||||
match tt {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarDecl { .. }
|
||||
| TokenTree::MetaVarExpr(..) => {
|
||||
first.add_one(TtHandle::TtRef(tt));
|
||||
return first;
|
||||
@@ -1084,7 +1085,7 @@ fn check_matcher_core<'tt>(
|
||||
match token {
|
||||
TokenTree::Token(..)
|
||||
| TokenTree::MetaVar(..)
|
||||
| TokenTree::MetaVarDecl(..)
|
||||
| TokenTree::MetaVarDecl { .. }
|
||||
| TokenTree::MetaVarExpr(..) => {
|
||||
if token_can_be_followed_by_any(token) {
|
||||
// don't need to track tokens that work with any,
|
||||
@@ -1152,7 +1153,7 @@ fn check_matcher_core<'tt>(
|
||||
// Now `last` holds the complete set of NT tokens that could
|
||||
// end the sequence before SUFFIX. Check that every one works with `suffix`.
|
||||
for tt in &last.tokens {
|
||||
if let &TokenTree::MetaVarDecl(span, name, Some(kind)) = tt.get() {
|
||||
if let &TokenTree::MetaVarDecl { span, name, kind } = tt.get() {
|
||||
for next_token in &suffix_first.tokens {
|
||||
let next_token = next_token.get();
|
||||
|
||||
@@ -1172,11 +1173,11 @@ fn check_matcher_core<'tt>(
|
||||
)
|
||||
{
|
||||
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||
));
|
||||
kind: NonterminalKind::Pat(PatParam { inferred: false }),
|
||||
});
|
||||
sess.psess.buffer_lint(
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||
span,
|
||||
@@ -1212,11 +1213,11 @@ fn check_matcher_core<'tt>(
|
||||
&& sess.psess.edition.at_least_rust_2021()
|
||||
&& next_token.is_token(&token::Or)
|
||||
{
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||
));
|
||||
kind: NonterminalKind::Pat(PatParam { inferred: false }),
|
||||
});
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try a `pat_param` fragment specifier instead",
|
||||
@@ -1254,7 +1255,7 @@ fn check_matcher_core<'tt>(
|
||||
}
|
||||
|
||||
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
|
||||
if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
|
||||
if let mbe::TokenTree::MetaVarDecl { kind, .. } = *tok {
|
||||
frag_can_be_followed_by_any(kind)
|
||||
} else {
|
||||
// (Non NT's can always be followed by anything in matchers.)
|
||||
@@ -1367,7 +1368,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
||||
}
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
},
|
||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
|
||||
TokenTree::MetaVarDecl { kind: NonterminalKind::Block, .. } => IsInFollow::Yes,
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
@@ -1400,11 +1401,10 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
||||
}
|
||||
}
|
||||
},
|
||||
TokenTree::MetaVarDecl(
|
||||
_,
|
||||
_,
|
||||
Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
|
||||
) => IsInFollow::Yes,
|
||||
TokenTree::MetaVarDecl {
|
||||
kind: NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
|
||||
..
|
||||
} => IsInFollow::Yes,
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
@@ -1416,8 +1416,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
|
||||
match tt {
|
||||
mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(),
|
||||
mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
|
||||
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
|
||||
mbe::TokenTree::MetaVarDecl { name, kind, .. } => format!("${name}:{kind}"),
|
||||
_ => panic!(
|
||||
"{}",
|
||||
"unexpected mbe::TokenTree::{Sequence or Delimited} \
|
||||
|
||||
@@ -54,22 +54,53 @@ pub(super) fn parse(
|
||||
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
|
||||
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
|
||||
let tree = parse_tree(tree, &mut iter, parsing_patterns, sess, node_id, features, edition);
|
||||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
||||
|
||||
if !parsing_patterns {
|
||||
// No matchers allowed, nothing to process here
|
||||
result.push(tree);
|
||||
continue;
|
||||
}
|
||||
|
||||
let TokenTree::MetaVar(start_sp, ident) = tree else {
|
||||
// Not a metavariable, just return the tree
|
||||
result.push(tree);
|
||||
continue;
|
||||
};
|
||||
|
||||
// Push a metavariable with no fragment specifier at the given span
|
||||
let mut missing_fragment_specifier = |span| {
|
||||
sess.dcx().emit_err(errors::MissingFragmentSpecifier {
|
||||
span,
|
||||
add_span: span.shrink_to_hi(),
|
||||
valid: VALID_FRAGMENT_NAMES_MSG,
|
||||
});
|
||||
|
||||
// Fall back to a `TokenTree` since that will match anything if we continue expanding.
|
||||
result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT });
|
||||
};
|
||||
|
||||
// Not consuming the next token immediately, as it may not be a colon
|
||||
let span = match iter.peek() {
|
||||
Some(&tokenstream::TokenTree::Token(
|
||||
Token { kind: token::Colon, span: colon_span },
|
||||
_,
|
||||
)) => {
|
||||
// Consume the colon first
|
||||
if let Some(peek) = iter.peek()
|
||||
&& let tokenstream::TokenTree::Token(token, _spacing) = peek
|
||||
&& let Token { kind: token::Colon, span: colon_span } = token
|
||||
{
|
||||
// Next token is a colon; consume it
|
||||
iter.next();
|
||||
|
||||
// It's ok to consume the next tree no matter how,
|
||||
// since if it's not a token then it will be an invalid declaration.
|
||||
match iter.next() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||
Some((fragment, _)) => {
|
||||
let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else {
|
||||
// Invalid, return a nice source location as `var:`
|
||||
missing_fragment_specifier(colon_span.with_lo(start_sp.lo()));
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some((fragment, _)) = token.ident() else {
|
||||
// No identifier for the fragment specifier;
|
||||
missing_fragment_specifier(token.span);
|
||||
continue;
|
||||
};
|
||||
|
||||
let span = token.span.with_lo(start_sp.lo());
|
||||
let edition = || {
|
||||
// FIXME(#85708) - once we properly decode a foreign
|
||||
@@ -80,40 +111,21 @@ pub(super) fn parse(
|
||||
// `SyntaxContext::root()` from a foreign crate will
|
||||
// have the edition of that crate (which we manually
|
||||
// retrieve via the `edition` parameter).
|
||||
if !span.from_expansion() {
|
||||
edition
|
||||
} else {
|
||||
span.edition()
|
||||
}
|
||||
if !span.from_expansion() { edition } else { span.edition() }
|
||||
};
|
||||
let kind = NonterminalKind::from_symbol(fragment.name, edition)
|
||||
.unwrap_or_else(|| {
|
||||
let kind = NonterminalKind::from_symbol(fragment.name, edition).unwrap_or_else(|| {
|
||||
sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
|
||||
span,
|
||||
fragment,
|
||||
help: VALID_FRAGMENT_NAMES_MSG.into(),
|
||||
help: VALID_FRAGMENT_NAMES_MSG,
|
||||
});
|
||||
NonterminalKind::Ident
|
||||
NonterminalKind::TT
|
||||
});
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
|
||||
continue;
|
||||
}
|
||||
_ => token.span,
|
||||
},
|
||||
// Invalid, return a nice source location
|
||||
_ => colon_span.with_lo(start_sp.lo()),
|
||||
}
|
||||
}
|
||||
result.push(TokenTree::MetaVarDecl { span, name: ident, kind });
|
||||
} else {
|
||||
// Whether it's none or some other tree, it doesn't belong to
|
||||
// the current meta variable, returning the original span.
|
||||
_ => start_sp,
|
||||
};
|
||||
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
||||
}
|
||||
|
||||
// Not a metavar or no matchers allowed, so just return the tree
|
||||
_ => result.push(tree),
|
||||
missing_fragment_specifier(start_sp);
|
||||
}
|
||||
}
|
||||
result
|
||||
|
||||
@@ -283,7 +283,7 @@ pub(super) fn transcribe<'a>(
|
||||
}
|
||||
|
||||
// There should be no meta-var declarations in the invocation of a macro.
|
||||
mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"),
|
||||
mbe::TokenTree::MetaVarDecl { .. } => panic!("unexpected `TokenTree::MetaVarDecl`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -776,7 +776,7 @@ fn lockstep_iter_size(
|
||||
size.with(lockstep_iter_size(tt, interpolations, repeats))
|
||||
})
|
||||
}
|
||||
TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => {
|
||||
TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl { name, .. } => {
|
||||
let name = MacroRulesNormalizedIdent::new(*name);
|
||||
match lookup_cur_matched(name, interpolations, repeats) {
|
||||
Some(matched) => match matched {
|
||||
|
||||
@@ -2,11 +2,10 @@ macro_rules! test {
|
||||
($a, $b) => {
|
||||
//~^ ERROR missing fragment
|
||||
//~| ERROR missing fragment
|
||||
//~| ERROR missing fragment
|
||||
()
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test!()
|
||||
test!() //~ ERROR unexpected end of macro invocation
|
||||
}
|
||||
|
||||
@@ -24,7 +24,16 @@ help: try adding a specifier here
|
||||
LL | ($a, $b:spec) => {
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/macro-match-nonterminal.rs:10:5
|
||||
|
|
||||
LL | macro_rules! test {
|
||||
| ----------------- when calling this macro
|
||||
...
|
||||
LL | test!()
|
||||
| ^^^^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$a:tt`
|
||||
--> $DIR/macro-match-nonterminal.rs:2:6
|
||||
|
|
||||
LL | ($a, $b) => {
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
macro_rules! m {
|
||||
($name) => {}; //~ ERROR missing fragment
|
||||
//~| ERROR missing fragment
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m!();
|
||||
m!();
|
||||
m!();
|
||||
m!();
|
||||
m!(); //~ ERROR unexpected end
|
||||
m!(); //~ ERROR unexpected end
|
||||
m!(); //~ ERROR unexpected end
|
||||
m!(); //~ ERROR unexpected end
|
||||
}
|
||||
|
||||
@@ -11,11 +11,65 @@ help: try adding a specifier here
|
||||
LL | ($name:spec) => {};
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:8:5
|
||||
|
|
||||
LL | macro_rules! m {
|
||||
| -------------- when calling this macro
|
||||
...
|
||||
LL | m!();
|
||||
| ^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$name:tt`
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
||||
|
|
||||
LL | ($name) => {};
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:9:5
|
||||
|
|
||||
LL | macro_rules! m {
|
||||
| -------------- when calling this macro
|
||||
...
|
||||
LL | m!();
|
||||
| ^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$name:tt`
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
||||
|
|
||||
LL | ($name) => {};
|
||||
| ^^^^^
|
||||
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:10:5
|
||||
|
|
||||
LL | macro_rules! m {
|
||||
| -------------- when calling this macro
|
||||
...
|
||||
LL | m!();
|
||||
| ^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$name:tt`
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
||||
|
|
||||
LL | ($name) => {};
|
||||
| ^^^^^
|
||||
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:11:5
|
||||
|
|
||||
LL | macro_rules! m {
|
||||
| -------------- when calling this macro
|
||||
...
|
||||
LL | m!();
|
||||
| ^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$name:tt`
|
||||
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
||||
|
|
||||
LL | ($name) => {};
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
macro_rules! used_arm {
|
||||
( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
|
||||
//~| ERROR missing fragment
|
||||
}
|
||||
|
||||
macro_rules! used_macro_unused_arm {
|
||||
|
||||
@@ -12,7 +12,7 @@ LL | ( $( any_token $field_rust_type:spec )* ) => {};
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
--> $DIR/macro-missing-fragment.rs:10:7
|
||||
--> $DIR/macro-missing-fragment.rs:9:7
|
||||
|
|
||||
LL | ( $name ) => {};
|
||||
| ^^^^^
|
||||
@@ -25,7 +25,7 @@ LL | ( $name:spec ) => {};
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
--> $DIR/macro-missing-fragment.rs:14:7
|
||||
--> $DIR/macro-missing-fragment.rs:13:7
|
||||
|
|
||||
LL | ( $name ) => {};
|
||||
| ^^^^^
|
||||
@@ -37,11 +37,5 @@ help: try adding a specifier here
|
||||
LL | ( $name:spec ) => {};
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
--> $DIR/macro-missing-fragment.rs:4:20
|
||||
|
|
||||
LL | ( $( any_token $field_rust_type )* ) => {};
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
macro_rules! foo {
|
||||
{ $+ } => { //~ ERROR expected identifier, found `+`
|
||||
//~^ ERROR missing fragment specifier
|
||||
//~| ERROR missing fragment specifier
|
||||
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
|
||||
}
|
||||
}
|
||||
|
||||
foo!();
|
||||
foo!(); //~ ERROR unexpected end
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -4,12 +4,6 @@ error: expected identifier, found `+`
|
||||
LL | { $+ } => {
|
||||
| ^
|
||||
|
||||
error: expected one of: `*`, `+`, or `?`
|
||||
--> $DIR/issue-33569.rs:5:13
|
||||
|
|
||||
LL | $(x)(y)
|
||||
| ^^^
|
||||
|
||||
error: missing fragment specifier
|
||||
--> $DIR/issue-33569.rs:2:8
|
||||
|
|
||||
@@ -23,7 +17,22 @@ help: try adding a specifier here
|
||||
LL | { $+:spec } => {
|
||||
| +++++
|
||||
|
||||
error: missing fragment specifier
|
||||
error: expected one of: `*`, `+`, or `?`
|
||||
--> $DIR/issue-33569.rs:4:13
|
||||
|
|
||||
LL | $(x)(y)
|
||||
| ^^^
|
||||
|
||||
error: unexpected end of macro invocation
|
||||
--> $DIR/issue-33569.rs:8:1
|
||||
|
|
||||
LL | macro_rules! foo {
|
||||
| ---------------- when calling this macro
|
||||
...
|
||||
LL | foo!();
|
||||
| ^^^^^^ missing tokens in macro arguments
|
||||
|
|
||||
note: while trying to match meta-variable `$<!dummy!>:tt`
|
||||
--> $DIR/issue-33569.rs:2:8
|
||||
|
|
||||
LL | { $+ } => {
|
||||
|
||||
Reference in New Issue
Block a user