Skip to content

Commit 91218e6

Browse files
committed
macros: Clean up code with non-optional NonterminalKind
Since [1], 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. [1]: #128425
1 parent d74bf2b commit 91218e6

16 files changed

+158
-111
lines changed

compiler/rustc_ast/src/token.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,7 @@ pub enum NtExprKind {
10851085
Expr2021 { inferred: bool },
10861086
}
10871087

1088+
/// A macro nonterminal, known in documentation as a fragment specifier.
10881089
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
10891090
pub enum NonterminalKind {
10901091
Item,

compiler/rustc_expand/src/mbe.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,12 @@ enum TokenTree {
7878
/// only covers the ident, e.g. `var`.)
7979
MetaVar(Span, Ident),
8080
/// e.g., `$var:expr`. Only appears on the LHS.
81-
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
81+
MetaVarDecl {
82+
span: Span,
83+
/// Name to bind.
84+
name: Ident,
85+
kind: NonterminalKind,
86+
},
8287
/// A meta-variable expression inside `${...}`.
8388
MetaVarExpr(DelimSpan, MetaVarExpr),
8489
}
@@ -102,7 +107,7 @@ impl TokenTree {
102107
match *self {
103108
TokenTree::Token(Token { span, .. })
104109
| TokenTree::MetaVar(span, _)
105-
| TokenTree::MetaVarDecl(span, _, _) => span,
110+
| TokenTree::MetaVarDecl { span, .. } => span,
106111
TokenTree::Delimited(span, ..)
107112
| TokenTree::MetaVarExpr(span, _)
108113
| TokenTree::Sequence(span, _) => span.entire(),

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub(super) fn failed_to_match_macro(
2424
arg: TokenStream,
2525
lhses: &[Vec<MatcherLoc>],
2626
) -> (Span, ErrorGuaranteed) {
27+
debug!("failed to match macro");
2728
// An error occurred, try the expansion again, tracking the expansion closely for better
2829
// diagnostics.
2930
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);

compiler/rustc_expand/src/mbe/macro_check.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ use rustc_session::parse::ParseSess;
117117
use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
118118
use smallvec::SmallVec;
119119

120-
use super::quoted::VALID_FRAGMENT_NAMES_MSG;
120+
// use super::quoted::VALID_FRAGMENT_NAMES_MSG;
121121
use crate::errors;
122122
use crate::mbe::{KleeneToken, TokenTree};
123123

@@ -263,14 +263,7 @@ fn check_binders(
263263
}
264264
}
265265
// Similarly, this can only happen when checking a toplevel macro.
266-
TokenTree::MetaVarDecl(span, name, kind) => {
267-
if kind.is_none() && node_id != DUMMY_NODE_ID {
268-
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
269-
span,
270-
add_span: span.shrink_to_hi(),
271-
valid: VALID_FRAGMENT_NAMES_MSG,
272-
});
273-
}
266+
TokenTree::MetaVarDecl { span, name, .. } => {
274267
if !macros.is_empty() {
275268
psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
276269
}
@@ -339,7 +332,7 @@ fn check_occurrences(
339332
) {
340333
match *rhs {
341334
TokenTree::Token(..) => {}
342-
TokenTree::MetaVarDecl(span, _name, _kind) => {
335+
TokenTree::MetaVarDecl { span, .. } => {
343336
psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs")
344337
}
345338
TokenTree::MetaVar(span, name) => {

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub(crate) enum MatcherLoc {
122122
MetaVarDecl {
123123
span: Span,
124124
bind: Ident,
125-
kind: Option<NonterminalKind>,
125+
kind: NonterminalKind,
126126
next_metavar: usize,
127127
seq_depth: usize,
128128
},
@@ -151,12 +151,7 @@ impl Display for MatcherLoc {
151151
write!(f, "{}", token_descr(token))
152152
}
153153
MatcherLoc::MetaVarDecl { bind, kind, .. } => {
154-
write!(f, "meta-variable `${bind}")?;
155-
if let Some(kind) = kind {
156-
write!(f, ":{kind}")?;
157-
}
158-
write!(f, "`")?;
159-
Ok(())
154+
write!(f, "meta-variable `${bind}:{kind}`")
160155
}
161156
MatcherLoc::Eof => f.write_str("end of macro"),
162157

@@ -220,7 +215,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
220215
seq_depth,
221216
};
222217
}
223-
&TokenTree::MetaVarDecl(span, bind, kind) => {
218+
&TokenTree::MetaVarDecl { span, name: bind, kind } => {
224219
locs.push(MatcherLoc::MetaVarDecl {
225220
span,
226221
bind,
@@ -330,7 +325,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
330325
matcher
331326
.iter()
332327
.map(|tt| match tt {
333-
TokenTree::MetaVarDecl(..) => 1,
328+
TokenTree::MetaVarDecl { .. } => 1,
334329
TokenTree::Sequence(_, seq) => seq.num_captures,
335330
TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts),
336331
TokenTree::Token(..) => 0,
@@ -551,18 +546,12 @@ impl TtParser {
551546
mp.idx = idx_first;
552547
self.cur_mps.push(mp);
553548
}
554-
&MatcherLoc::MetaVarDecl { span, kind, .. } => {
549+
&MatcherLoc::MetaVarDecl { kind, .. } => {
555550
// Built-in nonterminals never start with these tokens, so we can eliminate
556551
// them from consideration. We use the span of the metavariable declaration
557552
// to determine any edition-specific matching behavior for non-terminals.
558-
if let Some(kind) = kind {
559-
if Parser::nonterminal_may_begin_with(kind, token) {
560-
self.bb_mps.push(mp);
561-
}
562-
} else {
563-
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
564-
// Both this check and the one in `nameize` are necessary, surprisingly.
565-
return Some(Error(span, "missing fragment specifier".to_string()));
553+
if Parser::nonterminal_may_begin_with(kind, token) {
554+
self.bb_mps.push(mp);
566555
}
567556
}
568557
MatcherLoc::Eof => {
@@ -666,11 +655,7 @@ impl TtParser {
666655
let mut mp = self.bb_mps.pop().unwrap();
667656
let loc = &matcher[mp.idx];
668657
if let &MatcherLoc::MetaVarDecl {
669-
span,
670-
kind: Some(kind),
671-
next_metavar,
672-
seq_depth,
673-
..
658+
span, kind, next_metavar, seq_depth, ..
674659
} = loc
675660
{
676661
// We use the span of the metavariable declaration to determine any
@@ -715,7 +700,7 @@ impl TtParser {
715700
.bb_mps
716701
.iter()
717702
.map(|mp| match &matcher[mp.idx] {
718-
MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
703+
MatcherLoc::MetaVarDecl { bind, kind, .. } => {
719704
format!("{kind} ('{bind}')")
720705
}
721706
_ => unreachable!(),
@@ -745,19 +730,13 @@ impl TtParser {
745730
// `NamedParseResult`. Otherwise, it's an error.
746731
let mut ret_val = FxHashMap::default();
747732
for loc in matcher {
748-
if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
749-
if kind.is_some() {
750-
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
751-
Vacant(spot) => spot.insert(res.next().unwrap()),
752-
Occupied(..) => {
753-
return Error(span, format!("duplicated bind name: {bind}"));
754-
}
755-
};
756-
} else {
757-
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
758-
// Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
759-
return Error(span, "missing fragment specifier".to_string());
760-
}
733+
if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc {
734+
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
735+
Vacant(spot) => spot.insert(res.next().unwrap()),
736+
Occupied(..) => {
737+
return Error(span, format!("duplicated bind name: {bind}"));
738+
}
739+
};
761740
}
762741
}
763742
Success(ret_val)

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ pub fn compile_declarative_macro(
392392

393393
let lhs_nm = Ident::new(sym::lhs, span);
394394
let rhs_nm = Ident::new(sym::rhs, span);
395-
let tt_spec = Some(NonterminalKind::TT);
395+
let tt_spec = NonterminalKind::TT;
396396
let macro_rules = macro_def.macro_rules;
397397

398398
// Parse the macro_rules! invocation
@@ -407,9 +407,9 @@ pub fn compile_declarative_macro(
407407
DelimSpan::dummy(),
408408
mbe::SequenceRepetition {
409409
tts: vec![
410-
mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
410+
mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec },
411411
mbe::TokenTree::token(token::FatArrow, span),
412-
mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
412+
mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec },
413413
],
414414
separator: Some(Token::new(
415415
if macro_rules { token::Semi } else { token::Comma },
@@ -448,6 +448,7 @@ pub fn compile_declarative_macro(
448448
match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
449449
Success(m) => m,
450450
Failure(()) => {
451+
debug!("failed to parse macro tt");
451452
// The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
452453
// with another one that gives us the information we need.
453454
// 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 {
616617
let mut iter = seq.tts.iter().peekable();
617618
while let Some(tt) = iter.next() {
618619
match tt {
619-
mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
620+
mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. } => {}
620621
mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
621622
let mut now = t;
622623
while let Some(&mbe::TokenTree::Token(
@@ -651,7 +652,7 @@ fn check_redundant_vis_repetition(
651652
) {
652653
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
653654
let is_vis = seq.tts.first().map_or(false, |tt| {
654-
matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
655+
matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
655656
});
656657

657658
if is_vis && is_zero_or_one {
@@ -678,7 +679,7 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
678679
match tt {
679680
TokenTree::Token(..)
680681
| TokenTree::MetaVar(..)
681-
| TokenTree::MetaVarDecl(..)
682+
| TokenTree::MetaVarDecl { .. }
682683
| TokenTree::MetaVarExpr(..) => (),
683684
TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?,
684685
TokenTree::Sequence(span, seq) => {
@@ -777,7 +778,7 @@ impl<'tt> FirstSets<'tt> {
777778
match tt {
778779
TokenTree::Token(..)
779780
| TokenTree::MetaVar(..)
780-
| TokenTree::MetaVarDecl(..)
781+
| TokenTree::MetaVarDecl { .. }
781782
| TokenTree::MetaVarExpr(..) => {
782783
first.replace_with(TtHandle::TtRef(tt));
783784
}
@@ -845,7 +846,7 @@ impl<'tt> FirstSets<'tt> {
845846
match tt {
846847
TokenTree::Token(..)
847848
| TokenTree::MetaVar(..)
848-
| TokenTree::MetaVarDecl(..)
849+
| TokenTree::MetaVarDecl { .. }
849850
| TokenTree::MetaVarExpr(..) => {
850851
first.add_one(TtHandle::TtRef(tt));
851852
return first;
@@ -1084,7 +1085,7 @@ fn check_matcher_core<'tt>(
10841085
match token {
10851086
TokenTree::Token(..)
10861087
| TokenTree::MetaVar(..)
1087-
| TokenTree::MetaVarDecl(..)
1088+
| TokenTree::MetaVarDecl { .. }
10881089
| TokenTree::MetaVarExpr(..) => {
10891090
if token_can_be_followed_by_any(token) {
10901091
// don't need to track tokens that work with any,
@@ -1152,7 +1153,7 @@ fn check_matcher_core<'tt>(
11521153
// Now `last` holds the complete set of NT tokens that could
11531154
// end the sequence before SUFFIX. Check that every one works with `suffix`.
11541155
for tt in &last.tokens {
1155-
if let &TokenTree::MetaVarDecl(span, name, Some(kind)) = tt.get() {
1156+
if let &TokenTree::MetaVarDecl { span, name, kind } = tt.get() {
11561157
for next_token in &suffix_first.tokens {
11571158
let next_token = next_token.get();
11581159

@@ -1172,11 +1173,11 @@ fn check_matcher_core<'tt>(
11721173
)
11731174
{
11741175
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
1175-
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
1176+
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
11761177
span,
11771178
name,
1178-
Some(NonterminalKind::Pat(PatParam { inferred: false })),
1179-
));
1179+
kind: NonterminalKind::Pat(PatParam { inferred: false }),
1180+
});
11801181
sess.psess.buffer_lint(
11811182
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
11821183
span,
@@ -1212,11 +1213,11 @@ fn check_matcher_core<'tt>(
12121213
&& sess.psess.edition.at_least_rust_2021()
12131214
&& next_token.is_token(&token::Or)
12141215
{
1215-
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
1216+
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
12161217
span,
12171218
name,
1218-
Some(NonterminalKind::Pat(PatParam { inferred: false })),
1219-
));
1219+
kind: NonterminalKind::Pat(PatParam { inferred: false }),
1220+
});
12201221
err.span_suggestion(
12211222
span,
12221223
"try a `pat_param` fragment specifier instead",
@@ -1254,7 +1255,7 @@ fn check_matcher_core<'tt>(
12541255
}
12551256

12561257
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
1257-
if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
1258+
if let mbe::TokenTree::MetaVarDecl { kind, .. } = *tok {
12581259
frag_can_be_followed_by_any(kind)
12591260
} else {
12601261
// (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 {
13671368
}
13681369
_ => IsInFollow::No(TOKENS),
13691370
},
1370-
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
1371+
TokenTree::MetaVarDecl { kind: NonterminalKind::Block, .. } => IsInFollow::Yes,
13711372
_ => IsInFollow::No(TOKENS),
13721373
}
13731374
}
@@ -1400,11 +1401,10 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
14001401
}
14011402
}
14021403
},
1403-
TokenTree::MetaVarDecl(
1404-
_,
1405-
_,
1406-
Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
1407-
) => IsInFollow::Yes,
1404+
TokenTree::MetaVarDecl {
1405+
kind: NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
1406+
..
1407+
} => IsInFollow::Yes,
14081408
_ => IsInFollow::No(TOKENS),
14091409
}
14101410
}
@@ -1416,8 +1416,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
14161416
match tt {
14171417
mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(),
14181418
mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
1419-
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
1420-
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
1419+
mbe::TokenTree::MetaVarDecl { name, kind, .. } => format!("${name}:{kind}"),
14211420
_ => panic!(
14221421
"{}",
14231422
"unexpected mbe::TokenTree::{Sequence or Delimited} \

compiler/rustc_expand/src/mbe/quoted.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,15 @@ pub(super) fn parse(
6868
};
6969

7070
// Push a metavariable with no fragment specifier at the given span
71-
let mut push_empty_metavar = |span| {
72-
result.push(TokenTree::MetaVarDecl(span, ident, None));
71+
let mut missing_fragment_specifier = |span| {
72+
sess.dcx().emit_err(errors::MissingFragmentSpecifier {
73+
span,
74+
add_span: span.shrink_to_hi(),
75+
valid: VALID_FRAGMENT_NAMES_MSG,
76+
});
77+
78+
// Fall back to a
79+
result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT });
7380
};
7481

7582
// Not consuming the next token immediately, as it may not be a colon
@@ -84,13 +91,13 @@ pub(super) fn parse(
8491
// since if it's not a token then it will be an invalid declaration.
8592
let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else {
8693
// Invalid, return a nice source location as `var:`
87-
push_empty_metavar(colon_span.with_lo(start_sp.lo()));
94+
missing_fragment_specifier(colon_span.with_lo(start_sp.lo()));
8895
continue;
8996
};
9097

9198
let Some((fragment, _)) = token.ident() else {
9299
// No identifier for the fragment specifier;
93-
push_empty_metavar(token.span);
100+
missing_fragment_specifier(token.span);
94101
continue;
95102
};
96103

@@ -114,11 +121,11 @@ pub(super) fn parse(
114121
});
115122
NonterminalKind::Ident
116123
});
117-
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
124+
result.push(TokenTree::MetaVarDecl { span, name: ident, kind });
118125
} else {
119126
// Whether it's none or some other tree, it doesn't belong to
120127
// the current meta variable, returning the original span.
121-
push_empty_metavar(start_sp);
128+
missing_fragment_specifier(start_sp);
122129
}
123130
}
124131
result

0 commit comments

Comments
 (0)