@@ -8,8 +8,10 @@ use proc_macro2::{Ident, TokenStream};
8
8
use quote:: { format_ident, quote} ;
9
9
use syn:: {
10
10
parse:: { Parse , ParseStream } ,
11
+ parse_quote,
11
12
punctuated:: Punctuated ,
12
13
token:: Comma ,
14
+ visit:: Visit ,
13
15
Attribute , Data , DeriveInput , Expr , ExprLit , Field , Fields , Lit , Meta , Result , Variant ,
14
16
WherePredicate ,
15
17
} ;
@@ -36,12 +38,19 @@ pub fn derive_zeroize(input: proc_macro::TokenStream) -> proc_macro::TokenStream
36
38
fn derive_zeroize_impl ( input : DeriveInput ) -> TokenStream {
37
39
let attributes = ZeroizeAttrs :: parse ( & input) ;
38
40
41
+ let mut generics = input. generics . clone ( ) ;
42
+
39
43
let extra_bounds = match attributes. bound {
40
44
Some ( bounds) => bounds. 0 ,
41
- None => Default :: default ( ) ,
45
+ None => attributes
46
+ . auto_params
47
+ . iter ( )
48
+ . map ( |type_param| -> WherePredicate {
49
+ parse_quote ! { #type_param: Zeroize }
50
+ } )
51
+ . collect ( ) ,
42
52
} ;
43
53
44
- let mut generics = input. generics . clone ( ) ;
45
54
generics. make_where_clause ( ) . predicates . extend ( extra_bounds) ;
46
55
47
56
let ty_name = & input. ident ;
@@ -117,6 +126,8 @@ struct ZeroizeAttrs {
117
126
drop : bool ,
118
127
/// Custom bounds as defined by the user
119
128
bound : Option < Bounds > ,
129
+ /// Type parameters in use by fields
130
+ auto_params : Vec < Ident > ,
120
131
}
121
132
122
133
/// Parsing helper for custom bounds
@@ -128,10 +139,37 @@ impl Parse for Bounds {
128
139
}
129
140
}
130
141
142
+ struct BoundAccumulator < ' a > {
143
+ generics : & ' a syn:: Generics ,
144
+ params : Vec < Ident > ,
145
+ }
146
+
147
+ impl < ' ast > Visit < ' ast > for BoundAccumulator < ' ast > {
148
+ fn visit_path ( & mut self , path : & ' ast syn:: Path ) {
149
+ if path. segments . len ( ) != 1 {
150
+ return ;
151
+ }
152
+
153
+ if let Some ( segment) = path. segments . first ( ) {
154
+ for param in & self . generics . params {
155
+ if let syn:: GenericParam :: Type ( type_param) = param {
156
+ if type_param. ident == segment. ident && !self . params . contains ( & segment. ident ) {
157
+ self . params . push ( type_param. ident . clone ( ) ) ;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+
131
165
impl ZeroizeAttrs {
132
166
/// Parse attributes from the incoming AST
133
167
fn parse ( input : & DeriveInput ) -> Self {
134
168
let mut result = Self :: default ( ) ;
169
+ let mut bound_accumulator = BoundAccumulator {
170
+ generics : & input. generics ,
171
+ params : Vec :: new ( ) ,
172
+ } ;
135
173
136
174
for attr in & input. attrs {
137
175
result. parse_attr ( attr, None , None ) ;
@@ -147,6 +185,9 @@ impl ZeroizeAttrs {
147
185
for attr in & field. attrs {
148
186
result. parse_attr ( attr, Some ( variant) , Some ( field) ) ;
149
187
}
188
+ if !attr_skip ( & field. attrs ) {
189
+ bound_accumulator. visit_type ( & field. ty ) ;
190
+ }
150
191
}
151
192
}
152
193
}
@@ -155,11 +196,16 @@ impl ZeroizeAttrs {
155
196
for attr in & field. attrs {
156
197
result. parse_attr ( attr, None , Some ( field) ) ;
157
198
}
199
+ if !attr_skip ( & field. attrs ) {
200
+ bound_accumulator. visit_type ( & field. ty ) ;
201
+ }
158
202
}
159
203
}
160
204
syn:: Data :: Union ( union_) => panic ! ( "Unsupported untagged union {:?}" , union_) ,
161
205
}
162
206
207
+ result. auto_params = bound_accumulator. params ;
208
+
163
209
result
164
210
}
165
211
0 commit comments