@@ -42,7 +42,6 @@ pub fn derive_enum_flags(input: proc_macro::TokenStream)
4242#[ derive( Debug ) ]
4343enum EvaluationError {
4444 LiteralOutOfRange ( Span ) ,
45- UnsupportedOperation ( Span ) ,
4645}
4746
4847impl From < EvaluationError > for TokenStream {
@@ -53,42 +52,44 @@ impl From<EvaluationError> for TokenStream {
5352 LiteralOutOfRange ( span) => {
5453 error ! ( span => "Integer literal out of range" )
5554 }
56- UnsupportedOperation ( span) => {
57- error ! ( span => "This kind of discriminant expression is \
58- not supported.\n \
59- hint: Enable the \" not_literal\" feature to \
60- use a workaround.\n \
61- note: This is not enabled by default due to the \
62- high potential for confusing error messages \
63- (see documentation).")
64- }
6555 }
6656 }
6757}
6858
6959/// Try to evaluate the expression given.
70- fn fold_expr ( expr : & syn:: Expr ) -> Result < u64 , EvaluationError > {
60+ fn fold_expr ( expr : & syn:: Expr ) -> Result < Option < u64 > , EvaluationError > {
61+ /// Recurse, but bubble-up both kinds of errors.
62+ /// (I miss my monad transformers)
63+ macro_rules! fold_expr {
64+ ( $( $x: tt) * ) => {
65+ match fold_expr( $( $x) * ) ? {
66+ Some ( x) => x,
67+ None => return Ok ( None ) ,
68+ }
69+ }
70+ }
71+
7172 use syn:: Expr ;
7273 use crate :: EvaluationError :: * ;
7374 match expr {
7475 Expr :: Lit ( ref expr_lit) => {
7576 match expr_lit. lit {
7677 syn:: Lit :: Int ( ref lit_int) => {
77- lit_int. base10_parse ( )
78- . map_err ( |_| LiteralOutOfRange ( expr. span ( ) ) )
78+ Ok ( Some ( lit_int. base10_parse ( )
79+ . map_err ( |_| LiteralOutOfRange ( expr. span ( ) ) ) ? ) )
7980 }
80- _ => Err ( UnsupportedOperation ( expr . span ( ) ) )
81+ _ => Ok ( None ) ,
8182 }
8283 } ,
8384 Expr :: Binary ( ref expr_binary) => {
84- let l = fold_expr ( & expr_binary. left ) ? ;
85- let r = fold_expr ( & expr_binary. right ) ? ;
85+ let l = fold_expr ! ( & expr_binary. left) ;
86+ let r = fold_expr ! ( & expr_binary. right) ;
8687 match & expr_binary. op {
87- syn:: BinOp :: Shl ( _) => Ok ( l << r) ,
88- _ => Err ( UnsupportedOperation ( expr_binary . span ( ) ) )
88+ syn:: BinOp :: Shl ( _) => Ok ( Some ( l << r) ) ,
89+ _ => Ok ( None ) ,
8990 }
9091 }
91- _ => Err ( UnsupportedOperation ( expr . span ( ) ) )
92+ _ => Ok ( None ) ,
9293 }
9394}
9495
@@ -121,42 +122,38 @@ fn extract_repr(attrs: &[syn::Attribute])
121122 . transpose ( )
122123}
123124
124- /// Returns Ok with deferred checks (not_literal), or Err with error!
125+ /// Returns deferred checks
125126fn verify_flag_values < ' a > (
126- // starts with underscore to silence warnings when not_literal
127- // are disabled
128- _type_name : & Ident ,
127+ type_name : & Ident ,
129128 variants : impl Iterator < Item =& ' a syn:: Variant >
130129) -> Result < TokenStream , TokenStream > {
131- #[ cfg_attr( not( feature = "not_literal" ) , allow( unused_mut) ) ]
132130 let mut deferred_checks: Vec < TokenStream > = vec ! [ ] ;
133131 for variant in variants {
134132 let discr = variant. discriminant . as_ref ( )
135133 . ok_or_else ( || error ! ( variant. span( ) =>
136134 "Please add an explicit discriminant" ) ) ?;
137135 match fold_expr ( & discr. 1 ) {
138- Ok ( flag) => {
136+ Ok ( Some ( flag) ) => {
139137 if !flag. is_power_of_two ( ) {
140138 return Err ( error ! ( variant. discriminant. as_ref( )
141139 . unwrap( ) . 1 . span( ) =>
142140 "Flags must have exactly one set bit." ) ) ;
143141 }
144142 }
145- #[ cfg( feature = "not_literal" ) ]
146- Err ( EvaluationError :: UnsupportedOperation ( _) ) => {
143+ Ok ( None ) => {
147144 let variant_name = & variant. ident ;
148145 // TODO: Remove this madness when Debian ships a new compiler.
149146 let assertion_name = syn:: Ident :: new (
150147 & format ! ( "__enumflags_assertion_{}_{}" ,
151- _type_name , variant_name) ,
148+ type_name , variant_name) ,
152149 Span :: call_site ( ) ) ; // call_site because def_site is unstable
153150 // adapted from static-assertions-rs by nvzqz (MIT/Apache-2.0)
154151 deferred_checks. push ( quote_spanned ! ( variant. span( ) =>
155152 const #assertion_name: fn ( ) = || {
156153 :: enumflags2:: _internal:: assert_exactly_one_bit_set:: <[ ( ) ; (
157- ( #_type_name :: #variant_name as u64 ) . wrapping_sub( 1 ) &
158- ( #_type_name :: #variant_name as u64 ) == 0 &&
159- ( #_type_name :: #variant_name as u64 ) != 0
154+ ( #type_name :: #variant_name as u64 ) . wrapping_sub( 1 ) &
155+ ( #type_name :: #variant_name as u64 ) == 0 &&
156+ ( #type_name :: #variant_name as u64 ) != 0
160157 ) as usize ] >( ) ;
161158 } ;
162159 ) ) ;
0 commit comments