@@ -8,55 +8,89 @@ extern crate proc_macro;
88
99use proc_macro2:: TokenStream ;
1010use quote:: quote;
11+ use syn:: { Attribute , Ident , Meta , NestedMeta } ;
1112use synstructure:: { decl_derive, BindStyle } ;
1213
1314/// Name of zeroize-related attributes
1415const ZEROIZE_ATTR : & str = "zeroize" ;
1516
1617/// Custom derive for `Zeroize`
1718fn derive_zeroize ( s : synstructure:: Structure ) -> TokenStream {
18- let attributes = ZeroizeDeriveAttrs :: parse ( & s) ;
19+ let attributes = DeriveAttrs :: parse ( & s) ;
1920
2021 match attributes. drop {
2122 Some ( true ) => derive_zeroize_with_drop ( s) ,
22- Some ( false ) => derive_zeroize_without_drop ( s) ,
23- None => panic ! ( "must specify either zeroize(drop) or zeroize(no_drop) attribute" ) ,
23+ Some ( false ) | None => derive_zeroize_without_drop ( s) ,
2424 }
2525}
2626decl_derive ! ( [ Zeroize , attributes( zeroize) ] => derive_zeroize) ;
2727
2828/// Custom derive attributes for `Zeroize`
29- struct ZeroizeDeriveAttrs {
29+ struct DeriveAttrs {
3030 /// Derive a `Drop` impl which calls zeroize on this type
3131 drop : Option < bool > ,
3232}
3333
34- impl Default for ZeroizeDeriveAttrs {
34+ impl Default for DeriveAttrs {
3535 fn default ( ) -> Self {
3636 Self { drop : None }
3737 }
3838}
3939
40- impl ZeroizeDeriveAttrs {
40+ impl DeriveAttrs {
4141 /// Parse attributes from the incoming AST
4242 fn parse ( s : & synstructure:: Structure ) -> Self {
4343 let mut result = Self :: default ( ) ;
4444
4545 for v in s. variants ( ) . iter ( ) {
4646 for attr in v. ast ( ) . attrs . iter ( ) {
47- if attr. path . is_ident ( ZEROIZE_ATTR ) {
48- // TODO(tarcieri): hax, but probably good enough for now
49- match attr. tts . to_string ( ) . as_ref ( ) {
50- "( drop )" => result. drop = Some ( true ) ,
51- "( no_drop )" => result. drop = Some ( false ) ,
52- other => panic ! ( "unknown zeroize attribute: {}" , other) ,
53- }
54- }
47+ result. parse_attr ( attr) ;
5548 }
5649 }
5750
5851 result
5952 }
53+
54+ /// Parse attribute and handle `#[zeroize(...)]` attributes
55+ fn parse_attr ( & mut self , attr : & Attribute ) {
56+ let meta = attr
57+ . parse_meta ( )
58+ . unwrap_or_else ( |e| panic ! ( "error parsing attribute: {} ({})" , attr. tts, e) ) ;
59+
60+ if let Meta :: List ( list) = meta {
61+ if list. ident != ZEROIZE_ATTR {
62+ return ;
63+ }
64+
65+ for nested_meta in & list. nested {
66+ if let NestedMeta :: Meta ( Meta :: Word ( ident) ) = nested_meta {
67+ self . parse_attr_ident ( ident) ;
68+ } else {
69+ panic ! ( "malformed #[zeroize] attribute: {:?}" , nested_meta) ;
70+ }
71+ }
72+ }
73+ }
74+
75+ /// Parse a `#[zeroize(...)]` attribute containing a single ident (e.g. `drop`)
76+ fn parse_attr_ident ( & mut self , ident : & Ident ) {
77+ if ident == "drop" {
78+ self . set_drop_flag ( true ) ;
79+ } else if ident == "no_drop" {
80+ self . set_drop_flag ( false ) ;
81+ } else {
82+ panic ! ( "unknown #[zeroize] attribute type: {}" , ident) ;
83+ }
84+ }
85+
86+ /// Set the value of the `drop` flag
87+ fn set_drop_flag ( & mut self , value : bool ) {
88+ if self . drop . is_some ( ) {
89+ panic ! ( "duplicate #[zeroize] drop/no_drop flags" ) ;
90+ } else {
91+ self . drop = Some ( value) ;
92+ }
93+ }
6094}
6195
6296/// Custom derive for `Zeroize` (without `Drop`)
0 commit comments