Skip to content

Commit e47107f

Browse files
committed
Auto merge of #143456 - joshtriplett:mbe-unused-rules-bitset, r=<try>
mbe: Change `unused_macro_rules` to a `DenseBitSet` Now that it only contains indexes, and no other information, a bitset provides a more compact and simpler representation. This builds on <#143416>. Only the last commit is new.
2 parents e384365 + 78c30b8 commit e47107f

File tree

11 files changed

+238
-132
lines changed

11 files changed

+238
-132
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4462,6 +4462,7 @@ dependencies = [
44624462
"rustc_feature",
44634463
"rustc_fluent_macro",
44644464
"rustc_hir",
4465+
"rustc_index",
44654466
"rustc_macros",
44664467
"rustc_metadata",
44674468
"rustc_middle",

compiler/rustc_expand/src/base.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ pub trait TTMacroExpander {
348348
span: Span,
349349
input: TokenStream,
350350
) -> MacroExpanderResult<'cx>;
351+
352+
fn get_unused_rule(&self, _rule_i: usize) -> Option<(&Ident, Span)> {
353+
None
354+
}
351355
}
352356

353357
pub type MacroExpanderResult<'cx> = ExpandResult<Box<dyn MacResult + 'cx>, ()>;

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_span::source_map::SourceMap;
1010
use rustc_span::{ErrorGuaranteed, Ident, Span};
1111
use tracing::debug;
1212

13-
use super::macro_rules::{NoopTracker, parser_from_cx};
13+
use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx};
1414
use crate::expand::{AstFragmentKind, parse_ast_fragment};
1515
use crate::mbe::macro_parser::ParseResult::*;
1616
use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
@@ -22,14 +22,14 @@ pub(super) fn failed_to_match_macro(
2222
def_span: Span,
2323
name: Ident,
2424
arg: TokenStream,
25-
lhses: &[Vec<MatcherLoc>],
25+
rules: &[MacroRule],
2626
) -> (Span, ErrorGuaranteed) {
2727
debug!("failed to match macro");
2828
// An error occurred, try the expansion again, tracking the expansion closely for better
2929
// diagnostics.
3030
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
3131

32-
let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker);
32+
let try_success_result = try_match_macro(psess, name, &arg, rules, &mut tracker);
3333

3434
if try_success_result.is_ok() {
3535
// Nonterminal parser recovery might turn failed matches into successful ones,
@@ -80,12 +80,12 @@ pub(super) fn failed_to_match_macro(
8080

8181
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
8282
if let Some((arg, comma_span)) = arg.add_comma() {
83-
for lhs in lhses {
83+
for rule in rules {
8484
let parser = parser_from_cx(psess, arg.clone(), Recovery::Allowed);
8585
let mut tt_parser = TtParser::new(name);
8686

8787
if let Success(_) =
88-
tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker)
88+
tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, &mut NoopTracker)
8989
{
9090
if comma_span.is_dummy() {
9191
err.note("you might be missing a comma");

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 59 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use crate::base::{
3636
};
3737
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
3838
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
39+
use crate::mbe::quoted::{RulePart, parse_one_tt};
3940
use crate::mbe::transcribe::transcribe;
4041
use crate::mbe::{self, KleeneOp, macro_check};
4142

@@ -97,13 +98,18 @@ impl<'a> ParserAnyMacro<'a> {
9798
}
9899
}
99100

101+
pub(super) struct MacroRule {
102+
pub(super) lhs: Vec<MatcherLoc>,
103+
lhs_span: Span,
104+
rhs: mbe::TokenTree,
105+
}
106+
100107
struct MacroRulesMacroExpander {
101108
node_id: NodeId,
102109
name: Ident,
103110
span: Span,
104111
transparency: Transparency,
105-
lhses: Vec<Vec<MatcherLoc>>,
106-
rhses: Vec<mbe::TokenTree>,
112+
rules: Vec<MacroRule>,
107113
}
108114

109115
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -121,10 +127,15 @@ impl TTMacroExpander for MacroRulesMacroExpander {
121127
self.name,
122128
self.transparency,
123129
input,
124-
&self.lhses,
125-
&self.rhses,
130+
&self.rules,
126131
))
127132
}
133+
134+
fn get_unused_rule(&self, rule_i: usize) -> Option<(&Ident, Span)> {
135+
// If the rhs contains an invocation like `compile_error!`, don't report it as unused.
136+
let rule = &self.rules[rule_i];
137+
if has_compile_error_macro(&rule.rhs) { None } else { Some((&self.name, rule.lhs_span)) }
138+
}
128139
}
129140

130141
struct DummyExpander(ErrorGuaranteed);
@@ -183,9 +194,8 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
183194
}
184195
}
185196

186-
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
187-
/// input `arg`.
188-
#[instrument(skip(cx, transparency, arg, lhses, rhses))]
197+
/// Expands the rules based macro defined by `rules` for a given input `arg`.
198+
#[instrument(skip(cx, transparency, arg, rules))]
189199
fn expand_macro<'cx>(
190200
cx: &'cx mut ExtCtxt<'_>,
191201
sp: Span,
@@ -194,8 +204,7 @@ fn expand_macro<'cx>(
194204
name: Ident,
195205
transparency: Transparency,
196206
arg: TokenStream,
197-
lhses: &[Vec<MatcherLoc>],
198-
rhses: &[mbe::TokenTree],
207+
rules: &[MacroRule],
199208
) -> Box<dyn MacResult + 'cx> {
200209
let psess = &cx.sess.psess;
201210
// Macros defined in the current crate have a real node id,
@@ -208,15 +217,14 @@ fn expand_macro<'cx>(
208217
}
209218

210219
// Track nothing for the best performance.
211-
let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut NoopTracker);
220+
let try_success_result = try_match_macro(psess, name, &arg, rules, &mut NoopTracker);
212221

213222
match try_success_result {
214-
Ok((i, named_matches)) => {
215-
let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
216-
mbe::TokenTree::Delimited(span, _, delimited) => (&delimited, *span),
217-
_ => cx.dcx().span_bug(sp, "malformed macro rhs"),
223+
Ok((i, rule, named_matches)) => {
224+
let mbe::TokenTree::Delimited(rhs_span, _, ref rhs) = rule.rhs else {
225+
cx.dcx().span_bug(sp, "malformed macro rhs");
218226
};
219-
let arm_span = rhses[i].span();
227+
let arm_span = rule.rhs.span();
220228

221229
// rhs has holes ( `$id` and `$(...)` that need filled)
222230
let id = cx.current_expansion.id;
@@ -262,7 +270,7 @@ fn expand_macro<'cx>(
262270
Err(CanRetry::Yes) => {
263271
// Retry and emit a better error.
264272
let (span, guar) =
265-
diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, lhses);
273+
diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules);
266274
cx.trace_macros_diag();
267275
DummyResult::any(span, guar)
268276
}
@@ -278,14 +286,14 @@ pub(super) enum CanRetry {
278286
/// Try expanding the macro. Returns the index of the successful arm and its named_matches if it was successful,
279287
/// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
280288
/// correctly.
281-
#[instrument(level = "debug", skip(psess, arg, lhses, track), fields(tracking = %T::description()))]
289+
#[instrument(level = "debug", skip(psess, arg, rules, track), fields(tracking = %T::description()))]
282290
pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
283291
psess: &ParseSess,
284292
name: Ident,
285293
arg: &TokenStream,
286-
lhses: &'matcher [Vec<MatcherLoc>],
294+
rules: &'matcher [MacroRule],
287295
track: &mut T,
288-
) -> Result<(usize, NamedMatches), CanRetry> {
296+
) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> {
289297
// We create a base parser that can be used for the "black box" parts.
290298
// Every iteration needs a fresh copy of that parser. However, the parser
291299
// is not mutated on many of the iterations, particularly when dealing with
@@ -308,7 +316,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
308316
let parser = parser_from_cx(psess, arg.clone(), T::recovery());
309317
// Try each arm's matchers.
310318
let mut tt_parser = TtParser::new(name);
311-
for (i, lhs) in lhses.iter().enumerate() {
319+
for (i, rule) in rules.iter().enumerate() {
312320
let _tracing_span = trace_span!("Matching arm", %i);
313321

314322
// Take a snapshot of the state of pre-expansion gating at this point.
@@ -317,7 +325,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
317325
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
318326
let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut());
319327

320-
let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, track);
328+
let result = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &rule.lhs, track);
321329

322330
track.after_arm(&result);
323331

@@ -328,7 +336,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
328336
// Merge the gated spans from parsing the matcher with the preexisting ones.
329337
psess.gated_spans.merge(gated_spans_snapshot);
330338

331-
return Ok((i, named_matches));
339+
return Ok((i, rule, named_matches));
332340
}
333341
Failure(_) => {
334342
trace!("Failed to match arm, trying the next one");
@@ -364,7 +372,7 @@ pub fn compile_declarative_macro(
364372
span: Span,
365373
node_id: NodeId,
366374
edition: Edition,
367-
) -> (SyntaxExtension, Vec<(usize, Span)>) {
375+
) -> (SyntaxExtension, usize) {
368376
let mk_syn_ext = |expander| {
369377
SyntaxExtension::new(
370378
sess,
@@ -377,7 +385,7 @@ pub fn compile_declarative_macro(
377385
node_id != DUMMY_NODE_ID,
378386
)
379387
};
380-
let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), Vec::new());
388+
let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), 0);
381389

382390
let macro_rules = macro_def.macro_rules;
383391
let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@@ -389,43 +397,40 @@ pub fn compile_declarative_macro(
389397
let mut guar = None;
390398
let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
391399

392-
let mut lhses = Vec::new();
393-
let mut rhses = Vec::new();
400+
let mut rules = Vec::new();
394401

395402
while p.token != token::Eof {
396403
let lhs_tt = p.parse_token_tree();
397-
let lhs_tt = mbe::quoted::parse(
398-
&TokenStream::new(vec![lhs_tt]),
399-
true, // LHS
400-
sess,
401-
node_id,
402-
features,
403-
edition,
404-
)
405-
.pop()
406-
.unwrap();
404+
let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition);
407405
// We don't handle errors here, the driver will abort after parsing/expansion. We can
408406
// report every error in every macro this way.
409407
check_emission(check_lhs_nt_follows(sess, node_id, &lhs_tt));
410408
check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(&lhs_tt)));
411409
if let Err(e) = p.expect(exp!(FatArrow)) {
412410
return dummy_syn_ext(e.emit());
413411
}
412+
if p.token == token::Eof {
413+
let err_sp = p.token.span.shrink_to_hi();
414+
let guar = sess
415+
.dcx()
416+
.struct_span_err(err_sp, "macro definition ended unexpectedly")
417+
.with_span_label(err_sp, "expected right-hand side of macro rule")
418+
.emit();
419+
return dummy_syn_ext(guar);
420+
}
414421
let rhs_tt = p.parse_token_tree();
415-
let rhs_tt = mbe::quoted::parse(
416-
&TokenStream::new(vec![rhs_tt]),
417-
false, // RHS
418-
sess,
419-
node_id,
420-
features,
421-
edition,
422-
)
423-
.pop()
424-
.unwrap();
422+
let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition);
425423
check_emission(check_rhs(sess, &rhs_tt));
426424
check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt));
427-
lhses.push(lhs_tt);
428-
rhses.push(rhs_tt);
425+
let lhs_span = lhs_tt.span();
426+
// Convert the lhs into `MatcherLoc` form, which is better for doing the
427+
// actual matching.
428+
let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt {
429+
mbe::macro_parser::compute_locs(&delimited.tts)
430+
} else {
431+
return dummy_syn_ext(guar.unwrap());
432+
};
433+
rules.push(MacroRule { lhs, lhs_span, rhs: rhs_tt });
429434
if p.token == token::Eof {
430435
break;
431436
}
@@ -434,7 +439,7 @@ pub fn compile_declarative_macro(
434439
}
435440
}
436441

437-
if lhses.is_empty() {
442+
if rules.is_empty() {
438443
let guar = sess.dcx().span_err(span, "macros must contain at least one rule");
439444
return dummy_syn_ext(guar);
440445
}
@@ -448,48 +453,12 @@ pub fn compile_declarative_macro(
448453
return dummy_syn_ext(guar);
449454
}
450455

451-
// Compute the spans of the macro rules for unused rule linting.
452-
// Also, we are only interested in non-foreign macros.
453-
let rule_spans = if node_id != DUMMY_NODE_ID {
454-
lhses
455-
.iter()
456-
.zip(rhses.iter())
457-
.enumerate()
458-
// If the rhs contains an invocation like compile_error!,
459-
// don't consider the rule for the unused rule lint.
460-
.filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs))
461-
// We only take the span of the lhs here,
462-
// so that the spans of created warnings are smaller.
463-
.map(|(idx, (lhs, _rhs))| (idx, lhs.span()))
464-
.collect::<Vec<_>>()
465-
} else {
466-
Vec::new()
467-
};
456+
// Return the number of rules for unused rule linting, if this is a local macro.
457+
let nrules = if node_id != DUMMY_NODE_ID { rules.len() } else { 0 };
468458

469-
// Convert the lhses into `MatcherLoc` form, which is better for doing the
470-
// actual matching.
471-
let lhses = lhses
472-
.iter()
473-
.map(|lhs| {
474-
// Ignore the delimiters around the matcher.
475-
match lhs {
476-
mbe::TokenTree::Delimited(.., delimited) => {
477-
mbe::macro_parser::compute_locs(&delimited.tts)
478-
}
479-
_ => sess.dcx().span_bug(span, "malformed macro lhs"),
480-
}
481-
})
482-
.collect();
483-
484-
let expander = Arc::new(MacroRulesMacroExpander {
485-
name: ident,
486-
span,
487-
node_id,
488-
transparency,
489-
lhses,
490-
rhses,
491-
});
492-
(mk_syn_ext(expander), rule_spans)
459+
let expander =
460+
Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
461+
(mk_syn_ext(expander), nrules)
493462
}
494463

495464
fn check_lhs_nt_follows(

0 commit comments

Comments
 (0)