Skip to content

Commit d54a8ac

Browse files
authored
Rollup merge of #110222 - lovelymono:rustc-expand-mbe-diagnostic, r=davidtwco
Improve the error message when forwarding a matched fragment to another macro Adds a link to [Forwarding a matched fragment](https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment) section of the Rust Reference, and suggests a possible fix (using `:tt` instead in the macro definition). Also removes typos from the original message, it should be `:lifetime` instead of `$lifetime`. ## Motivation When trying to write a macro which uses a literal in the matcher from the outer macro, like the following one, using a fragment specified that isn't one of `:ident`, `:lifetime`, or `:tt` currently results in a hard to understand message. ```rs macro_rules! make_t_for_all_tokens { ($($name:literal as $variant:expr,)*) => { macro_rules! t { $( ($name) => { $variant }; )* } }; } make_t_for_all_tokens! { "fn" as Token::Fn, "return" as Token::Return, "let" as Token::Let, } // This creates // // macro_rules! t { // ("fn") => { // Token::Fn // }; // ("return") => { // Token::Return // }; // ("let") => { // Token::Let // }; // } t!["fn"]; ``` ### Before ``` error: no rules expected the token `"fn"` --> src/main.rs:103:10 | 32 | macro_rules! t { | -------------- when calling this macro ... 103 | t!["fn"]; | ^^^^ no rules expected this token in macro call | note: while trying to match `"fn"` --> src/main.rs:34:6 | 34 | ($name) => { | ^^^^^ ... 58 | / make_t_for_all_tokens! { 59 | | "fn" as Token::Fn, 60 | | "return" as Token::Return, 61 | | "let" as Token::Let, 62 | | } | |_- in this macro invocation = note: captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens = note: this error originates in the macro `make_t_for_all_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) ``` ### After ``` error: no rules expected the token `"fn"` --> src/main.rs:103:10 | 32 | macro_rules! t { | -------------- when calling this macro ... 103 | t!["fn"]; | ^^^^ no rules expected this token in macro call | note: while trying to match `"fn"` --> src/main.rs:34:6 | 34 | ($name) => { | ^^^^^ ... 58 | / make_t_for_all_tokens! { 59 | | "fn" as Token::Fn, 60 | | "return" as Token::Return, 61 | | "let" as Token::Let, 62 | | } | |_- in this macro invocation = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens = note: see https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment for more information = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `make_t_for_all_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) ``` ## Unresolved questions - Preferrably the suggestion should be attached to the `$name:literal` part of the outer macro, instead of being in the notes section at the end. But I'm not familiar with how the compiler works at all, and I have no idea how to approach this kind of solution. - `@Nilstrieb` raised a question that the suggestion of adding `:tt` isn't accurate when there's more than `tt` being matched, for example when the input is an `item`.
2 parents b53817d + 04f20d4 commit d54a8ac

File tree

2 files changed

+9
-2
lines changed

2 files changed

+9
-2
lines changed

compiler/rustc_expand/src/mbe/diagnostics.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ pub(super) fn failed_to_match_macro<'cx>(
6666
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
6767
|| matches!(token.kind, TokenKind::Interpolated(_)))
6868
{
69-
err.note("captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens");
69+
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
70+
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
71+
72+
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
73+
err.help("try using `:tt` instead in the macro definition");
74+
}
7075
}
7176

7277
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`

tests/ui/macros/nonterminal-matching.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ LL | macro n(a $nt_item b) {
1818
...
1919
LL | complex_nonterminal!(enum E {});
2020
| ------------------------------- in this macro invocation
21-
= note: captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens
21+
= note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
22+
= note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
23+
= help: try using `:tt` instead in the macro definition
2224
= note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
2325

2426
error: aborting due to previous error

0 commit comments

Comments
 (0)