rust icon indicating copy to clipboard operation
rust copied to clipboard

Don't give "no rules expected the token" errors for macros that failed to parse

Open scottmcm opened this issue 3 years ago • 0 comments

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

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
}

scottmcm avatar Oct 02 '22 19:10 scottmcm