//! Shims for macros whose expansion cannot usefully be followed. //! //! The general rule in this project is that a macro whose expansion is not //! known is rejected. `bitflags!` is an argued exception, and the argument is //! this: expanding it does not help. `cargo rustc -Zunpretty=expanded` on a //! one-flag user produces 869 lines that still call into //! `bitflags::{Bits, Flag, Flags, iter, parser}` — which are themselves //! defined by 26 further `macro_rules!` across five files. The chain does not //! terminate in code we could lower. //! //! What the macro *means*, though, is small, documented and stable: a newtype //! over an integer with named constants and set operations. So it is lowered //! directly. That is not approximating a semantic we cannot represent — it is //! implementing one we can, and `tests/cases/034-bitflags.rs` checks the //! result against the real crate rather than against this comment. //! //! Verified against bitflags 2.13.2. Two behaviours are worth naming because //! they are not what a reimplementation would guess: `!x` is complemented and //! then masked to `all()`, and `from_bits` returns `None` for any bit outside //! `all()`. use syn::parse::{Parse, ParseStream}; use syn::{braced, Expr, Ident, Token, Type, Visibility}; /// One `pub struct Name: Repr { const A = ..; }` inside a `bitflags!`. pub struct FlagsDef { pub name: Ident, pub repr: Type, pub flags: Vec<(Ident, Expr)>, } /// The whole macro body, which may declare more than one type. pub struct BitflagsInput(pub Vec); impl Parse for BitflagsInput { fn parse(input: ParseStream) -> syn::Result { let mut out = Vec::new(); while !input.is_empty() { // Attributes on the struct (`#[derive(..)]`) carry no meaning we // need: the operations they derive are generated regardless. let _ = input.call(syn::Attribute::parse_outer)?; let _: Visibility = input.parse()?; input.parse::()?; let name: Ident = input.parse()?; input.parse::()?; let repr: Type = input.parse()?; let body; braced!(body in input); let mut flags = Vec::new(); while !body.is_empty() { let _ = body.call(syn::Attribute::parse_outer)?; body.parse::()?; let fname: Ident = body.parse()?; body.parse::()?; let value: Expr = body.parse()?; body.parse::()?; flags.push((fname, value)); } out.push(FlagsDef { name, repr, flags }); } Ok(BitflagsInput(out)) } }