about summary refs log tree commit diff
path: root/compiler/rustc_expand/src/expand.rs
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-08-13 18:43:01 +0200
committerGitHub <noreply@github.com>2025-08-13 18:43:01 +0200
commitbd6fb635965cbbc8c70f5e011b5c19711e52a5fe (patch)
tree4369489a4038589bd7152b3d04669926e3e70952 /compiler/rustc_expand/src/expand.rs
parent0774928cf18f471466f1e0fdbdbeada342dc7951 (diff)
parente1fc89af5bb657acb45097cae15873de78210065 (diff)
downloadrust-bd6fb635965cbbc8c70f5e011b5c19711e52a5fe.tar.gz
rust-bd6fb635965cbbc8c70f5e011b5c19711e52a5fe.zip
Rollup merge of #145153 - joshtriplett:macro-kinds-plural, r=petrochenkov
Handle macros with multiple kinds, and improve errors

(I recommend reviewing this commit-by-commit.)

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.

This allows detecting and report macro kind mismatches early, and more precisely, improving various error messages. In particular, this eliminates the case in `failed_to_match_macro` to check for a function-like invocation of a macro with no function-like rules.

Instead, macro kind mismatches now result in an unresolved macro, and we detect this case in `unresolved_macro_suggestions`, which now carefully distinguishes between a kind mismatch and other errors.

This also handles cases of forward-referenced attributes and cyclic attributes.

----

In this PR, I've minimally fixed up `rustdoc` so that it compiles and passes tests. This is just the minimal necessary fixes to handle the switch to `MacroKinds`, and it only works for macros that don't actually have multiple kinds. This will panic (with a `todo!`) if it encounters a macro with multiple kinds.

rustdoc needs further fixes to handle macros with multiple kinds, and to handle attributes and derive macros that aren't proc macros. I'd appreciate some help from a rustdoc expert on that.

----

r? ````````@petrochenkov````````
Diffstat (limited to 'compiler/rustc_expand/src/expand.rs')
-rw-r--r--compiler/rustc_expand/src/expand.rs27
1 files changed, 13 insertions, 14 deletions
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 00533285fb4..670f5c91bb9 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) => {