@@ -4,7 +4,7 @@ extern crate proc_macro;
44extern crate quote;
55
66use std:: convert:: TryFrom ;
7- use syn:: { Data , Ident , DeriveInput , DataEnum , spanned:: Spanned } ;
7+ use syn:: { Ident , Item , ItemEnum , spanned:: Spanned , parse_macro_input } ;
88use proc_macro2:: { TokenStream , Span } ;
99
1010struct Flag {
@@ -24,18 +24,11 @@ pub fn bitflags_internal(
2424 _attr : proc_macro:: TokenStream ,
2525 input : proc_macro:: TokenStream ,
2626) -> proc_macro:: TokenStream {
27- let ast: DeriveInput = syn:: parse ( input) . unwrap ( ) ;
28-
29- let output = match ast. data {
30- Data :: Enum ( ref data) => {
31- gen_enumflags ( & ast. ident , & ast, data)
32- }
33- Data :: Struct ( ref data) => {
34- Err ( syn:: Error :: new_spanned ( data. struct_token , "#[bitflags] requires an enum" ) )
35- }
36- Data :: Union ( ref data) => {
37- Err ( syn:: Error :: new_spanned ( data. union_token , "#[bitflags] requires an enum" ) )
38- }
27+ let ast = parse_macro_input ! ( input as Item ) ;
28+ let output = match ast {
29+ Item :: Enum ( ref item_enum) => gen_enumflags ( item_enum) ,
30+ _ => Err ( syn:: Error :: new_spanned ( & ast,
31+ "#[bitflags] requires an enum" ) ) ,
3932 } ;
4033
4134 output. unwrap_or_else ( |err| {
@@ -197,31 +190,39 @@ fn check_flag(
197190 }
198191}
199192
200- fn gen_enumflags ( ident : & Ident , item : & DeriveInput , data : & DataEnum )
193+ fn gen_enumflags ( ast : & ItemEnum )
201194 -> Result < TokenStream , syn:: Error >
202195{
196+ let ident = & ast. ident ;
197+
203198 let span = Span :: call_site ( ) ;
204199 // for quote! interpolation
205200 let variant_names =
206- data . variants . iter ( )
201+ ast . variants . iter ( )
207202 . map ( |v| & v. ident )
208203 . collect :: < Vec < _ > > ( ) ;
209- let repeated_name = vec ! [ & ident; data . variants. len( ) ] ;
204+ let repeated_name = vec ! [ & ident; ast . variants. len( ) ] ;
210205
211- let variants = collect_flags ( data . variants . iter ( ) ) ?;
206+ let variants = collect_flags ( ast . variants . iter ( ) ) ?;
212207 let deferred = variants. iter ( )
213208 . flat_map ( |variant| check_flag ( ident, variant) . transpose ( ) )
214209 . collect :: < Result < Vec < _ > , _ > > ( ) ?;
215210
216- let ty = extract_repr ( & item . attrs ) ?
211+ let ty = extract_repr ( & ast . attrs ) ?
217212 . ok_or_else ( || syn:: Error :: new_spanned ( & ident,
218213 "repr attribute missing. Add #[repr(u64)] or a similar attribute to specify the size of the bitfield." ) ) ?;
219- type_bits ( & ty) ?;
214+ let bits = type_bits ( & ty) ?;
215+
216+ if ( bits as usize ) < variants. len ( ) {
217+ return Err ( syn:: Error :: new_spanned ( & ty,
218+ format ! ( "Not enough bits for {} flags" , variants. len( ) ) ) ) ;
219+ }
220+
220221 let std_path = quote_spanned ! ( span => :: enumflags2:: _internal:: core) ;
221222
222223 Ok ( quote_spanned ! {
223224 span =>
224- #item
225+ #ast
225226 #( #deferred) *
226227 impl #std_path:: ops:: Not for #ident {
227228 type Output = :: enumflags2:: BitFlags <#ident>;
0 commit comments