Skip to content

Commit b3e8379

Browse files
committed
mbe: Support vis fragment field for fn; add infra for recursive token collection
Add support for getting a `.vis` field from a `fn` type. This requires adding support for collecting tokens when parsing the visibility of a function. Add a new `ForceCollect::Recursive`, and plumb that through the item parser enough to support visibility. Only use that when a macro uses macro metavariable expressions, as we don't need the tokens otherwise. `ForceCollect::Recursive` will need further handling later, to capture the tokens of any other fields needed, but that can be added alongside any fields it supports.
1 parent 604490a commit b3e8379

File tree

10 files changed

+207
-59
lines changed

10 files changed

+207
-59
lines changed

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_ast::token::{self, Token};
44
use rustc_ast::tokenstream::TokenStream;
55
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
66
use rustc_macros::Subdiagnostic;
7-
use rustc_parse::parser::{Parser, Recovery, token_descr};
7+
use rustc_parse::parser::{ForceCollect, Parser, Recovery, token_descr};
88
use rustc_session::parse::ParseSess;
99
use rustc_span::source_map::SourceMap;
1010
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Ident, Span};
@@ -44,12 +44,14 @@ pub(super) fn failed_to_match_macro(
4444
// diagnostics.
4545
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
4646

47+
// We don't need to collect tokens to process failures, since we'll never expand them.
48+
let no = ForceCollect::No;
4749
let try_success_result = match args {
48-
FailedMacro::Func => try_match_macro(psess, name, body, rules, &mut tracker),
50+
FailedMacro::Func => try_match_macro(psess, name, body, rules, no, &mut tracker),
4951
FailedMacro::Attr(attr_args) => {
50-
try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker)
52+
try_match_macro_attr(psess, name, attr_args, body, rules, no, &mut tracker)
5153
}
52-
FailedMacro::Derive => try_match_macro_derive(psess, name, body, rules, &mut tracker),
54+
FailedMacro::Derive => try_match_macro_derive(psess, name, body, rules, no, &mut tracker),
5355
};
5456

5557
if try_success_result.is_ok() {
@@ -108,9 +110,12 @@ pub(super) fn failed_to_match_macro(
108110
let parser = parser_from_cx(psess, body.clone(), Recovery::Allowed);
109111
let mut tt_parser = TtParser::new(name);
110112

111-
if let Success(_) =
112-
tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
113-
{
113+
if let Success(_) = tt_parser.parse_tt(
114+
&mut Cow::Borrowed(&parser),
115+
lhs,
116+
ForceCollect::No,
117+
&mut NoopTracker,
118+
) {
114119
if comma_span.is_dummy() {
115120
err.note("you might be missing a comma");
116121
} else {

compiler/rustc_expand/src/mbe/macro_check.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
109109
use rustc_ast::{DUMMY_NODE_ID, NodeId};
110110
use rustc_data_structures::fx::FxHashMap;
111111
use rustc_errors::DecorateDiagCompat;
112+
use rustc_parse::parser::ForceCollect;
112113
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
113114
use rustc_session::parse::ParseSess;
114115
use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
@@ -193,20 +194,23 @@ struct MacroState<'a> {
193194
/// - `psess` is used to emit diagnostics and lints
194195
/// - `node_id` is used to emit lints
195196
/// - `args`, `lhs`, and `rhs` represent the rule
197+
/// - `collect` is set to the token collection mode needed for the macro (recursive if any metavar exprs)
196198
pub(super) fn check_meta_variables(
197199
psess: &ParseSess,
198200
node_id: NodeId,
199201
args: Option<&TokenTree>,
200202
lhs: &TokenTree,
201203
rhs: &TokenTree,
204+
collect: &mut ForceCollect,
202205
) -> Result<(), ErrorGuaranteed> {
203206
let mut guar = None;
204207
let mut binders = Binders::default();
208+
let ops = &Stack::Empty;
205209
if let Some(args) = args {
206-
check_binders(psess, node_id, args, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
210+
check_binders(psess, node_id, args, &Stack::Empty, &mut binders, ops, collect, &mut guar);
207211
}
208-
check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
209-
check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar);
212+
check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, ops, collect, &mut guar);
213+
check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, ops, collect, &mut guar);
210214
guar.map_or(Ok(()), Err)
211215
}
212216

@@ -220,6 +224,7 @@ pub(super) fn check_meta_variables(
220224
/// - `macros` is the stack of possible outer macros
221225
/// - `binders` contains the binders of the LHS
222226
/// - `ops` is the stack of Kleene operators from the LHS
227+
/// - `collect` is updated to recursive if we encounter any metadata expressions
223228
/// - `guar` is set in case of errors
224229
fn check_binders(
225230
psess: &ParseSess,
@@ -228,6 +233,7 @@ fn check_binders(
228233
macros: &Stack<'_, MacroState<'_>>,
229234
binders: &mut Binders,
230235
ops: &Stack<'_, KleeneToken>,
236+
collect: &mut ForceCollect,
231237
guar: &mut Option<ErrorGuaranteed>,
232238
) {
233239
match *lhs {
@@ -255,7 +261,7 @@ fn check_binders(
255261
binders.insert(name, BinderInfo { span, ops: ops.into() });
256262
} else {
257263
// 3. The meta-variable is bound: This is an occurrence.
258-
check_occurrences(psess, node_id, lhs, macros, binders, ops, guar);
264+
check_occurrences(psess, node_id, lhs, macros, binders, ops, collect, guar);
259265
}
260266
}
261267
// Similarly, this can only happen when checking a toplevel macro.
@@ -280,13 +286,13 @@ fn check_binders(
280286
TokenTree::MetaVarExpr(..) => {}
281287
TokenTree::Delimited(.., ref del) => {
282288
for tt in &del.tts {
283-
check_binders(psess, node_id, tt, macros, binders, ops, guar);
289+
check_binders(psess, node_id, tt, macros, binders, ops, collect, guar);
284290
}
285291
}
286292
TokenTree::Sequence(_, ref seq) => {
287293
let ops = ops.push(seq.kleene);
288294
for tt in &seq.tts {
289-
check_binders(psess, node_id, tt, macros, binders, &ops, guar);
295+
check_binders(psess, node_id, tt, macros, binders, &ops, collect, guar);
290296
}
291297
}
292298
}
@@ -316,6 +322,7 @@ fn get_binder_info<'a>(
316322
/// - `macros` is the stack of possible outer macros
317323
/// - `binders` contains the binders of the associated LHS
318324
/// - `ops` is the stack of Kleene operators from the RHS
325+
/// - `collect` is updated to recursive if we encounter any metadata expressions
319326
/// - `guar` is set in case of errors
320327
fn check_occurrences(
321328
psess: &ParseSess,
@@ -324,6 +331,7 @@ fn check_occurrences(
324331
macros: &Stack<'_, MacroState<'_>>,
325332
binders: &Binders,
326333
ops: &Stack<'_, KleeneToken>,
334+
collect: &mut ForceCollect,
327335
guar: &mut Option<ErrorGuaranteed>,
328336
) {
329337
match *rhs {
@@ -336,17 +344,21 @@ fn check_occurrences(
336344
check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name);
337345
}
338346
TokenTree::MetaVarExpr(dl, ref mve) => {
347+
// Require recursive token collection if we have any metadata expressions
348+
*collect = ForceCollect::Recursive;
339349
mve.for_each_metavar((), |_, ident| {
340350
let name = MacroRulesNormalizedIdent::new(*ident);
341351
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
342352
});
343353
}
344354
TokenTree::Delimited(.., ref del) => {
345-
check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar);
355+
check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, collect, guar);
346356
}
347357
TokenTree::Sequence(_, ref seq) => {
348358
let ops = ops.push(seq.kleene);
349-
check_nested_occurrences(psess, node_id, &seq.tts, macros, binders, &ops, guar);
359+
check_nested_occurrences(
360+
psess, node_id, &seq.tts, macros, binders, &ops, collect, guar,
361+
);
350362
}
351363
}
352364
}
@@ -381,6 +393,7 @@ enum NestedMacroState {
381393
/// - `macros` is the stack of possible outer macros
382394
/// - `binders` contains the binders of the associated LHS
383395
/// - `ops` is the stack of Kleene operators from the RHS
396+
/// - `collect` is updated to recursive if we encounter metadata expressions or nested macros
384397
/// - `guar` is set in case of errors
385398
fn check_nested_occurrences(
386399
psess: &ParseSess,
@@ -389,6 +402,7 @@ fn check_nested_occurrences(
389402
macros: &Stack<'_, MacroState<'_>>,
390403
binders: &Binders,
391404
ops: &Stack<'_, KleeneToken>,
405+
collect: &mut ForceCollect,
392406
guar: &mut Option<ErrorGuaranteed>,
393407
) {
394408
let mut state = NestedMacroState::Empty;
@@ -421,16 +435,26 @@ fn check_nested_occurrences(
421435
(NestedMacroState::MacroRulesBang, &TokenTree::MetaVar(..)) => {
422436
state = NestedMacroState::MacroRulesBangName;
423437
// We check that the meta-variable is correctly used.
424-
check_occurrences(psess, node_id, tt, macros, binders, ops, guar);
438+
check_occurrences(psess, node_id, tt, macros, binders, ops, collect, guar);
425439
}
426440
(NestedMacroState::MacroRulesBangName, TokenTree::Delimited(.., del))
427441
| (NestedMacroState::MacroName, TokenTree::Delimited(.., del))
428442
if del.delim == Delimiter::Brace =>
429443
{
444+
// Conservatively assume that we might need recursive tokens, since our parsing in
445+
// the face of nested macro definitions is fuzzy.
446+
*collect = ForceCollect::Recursive;
430447
let macro_rules = state == NestedMacroState::MacroRulesBangName;
431448
state = NestedMacroState::Empty;
432-
let rest =
433-
check_nested_macro(psess, node_id, macro_rules, &del.tts, &nested_macros, guar);
449+
let rest = check_nested_macro(
450+
psess,
451+
node_id,
452+
macro_rules,
453+
&del.tts,
454+
&nested_macros,
455+
collect,
456+
guar,
457+
);
434458
// If we did not check the whole macro definition, then check the rest as if outside
435459
// the macro definition.
436460
check_nested_occurrences(
@@ -440,6 +464,7 @@ fn check_nested_occurrences(
440464
macros,
441465
binders,
442466
ops,
467+
collect,
443468
guar,
444469
);
445470
}
@@ -452,7 +477,7 @@ fn check_nested_occurrences(
452477
(NestedMacroState::Macro, &TokenTree::MetaVar(..)) => {
453478
state = NestedMacroState::MacroName;
454479
// We check that the meta-variable is correctly used.
455-
check_occurrences(psess, node_id, tt, macros, binders, ops, guar);
480+
check_occurrences(psess, node_id, tt, macros, binders, ops, collect, guar);
456481
}
457482
(NestedMacroState::MacroName, TokenTree::Delimited(.., del))
458483
if del.delim == Delimiter::Parenthesis =>
@@ -466,6 +491,7 @@ fn check_nested_occurrences(
466491
&nested_macros,
467492
&mut nested_binders,
468493
&Stack::Empty,
494+
collect,
469495
guar,
470496
);
471497
}
@@ -480,12 +506,13 @@ fn check_nested_occurrences(
480506
&nested_macros,
481507
&nested_binders,
482508
&Stack::Empty,
509+
collect,
483510
guar,
484511
);
485512
}
486513
(_, tt) => {
487514
state = NestedMacroState::Empty;
488-
check_occurrences(psess, node_id, tt, macros, binders, ops, guar);
515+
check_occurrences(psess, node_id, tt, macros, binders, ops, collect, guar);
489516
}
490517
}
491518
}
@@ -504,13 +531,15 @@ fn check_nested_occurrences(
504531
/// - `macro_rules` specifies whether the macro is `macro_rules`
505532
/// - `tts` is checked as a list of (LHS) => {RHS}
506533
/// - `macros` is the stack of outer macros
534+
/// - `collect` is passed down through to the macro checking code (but is already recursive)
507535
/// - `guar` is set in case of errors
508536
fn check_nested_macro(
509537
psess: &ParseSess,
510538
node_id: NodeId,
511539
macro_rules: bool,
512540
tts: &[TokenTree],
513541
macros: &Stack<'_, MacroState<'_>>,
542+
collect: &mut ForceCollect,
514543
guar: &mut Option<ErrorGuaranteed>,
515544
) -> usize {
516545
let n = tts.len();
@@ -528,8 +557,8 @@ fn check_nested_macro(
528557
let lhs = &tts[i];
529558
let rhs = &tts[i + 2];
530559
let mut binders = Binders::default();
531-
check_binders(psess, node_id, lhs, macros, &mut binders, &Stack::Empty, guar);
532-
check_occurrences(psess, node_id, rhs, macros, &binders, &Stack::Empty, guar);
560+
check_binders(psess, node_id, lhs, macros, &mut binders, &Stack::Empty, collect, guar);
561+
check_occurrences(psess, node_id, rhs, macros, &binders, &Stack::Empty, collect, guar);
533562
// Since the last semicolon is optional for `macro_rules` macros and decl_macro are not terminated,
534563
// we increment our checked position by how many token trees we already checked (the 3
535564
// above) before checking for the separator.

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind};
8181
use rustc_data_structures::fx::FxHashMap;
8282
use rustc_errors::ErrorGuaranteed;
8383
use rustc_lint_defs::pluralize;
84-
use rustc_parse::parser::{ParseNtResult, Parser, token_descr};
84+
use rustc_parse::parser::{ForceCollect, ParseNtResult, Parser, token_descr};
8585
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span};
8686

8787
use crate::mbe::macro_rules::Tracker;
@@ -616,6 +616,7 @@ impl TtParser {
616616
&mut self,
617617
parser: &mut Cow<'_, Parser<'_>>,
618618
matcher: &'matcher [MatcherLoc],
619+
collect_mode: ForceCollect,
619620
track: &mut T,
620621
) -> NamedParseResult<T::Failure> {
621622
// A queue of possible matcher positions. We initialize it with the matcher position in
@@ -675,7 +676,7 @@ impl TtParser {
675676
{
676677
// We use the span of the metavariable declaration to determine any
677678
// edition-specific matching behavior for non-terminals.
678-
let nt = match parser.to_mut().parse_nonterminal(kind) {
679+
let nt = match parser.to_mut().parse_nonterminal(kind, collect_mode) {
679680
Err(err) => {
680681
let guarantee = err.with_span_label(
681682
span,

0 commit comments

Comments
 (0)