Don't give "no rules expected the token" errors for macros that failed to parse
edb3d37
Opened by scottmcm at
Given the following code: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=293168337d6a7ce2c74a82461e536bad
macro_rules! foo {
($t:type) => {};
}
foo! { Option<bool> }
The current output is:
error: invalid fragment specifier `type`
--> src/lib.rs:2:6
|
2 | ($t:type) => {};
| ^^^^^^^
|
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
error: no rules expected the token `<`
--> src/lib.rs:5:14
|
1 | macro_rules! foo {
| ---------------- when calling this macro
...
5 | foo! { Option<bool> }
| ^ no rules expected this token in macro call
error: could not compile `playground` due to 2 previous errors
<!-- The following is not always necessary. -->
Ideally the output should look like:
error: invalid fragment specifier `type`
--> src/lib.rs:2:6
|
2 | ($t:type) => {};
| ^^^^^^^
|
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
error: could not compile `playground` due to previous error
Because telling me the call to the macro is invalid doesn't make much sense when that's impossible to fix without fixing the macro first.
Non-minimized mistake I made that inspired me to open this issue: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=aa7ce077f0b05e2af987f72539983e87
macro_rules! impl_for_optional_bool {
($($t:type,)+) => {$(
unsafe impl IsZero for $t {
fn is_zero(&self) -> bool {
// SAFETY: This is *not* a stable layout guarantee, but
// inside `core` we're allowed to rely on the current rustc
// behaviour that options of bools will be one byte with
// no padding, so long as they're nested less than 254 deep.
let raw: u8 = unsafe { core::mem::transmute(*self) };
raw == 0
}
}
)+};
}
impl_for_optional_bool! {
Option<bool>,
Option<Option<bool>>,
Option<Option<Option<bool>>>,
// Could go further, but not worth the trait lookup overhead
}
This case now has an even more confusing error message:
macro_rules! m { ($a:lit) => {}; } pub fn main() { m!(42); }will show a note claiming that
$awas declared as$a:ident:error: invalid fragment specifier `lit` --> <source>:2:6 | 2 | ($a:lit) => {}; | ^^^^^^ | = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility error: no rules expected the token `42` --> <source>:6:8 | 1 | macro_rules! m { | -------------- when calling this macro ... 6 | m!(42); | ^^ no rules expected this token in macro call | note: while trying to match meta-variable `$a:ident` --> <source>:2:6 | 2 | ($a:lit) => {}; | ^^^^^^ error: aborting due to 2 previous errors$ rustc --version --verbose rustc 1.83.0-nightly (3ae715c8c 2024-10-07) binary: rustc commit-hash: 3ae715c8c63f9aeac47cbf7d8d9dadb3fa32c638 commit-date: 2024-10-07 host: x86_64-unknown-linux-gnu release: 1.83.0-nightly LLVM version: 19.1.1narpfel at 2024-10-08 18:22:38