0

I'm using the bitflags crate. I want to automatically generate some other implementations for my types, so I tried to call the bitflags! macro from another macro. This worked fine until I wanted to be able to handle a visibility token.

I tried the following code.

Playground

use bitflags::bitflags;

macro_rules! my_bitflags {
    (
        $(#[$outer:meta])*
        $vis:vis struct $name:ident: $ty:ty {
            $(
                $(#[$inner:ident $($args:tt)*])*
                const $flag:ident = $value:expr;
            )+
        }
    ) => {
        bitflags! {
            $(#[$outer])*
            $vis struct $name: $ty {
                $(
                    $(#[$inner $($args)*])*
                    const $flag = $value;
                )+
            }
        }
        
        // other implementations on $name here
        // 
    }
}


my_bitflags! {
    pub struct Flags: u32 {
        const A = 0x1;
        const B = 0x2;
        const C = 0x4;
    }
}

I expected this to work but I get the following error

error: no rules expected the token `pub `

Is this an issue with the bitflags! macro? Or am I passing the visibility token incorrectly?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Ross MacArthur
  • 4,735
  • 1
  • 24
  • 36
  • 1
    I never used that crate, but seems like a [`yes`](https://docs.rs/bitflags/1.2.1/src/bitflags/lib.rs.html#336), this is the issue in bitflags crate. It for some reason matches explicitly, probably that's where it breaks? Maybe it would be worth making a pull request? Visibility token is optional and it wouldn't be a breaking change. The very bizarre part to me is that error explicitly has a space after `\`pub \``. – Yamirui Aug 17 '20 at 14:29
  • I'd say it is a bug in `bitflags`. It looks like it does not expect a `vis` but a combination of a literal `pub` and a few other tokens (`vis` is recent addition to the macro syntax). And by passing an explicitly parsed `vis` when it expects a plain token `pub` it gets confused and fails to compile. – rodrigo Aug 17 '20 at 14:47
  • Currently `bitflags` crate requires rustc 1.20, but `vis` in macros was added in 1.30. Maybe fixing the crate will bump the minimum required version? – rodrigo Aug 17 '20 at 14:57

1 Answers1

3

$vis in bitflags! is defined as a token tree (tt), not as visibility (vis). Visibility was only "recently" introduced to rustc and the bitflags! macro stays backward-compatible by not redefining $vis.

You need to change $vis:vis to $vis:tt in my_bitflags! so it can expand into bitflags!.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user2722968
  • 13,636
  • 2
  • 46
  • 67