Skip to content

Commit 0b855bc

Browse files
committed
Switch to a bitflags MacroKinds to support macros with more than one kind
Review everything that uses `MacroKind`, and switch anything that could refer to more than one kind to use `MacroKinds`. Add a new `SyntaxExtensionKind::MacroRules` for `macro_rules!` macros, using the concrete `MacroRulesMacroExpander` type, and have it track which kinds it can handle. Eliminate the separate optional `attr_ext`, now that a `SyntaxExtension` can handle multiple macro kinds. This also avoids the need to downcast when calling methods on `MacroRulesMacroExpander`, such as `get_unused_rule`. Integrate macro kind checking into name resolution's `sub_namespace_match`, so that we only find a macro if it's the right type, and eliminate the special-case hack for attributes.
1 parent 6355cd3 commit 0b855bc

File tree

19 files changed

+212
-119
lines changed

19 files changed

+212
-119
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,6 +3889,7 @@ dependencies = [
38893889
name = "rustc_hir"
38903890
version = "0.0.0"
38913891
dependencies = [
3892+
"bitflags",
38923893
"odht",
38933894
"rustc_abi",
38943895
"rustc_arena",

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
464464
let body = Box::new(self.lower_delim_args(body));
465465
let def_id = self.local_def_id(id);
466466
let def_kind = self.tcx.def_kind(def_id);
467-
let DefKind::Macro(macro_kind) = def_kind else {
467+
let DefKind::Macro(macro_kinds) = def_kind else {
468468
unreachable!(
469469
"expected DefKind::Macro for macro item, found {}",
470470
def_kind.descr(def_id.to_def_id())
471471
);
472472
};
473473
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
474-
hir::ItemKind::Macro(ident, macro_def, macro_kind)
474+
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
475475
}
476476
ItemKind::Delegation(box delegation) => {
477477
let delegation_results = self.lower_delegation(delegation, id, false);

compiler/rustc_expand/src/base.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
1717
use rustc_feature::Features;
1818
use rustc_hir as hir;
1919
use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
20+
use rustc_hir::def::MacroKinds;
2021
use rustc_hir::{Stability, find_attr};
2122
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
2223
use rustc_parse::MACRO_ARGUMENTS;
@@ -718,6 +719,9 @@ impl MacResult for DummyResult {
718719
/// A syntax extension kind.
719720
#[derive(Clone)]
720721
pub enum SyntaxExtensionKind {
722+
/// A `macro_rules!` macro that can work as any `MacroKind`
723+
MacroRules(Arc<crate::MacroRulesMacroExpander>),
724+
721725
/// A token-based function-like macro.
722726
Bang(
723727
/// An expander with signature TokenStream -> TokenStream.
@@ -775,6 +779,34 @@ pub enum SyntaxExtensionKind {
775779
GlobDelegation(Arc<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
776780
}
777781

782+
impl SyntaxExtensionKind {
783+
/// Returns `Some(expander)` for a macro usable as a `LegacyBang`; otherwise returns `None`
784+
///
785+
/// This includes a `MacroRules` with function-like rules.
786+
pub fn as_legacy_bang(&self) -> Option<&(dyn TTMacroExpander + sync::DynSync + sync::DynSend)> {
787+
match self {
788+
SyntaxExtensionKind::LegacyBang(exp) => Some(exp.as_ref()),
789+
SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::BANG) => {
790+
Some(exp.as_ref())
791+
}
792+
_ => None,
793+
}
794+
}
795+
796+
/// Returns `Some(expander)` for a macro usable as an `Attr`; otherwise returns `None`
797+
///
798+
/// This includes a `MacroRules` with `attr` rules.
799+
pub fn as_attr(&self) -> Option<&(dyn AttrProcMacro + sync::DynSync + sync::DynSend)> {
800+
match self {
801+
SyntaxExtensionKind::Attr(exp) => Some(exp.as_ref()),
802+
SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::ATTR) => {
803+
Some(exp.as_ref())
804+
}
805+
_ => None,
806+
}
807+
}
808+
}
809+
778810
/// A struct representing a macro definition in "lowered" form ready for expansion.
779811
pub struct SyntaxExtension {
780812
/// A syntax extension kind.
@@ -804,18 +836,19 @@ pub struct SyntaxExtension {
804836
}
805837

806838
impl SyntaxExtension {
807-
/// Returns which kind of macro calls this syntax extension.
808-
pub fn macro_kind(&self) -> MacroKind {
839+
/// Returns which kinds of macro call this syntax extension.
840+
pub fn macro_kinds(&self) -> MacroKinds {
809841
match self.kind {
810842
SyntaxExtensionKind::Bang(..)
811843
| SyntaxExtensionKind::LegacyBang(..)
812-
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
844+
| SyntaxExtensionKind::GlobDelegation(..) => MacroKinds::BANG,
813845
SyntaxExtensionKind::Attr(..)
814846
| SyntaxExtensionKind::LegacyAttr(..)
815-
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
847+
| SyntaxExtensionKind::NonMacroAttr => MacroKinds::ATTR,
816848
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
817-
MacroKind::Derive
849+
MacroKinds::DERIVE
818850
}
851+
SyntaxExtensionKind::MacroRules(ref m) => m.kinds(),
819852
}
820853
}
821854

@@ -1027,11 +1060,12 @@ impl SyntaxExtension {
10271060
parent: LocalExpnId,
10281061
call_site: Span,
10291062
descr: Symbol,
1063+
kind: MacroKind,
10301064
macro_def_id: Option<DefId>,
10311065
parent_module: Option<DefId>,
10321066
) -> ExpnData {
10331067
ExpnData::new(
1034-
ExpnKind::Macro(self.macro_kind(), descr),
1068+
ExpnKind::Macro(kind, descr),
10351069
parent.to_expn_id(),
10361070
call_site,
10371071
self.span,

compiler/rustc_expand/src/expand.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -736,8 +736,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
736736

737737
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
738738
ExpandResult::Ready(match invoc.kind {
739-
InvocationKind::Bang { mac, span } => match ext {
740-
SyntaxExtensionKind::Bang(expander) => {
739+
InvocationKind::Bang { mac, span } => {
740+
if let SyntaxExtensionKind::Bang(expander) = ext {
741741
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
742742
Ok(tok_result) => {
743743
let fragment =
@@ -755,8 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
755755
}
756756
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
757757
}
758-
}
759-
SyntaxExtensionKind::LegacyBang(expander) => {
758+
} else if let Some(expander) = ext.as_legacy_bang() {
760759
let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
761760
ExpandResult::Ready(tok_result) => tok_result,
762761
ExpandResult::Retry(_) => {
@@ -776,11 +775,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
776775
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
777776
fragment_kind.dummy(span, guar)
778777
}
778+
} else {
779+
unreachable!();
779780
}
780-
_ => unreachable!(),
781-
},
782-
InvocationKind::Attr { attr, pos, mut item, derives } => match ext {
783-
SyntaxExtensionKind::Attr(expander) => {
781+
}
782+
InvocationKind::Attr { attr, pos, mut item, derives } => {
783+
if let Some(expander) = ext.as_attr() {
784784
self.gate_proc_macro_input(&item);
785785
self.gate_proc_macro_attr_item(span, &item);
786786
let tokens = match &item {
@@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
835835
}
836836
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
837837
}
838-
}
839-
SyntaxExtensionKind::LegacyAttr(expander) => {
838+
} else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {
840839
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
841840
Ok(meta) => {
842841
let item_clone = macro_stats.then(|| item.clone());
@@ -878,15 +877,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
878877
fragment_kind.expect_from_annotatables(iter::once(item))
879878
}
880879
}
881-
}
882-
SyntaxExtensionKind::NonMacroAttr => {
880+
} else if let SyntaxExtensionKind::NonMacroAttr = ext {
883881
// `-Zmacro-stats` ignores these because they don't do any real expansion.
884882
self.cx.expanded_inert_attrs.mark(&attr);
885883
item.visit_attrs(|attrs| attrs.insert(pos, attr));
886884
fragment_kind.expect_from_annotatables(iter::once(item))
885+
} else {
886+
unreachable!();
887887
}
888-
_ => unreachable!(),
889-
},
888+
}
890889
InvocationKind::Derive { path, item, is_const } => match ext {
891890
SyntaxExtensionKind::Derive(expander)
892891
| SyntaxExtensionKind::LegacyDerive(expander) => {

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
1515
use rustc_feature::Features;
1616
use rustc_hir as hir;
1717
use rustc_hir::attrs::AttributeKind;
18+
use rustc_hir::def::MacroKinds;
1819
use rustc_hir::find_attr;
1920
use rustc_lint_defs::BuiltinLintDiag;
2021
use rustc_lint_defs::builtin::{
@@ -144,6 +145,7 @@ pub struct MacroRulesMacroExpander {
144145
name: Ident,
145146
span: Span,
146147
transparency: Transparency,
148+
kinds: MacroKinds,
147149
rules: Vec<MacroRule>,
148150
}
149151

@@ -158,6 +160,10 @@ impl MacroRulesMacroExpander {
158160
};
159161
if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) }
160162
}
163+
164+
pub fn kinds(&self) -> MacroKinds {
165+
self.kinds
166+
}
161167
}
162168

163169
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -540,13 +546,13 @@ pub fn compile_declarative_macro(
540546
span: Span,
541547
node_id: NodeId,
542548
edition: Edition,
543-
) -> (SyntaxExtension, Option<Arc<SyntaxExtension>>, usize) {
549+
) -> (SyntaxExtension, usize) {
544550
let mk_syn_ext = |kind| {
545551
let is_local = is_defined_in_current_crate(node_id);
546552
SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
547553
};
548-
let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander));
549-
let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0);
554+
let dummy_syn_ext =
555+
|guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0);
550556

551557
let macro_rules = macro_def.macro_rules;
552558
let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@@ -559,12 +565,12 @@ pub fn compile_declarative_macro(
559565
let mut guar = None;
560566
let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
561567

562-
let mut has_attr_rules = false;
568+
let mut kinds = MacroKinds::empty();
563569
let mut rules = Vec::new();
564570

565571
while p.token != token::Eof {
566572
let args = if p.eat_keyword_noexpect(sym::attr) {
567-
has_attr_rules = true;
573+
kinds |= MacroKinds::ATTR;
568574
if !features.macro_attr() {
569575
feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable")
570576
.emit();
@@ -581,6 +587,7 @@ pub fn compile_declarative_macro(
581587
}
582588
Some(args)
583589
} else {
590+
kinds |= MacroKinds::BANG;
584591
None
585592
};
586593
let lhs_tt = p.parse_token_tree();
@@ -627,6 +634,7 @@ pub fn compile_declarative_macro(
627634
let guar = sess.dcx().span_err(span, "macros must contain at least one rule");
628635
return dummy_syn_ext(guar);
629636
}
637+
assert!(!kinds.is_empty());
630638

631639
let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
632640
.unwrap_or(Transparency::fallback(macro_rules));
@@ -640,12 +648,8 @@ pub fn compile_declarative_macro(
640648
// Return the number of rules for unused rule linting, if this is a local macro.
641649
let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 };
642650

643-
let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
644-
let opt_attr_ext = has_attr_rules.then(|| {
645-
let exp = Arc::clone(&exp);
646-
Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp)))
647-
});
648-
(mk_bang_ext(exp), opt_attr_ext, nrules)
651+
let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules };
652+
(mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules)
649653
}
650654

651655
fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<ErrorGuaranteed> {

compiler/rustc_hir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2024"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
bitflags = "2.9.1"
89
odht = { version = "0.3.1", features = ["nightly"] }
910
rustc_abi = { path = "../rustc_abi" }
1011
rustc_arena = { path = "../rustc_arena" }

compiler/rustc_hir/src/def.rs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,53 @@ pub enum CtorKind {
3131
Const,
3232
}
3333

34+
/// A set of macro kinds, for macros that can have more than one kind
35+
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
36+
#[derive(HashStable_Generic)]
37+
pub struct MacroKinds(u8);
38+
bitflags::bitflags! {
39+
impl MacroKinds: u8 {
40+
const BANG = 1 << 0;
41+
const ATTR = 1 << 1;
42+
const DERIVE = 1 << 2;
43+
}
44+
}
45+
46+
impl From<MacroKind> for MacroKinds {
47+
fn from(kind: MacroKind) -> Self {
48+
match kind {
49+
MacroKind::Bang => Self::BANG,
50+
MacroKind::Attr => Self::ATTR,
51+
MacroKind::Derive => Self::DERIVE,
52+
}
53+
}
54+
}
55+
56+
impl MacroKinds {
57+
/// Convert the MacroKinds to a static string.
58+
///
59+
/// This hardcodes all the possibilities, in order to return a static string.
60+
pub fn descr(self) -> &'static str {
61+
match self {
62+
// FIXME: change this to "function-like macro" and fix all tests
63+
Self::BANG => "macro",
64+
Self::ATTR => "attribute macro",
65+
Self::DERIVE => "derive macro",
66+
_ if self == (Self::ATTR | Self::BANG) => "attribute/function macro",
67+
_ if self == (Self::DERIVE | Self::BANG) => "derive/function macro",
68+
_ if self == (Self::ATTR | Self::DERIVE) => "attribute/derive macro",
69+
_ if self.is_all() => "attribute/derive/function macro",
70+
_ if self.is_empty() => "useless macro",
71+
_ => unreachable!(),
72+
}
73+
}
74+
75+
/// Return an indefinite article (a/an) for use with `descr()`
76+
pub fn article(self) -> &'static str {
77+
if self.contains(Self::ATTR) { "an" } else { "a" }
78+
}
79+
}
80+
3481
/// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`.
3582
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
3683
pub enum NonMacroAttrKind {
@@ -101,7 +148,7 @@ pub enum DefKind {
101148
AssocConst,
102149

103150
// Macro namespace
104-
Macro(MacroKind),
151+
Macro(MacroKinds),
105152

106153
// Not namespaced (or they are, but we don't treat them so)
107154
ExternCrate,
@@ -177,7 +224,7 @@ impl DefKind {
177224
DefKind::AssocConst => "associated constant",
178225
DefKind::TyParam => "type parameter",
179226
DefKind::ConstParam => "const parameter",
180-
DefKind::Macro(macro_kind) => macro_kind.descr(),
227+
DefKind::Macro(kinds) => kinds.descr(),
181228
DefKind::LifetimeParam => "lifetime parameter",
182229
DefKind::Use => "import",
183230
DefKind::ForeignMod => "foreign module",
@@ -208,7 +255,7 @@ impl DefKind {
208255
| DefKind::Use
209256
| DefKind::InlineConst
210257
| DefKind::ExternCrate => "an",
211-
DefKind::Macro(macro_kind) => macro_kind.article(),
258+
DefKind::Macro(kinds) => kinds.article(),
212259
_ => "a",
213260
}
214261
}
@@ -845,10 +892,10 @@ impl<Id> Res<Id> {
845892
)
846893
}
847894

848-
pub fn macro_kind(self) -> Option<MacroKind> {
895+
pub fn macro_kinds(self) -> Option<MacroKinds> {
849896
match self {
850-
Res::Def(DefKind::Macro(kind), _) => Some(kind),
851-
Res::NonMacroAttr(..) => Some(MacroKind::Attr),
897+
Res::Def(DefKind::Macro(kinds), _) => Some(kinds),
898+
Res::NonMacroAttr(..) => Some(MacroKinds::ATTR),
852899
_ => None,
853900
}
854901
}

0 commit comments

Comments
 (0)