@@ -8,55 +8,89 @@ extern crate proc_macro;
8
8
9
9
use proc_macro2:: TokenStream ;
10
10
use quote:: quote;
11
+ use syn:: { Attribute , Ident , Meta , NestedMeta } ;
11
12
use synstructure:: { decl_derive, BindStyle } ;
12
13
13
14
/// Name of zeroize-related attributes
14
15
const ZEROIZE_ATTR : & str = "zeroize" ;
15
16
16
17
/// Custom derive for `Zeroize`
17
18
fn derive_zeroize ( s : synstructure:: Structure ) -> TokenStream {
18
- let attributes = ZeroizeDeriveAttrs :: parse ( & s) ;
19
+ let attributes = DeriveAttrs :: parse ( & s) ;
19
20
20
21
match attributes. drop {
21
22
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) ,
24
24
}
25
25
}
26
26
decl_derive ! ( [ Zeroize , attributes( zeroize) ] => derive_zeroize) ;
27
27
28
28
/// Custom derive attributes for `Zeroize`
29
- struct ZeroizeDeriveAttrs {
29
+ struct DeriveAttrs {
30
30
/// Derive a `Drop` impl which calls zeroize on this type
31
31
drop : Option < bool > ,
32
32
}
33
33
34
- impl Default for ZeroizeDeriveAttrs {
34
+ impl Default for DeriveAttrs {
35
35
fn default ( ) -> Self {
36
36
Self { drop : None }
37
37
}
38
38
}
39
39
40
- impl ZeroizeDeriveAttrs {
40
+ impl DeriveAttrs {
41
41
/// Parse attributes from the incoming AST
42
42
fn parse ( s : & synstructure:: Structure ) -> Self {
43
43
let mut result = Self :: default ( ) ;
44
44
45
45
for v in s. variants ( ) . iter ( ) {
46
46
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) ;
55
48
}
56
49
}
57
50
58
51
result
59
52
}
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
+ }
60
94
}
61
95
62
96
/// Custom derive for `Zeroize` (without `Drop`)
0 commit comments