// This type is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(NamedMatchVec, 72);
+rustc_data_structures::static_assert_size!(NamedMatchVec, 168);
/// Represents a single "position" (aka "matcher position", aka "item"), as
/// described in the module documentation.
})
}
-/// `NamedMatch` is a pattern-match result for a single `token::MATCH_NONTERMINAL`:
-/// so it is associated with a single ident in a parse, and all
-/// `MatchedNonterminal`s in the `NamedMatch` have the same non-terminal type
-/// (expr, item, etc). Each leaf in a single `NamedMatch` corresponds to a
-/// single `token::MATCH_NONTERMINAL` in the `TokenTree` that produced it.
+/// `NamedMatch` is a pattern-match result for a single metavar. All
+/// `MatchedNtNonTt`s in the `NamedMatch` have the same non-terminal type
+/// (expr, item, etc).
///
/// The in-memory structure of a particular `NamedMatch` represents the match
/// that occurred when a particular subset of a matcher was applied to a
/// particular token tree.
///
/// The width of each `MatchedSeq` in the `NamedMatch`, and the identity of
-/// the `MatchedNonterminal`s, will depend on the token tree it was applied
-/// to: each `MatchedSeq` corresponds to a single `TTSeq` in the originating
+/// the `MatchedNtNonTts`s, will depend on the token tree it was applied
+/// to: each `MatchedSeq` corresponds to a single repetition in the originating
/// token tree. The depth of the `NamedMatch` structure will therefore depend
-/// only on the nesting depth of `ast::TTSeq`s in the originating
-/// token tree it was derived from.
+/// only on the nesting depth of repetitions in the originating token tree it
+/// was derived from.
///
/// In layman's terms: `NamedMatch` will form a tree representing nested matches of a particular
/// meta variable. For example, if we are matching the following macro against the following
/// ```rust
/// MatchedSeq([
/// MatchedSeq([
-/// MatchedNonterminal(a),
-/// MatchedNonterminal(b),
-/// MatchedNonterminal(c),
-/// MatchedNonterminal(d),
+/// MatchedNtNonTt(a),
+/// MatchedNtNonTt(b),
+/// MatchedNtNonTt(c),
+/// MatchedNtNonTt(d),
/// ]),
/// MatchedSeq([
-/// MatchedNonterminal(a),
-/// MatchedNonterminal(b),
-/// MatchedNonterminal(c),
-/// MatchedNonterminal(d),
-/// MatchedNonterminal(e),
+/// MatchedNtNonTt(a),
+/// MatchedNtNonTt(b),
+/// MatchedNtNonTt(c),
+/// MatchedNtNonTt(d),
+/// MatchedNtNonTt(e),
/// ])
/// ])
/// ```
#[derive(Debug, Clone)]
crate enum NamedMatch {
MatchedSeq(Lrc<NamedMatchVec>),
- MatchedNonterminal(Lrc<Nonterminal>),
+
+ // This variant should never hold an `NtTT`. `MatchedNtTt` should be used
+ // for that case.
+ MatchedNtNonTt(Lrc<Nonterminal>),
+
+ // `NtTT` is handled without any cloning when transcribing, unlike other
+ // nonterminals. Therefore, an `Lrc` isn't helpful and causes unnecessary
+ // allocations. Hence this separate variant.
+ MatchedNtTt(rustc_ast::tokenstream::TokenTree),
}
/// Takes a slice of token trees `ms` representing a matcher which successfully matched input
}
Ok(nt) => nt,
};
- item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
+ let m = match nt {
+ Nonterminal::NtTT(tt) => MatchedNtTt(tt),
+ _ => MatchedNtNonTt(Lrc::new(nt)),
+ };
+ item.push_match(match_cur, m);
item.idx += 1;
item.match_cur += 1;
} else {
use crate::mbe;
use crate::mbe::macro_check;
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
-use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq};
+use crate::mbe::macro_parser::{MatchedNtTt, MatchedSeq};
use crate::mbe::transcribe::transcribe;
use rustc_ast as ast;
-use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
+use rustc_ast::token::{self, NonterminalKind, Token, TokenKind::*};
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
MatchedSeq(ref s) => s
.iter()
.map(|m| {
- if let MatchedNonterminal(ref nt) = *m {
- if let NtTT(ref tt) = **nt {
- let mut tts = vec![];
- mbe::quoted::parse(
- tt.clone().into(),
- true,
- &sess.parse_sess,
- def.id,
- features,
- edition,
- &mut tts,
- );
- let tt = tts.pop().unwrap();
- valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
- return tt;
- }
+ if let MatchedNtTt(ref tt) = *m {
+ let mut tts = vec![];
+ mbe::quoted::parse(
+ tt.clone().into(),
+ true,
+ &sess.parse_sess,
+ def.id,
+ features,
+ edition,
+ &mut tts,
+ );
+ let tt = tts.pop().unwrap();
+ valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
+ return tt;
}
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
MatchedSeq(ref s) => s
.iter()
.map(|m| {
- if let MatchedNonterminal(ref nt) = *m {
- if let NtTT(ref tt) = **nt {
- let mut tts = vec![];
- mbe::quoted::parse(
- tt.clone().into(),
- false,
- &sess.parse_sess,
- def.id,
- features,
- edition,
- &mut tts,
- );
- return tts.pop().unwrap();
- }
+ if let MatchedNtTt(ref tt) = *m {
+ let mut tts = vec![];
+ mbe::quoted::parse(
+ tt.clone().into(),
+ false,
+ &sess.parse_sess,
+ def.id,
+ features,
+ edition,
+ &mut tts,
+ );
+ return tts.pop().unwrap();
}
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
use crate::base::ExtCtxt;
-use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
+use crate::mbe::macro_parser::{MatchedNtNonTt, MatchedNtTt, MatchedSeq, NamedMatch};
use crate::mbe::{self, MetaVarExpr};
use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, NtTT, Token, TokenKind};
+use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
// the meta-var.
let ident = MacroRulesNormalizedIdent::new(orignal_ident);
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
- if let MatchedNonterminal(nt) = cur_matched {
- let token = if let NtTT(tt) = &**nt {
+ match cur_matched {
+ MatchedNtTt(ref tt) => {
// `tt`s are emitted into the output stream directly as "raw tokens",
// without wrapping them into groups.
- tt.clone()
- } else {
+ let token = tt.clone();
+ result.push(token.into());
+ }
+ MatchedNtNonTt(ref nt) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::None` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser.
+ debug_assert!(!matches!(**nt, Nonterminal::NtTT(_)));
marker.visit_span(&mut sp);
- TokenTree::token(token::Interpolated(nt.clone()), sp)
- };
- result.push(token.into());
- } else {
- // We were unable to descend far enough. This is an error.
- return Err(cx.struct_span_err(
- sp, /* blame the macro writer */
- &format!("variable '{}' is still repeating at this depth", ident),
- ));
+ let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
+ result.push(token.into());
+ }
+ MatchedSeq(..) => {
+ // We were unable to descend far enough. This is an error.
+ return Err(cx.struct_span_err(
+ sp, /* blame the macro writer */
+ &format!("variable '{}' is still repeating at this depth", ident),
+ ));
+ }
}
} else {
// If we aren't able to match the meta-var, we push it back into the result but
let mut matched = matched;
for &(idx, _) in repeats {
match matched {
- MatchedNonterminal(_) => break,
+ MatchedNtTt(_) | MatchedNtNonTt(_) => break,
MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
}
}
let name = MacroRulesNormalizedIdent::new(name);
match lookup_cur_matched(name, interpolations, repeats) {
Some(matched) => match matched {
- MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
+ MatchedNtTt(_) | MatchedNtNonTt(_) => LockstepIterSize::Unconstrained,
MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
},
_ => LockstepIterSize::Unconstrained,
sp: &DelimSpan,
) -> PResult<'a, usize> {
match matched {
- MatchedNonterminal(_) => {
+ MatchedNtTt(_) | MatchedNtNonTt(_) => {
if declared_lhs_depth == 0 {
return Err(cx.struct_span_err(
sp.entire(),