mbe: Defer checks for compile_error! until reporting an unused macro rule

The MBE parser checks rules at initial parse time to see if their RHS
has `compile_error!` in it, and returns a list of rule indexes and LHS
spans that don't map to `compile_error!`, for use in unused macro rule
checking.

Instead, have the unused macro rule reporting ask the macro for the rule
to report, and let the macro check at that time. That avoids checking
rules unless they're unused.

In the process, refactor the data structure used to store macro rules,
to group the LHS and RHS (and LHS span) of each rule together, and
refactor the unused rule tracking to only track rule indexes.

This ends up being a net simplification, and reduction in code size.
This commit is contained in:
Josh Triplett
2025-07-04 01:22:37 -07:00
parent 0d5ab3e46c
commit 63cfb3af37
6 changed files with 80 additions and 92 deletions

View File

@@ -351,13 +351,23 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
}
for (&node_id, unused_arms) in self.unused_macro_rules.iter() {
for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() {
self.lint_buffer.buffer_lint(
UNUSED_MACRO_RULES,
node_id,
rule_span,
BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name),
);
if unused_arms.is_empty() {
continue;
}
let def_id = self.local_def_id(node_id).to_def_id();
let m = &self.macro_map[&def_id];
let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else {
continue;
};
for &arm_i in unused_arms.to_sorted_stable_ord() {
if let Some((ident, rule_span)) = ext.get_unused_rule(arm_i) {
self.lint_buffer.buffer_lint(
UNUSED_MACRO_RULES,
node_id,
rule_span,
BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name),
);
}
}
}
}
@@ -1146,7 +1156,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
node_id: NodeId,
edition: Edition,
) -> MacroData {
let (mut ext, mut rule_spans) = compile_declarative_macro(
let (mut ext, mut nrules) = compile_declarative_macro(
self.tcx.sess,
self.tcx.features(),
macro_def,
@@ -1163,13 +1173,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
ext.kind = builtin_ext_kind.clone();
rule_spans = Vec::new();
nrules = 0;
} else {
self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
}
}
MacroData { ext: Arc::new(ext), rule_spans, macro_rules: macro_def.macro_rules }
MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules }
}
fn path_accessible(