diff options
| author | Josh Triplett <josh@joshtriplett.org> | 2025-08-07 19:21:16 -0700 |
|---|---|---|
| committer | Josh Triplett <josh@joshtriplett.org> | 2025-08-12 09:24:45 -0700 |
| commit | 0b855bcdc9b0fafa5a4a4330e10655105daf27cb (patch) | |
| tree | ee706f5f13096639cb38842ee8979ae471514640 /compiler/rustc_expand | |
| parent | 6355cd39c81e9699b1925c58d2ed3165bcab1715 (diff) | |
| download | rust-0b855bcdc9b0fafa5a4a4330e10655105daf27cb.tar.gz rust-0b855bcdc9b0fafa5a4a4330e10655105daf27cb.zip | |
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.
Diffstat (limited to 'compiler/rustc_expand')
| -rw-r--r-- | compiler/rustc_expand/src/base.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/mbe/macro_rules.rs | 26 |
3 files changed, 68 insertions, 31 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c234aa43c09..c47c076e56e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -17,6 +17,7 @@ use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; +use rustc_hir::def::MacroKinds; use rustc_hir::{Stability, find_attr}; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::MACRO_ARGUMENTS; @@ -718,6 +719,9 @@ impl MacResult for DummyResult { /// A syntax extension kind. #[derive(Clone)] pub enum SyntaxExtensionKind { + /// A `macro_rules!` macro that can work as any `MacroKind` + MacroRules(Arc<crate::MacroRulesMacroExpander>), + /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. @@ -775,6 +779,34 @@ pub enum SyntaxExtensionKind { GlobDelegation(Arc<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>), } +impl SyntaxExtensionKind { + /// Returns `Some(expander)` for a macro usable as a `LegacyBang`; otherwise returns `None` + /// + /// This includes a `MacroRules` with function-like rules. + pub fn as_legacy_bang(&self) -> Option<&(dyn TTMacroExpander + sync::DynSync + sync::DynSend)> { + match self { + SyntaxExtensionKind::LegacyBang(exp) => Some(exp.as_ref()), + SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::BANG) => { + Some(exp.as_ref()) + } + _ => None, + } + } + + /// Returns `Some(expander)` for a macro usable as an `Attr`; otherwise returns `None` + /// + /// This includes a `MacroRules` with `attr` rules. + pub fn as_attr(&self) -> Option<&(dyn AttrProcMacro + sync::DynSync + sync::DynSend)> { + match self { + SyntaxExtensionKind::Attr(exp) => Some(exp.as_ref()), + SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::ATTR) => { + Some(exp.as_ref()) + } + _ => None, + } + } +} + /// A struct representing a macro definition in "lowered" form ready for expansion. pub struct SyntaxExtension { /// A syntax extension kind. @@ -804,18 +836,19 @@ pub struct SyntaxExtension { } impl SyntaxExtension { - /// Returns which kind of macro calls this syntax extension. - pub fn macro_kind(&self) -> MacroKind { + /// Returns which kinds of macro call this syntax extension. + pub fn macro_kinds(&self) -> MacroKinds { match self.kind { SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) - | SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang, + | SyntaxExtensionKind::GlobDelegation(..) => MacroKinds::BANG, SyntaxExtensionKind::Attr(..) | SyntaxExtensionKind::LegacyAttr(..) - | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr, + | SyntaxExtensionKind::NonMacroAttr => MacroKinds::ATTR, SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - MacroKind::Derive + MacroKinds::DERIVE } + SyntaxExtensionKind::MacroRules(ref m) => m.kinds(), } } @@ -1027,11 +1060,12 @@ impl SyntaxExtension { parent: LocalExpnId, call_site: Span, descr: Symbol, + kind: MacroKind, macro_def_id: Option<DefId>, parent_module: Option<DefId>, ) -> ExpnData { ExpnData::new( - ExpnKind::Macro(self.macro_kind(), descr), + ExpnKind::Macro(kind, descr), parent.to_expn_id(), call_site, self.span, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index e7ae4416968..f675541e079 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -736,8 +736,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { - InvocationKind::Bang { mac, span } => match ext { - SyntaxExtensionKind::Bang(expander) => { + InvocationKind::Bang { mac, span } => { + if let SyntaxExtensionKind::Bang(expander) = ext { match expander.expand(self.cx, span, mac.args.tokens.clone()) { Ok(tok_result) => { let fragment = @@ -755,8 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } - } - SyntaxExtensionKind::LegacyBang(expander) => { + } else if let Some(expander) = ext.as_legacy_bang() { let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) { ExpandResult::Ready(tok_result) => tok_result, ExpandResult::Retry(_) => { @@ -776,11 +775,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); fragment_kind.dummy(span, guar) } + } else { + unreachable!(); } - _ => unreachable!(), - }, - InvocationKind::Attr { attr, pos, mut item, derives } => match ext { - SyntaxExtensionKind::Attr(expander) => { + } + InvocationKind::Attr { attr, pos, mut item, derives } => { + if let Some(expander) = ext.as_attr() { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); let tokens = match &item { @@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } - } - SyntaxExtensionKind::LegacyAttr(expander) => { + } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { let item_clone = macro_stats.then(|| item.clone()); @@ -878,15 +877,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment_kind.expect_from_annotatables(iter::once(item)) } } - } - SyntaxExtensionKind::NonMacroAttr => { + } else if let SyntaxExtensionKind::NonMacroAttr = ext { // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); fragment_kind.expect_from_annotatables(iter::once(item)) + } else { + unreachable!(); } - _ => unreachable!(), - }, + } InvocationKind::Derive { path, item, is_const } => match ext { SyntaxExtensionKind::Derive(expander) | SyntaxExtensionKind::LegacyDerive(expander) => { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 08b0efb74a0..334f57f9d62 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -15,6 +15,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::MacroKinds; use rustc_hir::find_attr; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ @@ -144,6 +145,7 @@ pub struct MacroRulesMacroExpander { name: Ident, span: Span, transparency: Transparency, + kinds: MacroKinds, rules: Vec<MacroRule>, } @@ -158,6 +160,10 @@ impl MacroRulesMacroExpander { }; if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) } } + + pub fn kinds(&self) -> MacroKinds { + self.kinds + } } impl TTMacroExpander for MacroRulesMacroExpander { @@ -540,13 +546,13 @@ pub fn compile_declarative_macro( span: Span, node_id: NodeId, edition: Edition, -) -> (SyntaxExtension, Option<Arc<SyntaxExtension>>, usize) { +) -> (SyntaxExtension, usize) { let mk_syn_ext = |kind| { let is_local = is_defined_in_current_crate(node_id); SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; - let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander)); - let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0); + let dummy_syn_ext = + |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -559,12 +565,12 @@ pub fn compile_declarative_macro( let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); - let mut has_attr_rules = false; + let mut kinds = MacroKinds::empty(); let mut rules = Vec::new(); while p.token != token::Eof { let args = if p.eat_keyword_noexpect(sym::attr) { - has_attr_rules = true; + kinds |= MacroKinds::ATTR; if !features.macro_attr() { feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable") .emit(); @@ -581,6 +587,7 @@ pub fn compile_declarative_macro( } Some(args) } else { + kinds |= MacroKinds::BANG; None }; let lhs_tt = p.parse_token_tree(); @@ -627,6 +634,7 @@ pub fn compile_declarative_macro( let guar = sess.dcx().span_err(span, "macros must contain at least one rule"); return dummy_syn_ext(guar); } + assert!(!kinds.is_empty()); let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(macro_rules)); @@ -640,12 +648,8 @@ pub fn compile_declarative_macro( // Return the number of rules for unused rule linting, if this is a local macro. let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 }; - let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); - let opt_attr_ext = has_attr_rules.then(|| { - let exp = Arc::clone(&exp); - Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp))) - }); - (mk_bang_ext(exp), opt_attr_ext, nrules) + let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules }; + (mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules) } fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<ErrorGuaranteed> { |
