@@ -8,8 +8,10 @@ use proc_macro2::{Ident, TokenStream};
88use quote:: { format_ident, quote} ;
99use syn:: {
1010 parse:: { Parse , ParseStream } ,
11+ parse_quote,
1112 punctuated:: Punctuated ,
1213 token:: Comma ,
14+ visit:: Visit ,
1315 Attribute , Data , DeriveInput , Expr , ExprLit , Field , Fields , Lit , Meta , Result , Variant ,
1416 WherePredicate ,
1517} ;
@@ -36,12 +38,19 @@ pub fn derive_zeroize(input: proc_macro::TokenStream) -> proc_macro::TokenStream
3638fn derive_zeroize_impl ( input : DeriveInput ) -> TokenStream {
3739 let attributes = ZeroizeAttrs :: parse ( & input) ;
3840
41+ let mut generics = input. generics . clone ( ) ;
42+
3943 let extra_bounds = match attributes. bound {
4044 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 ( ) ,
4252 } ;
4353
44- let mut generics = input. generics . clone ( ) ;
4554 generics. make_where_clause ( ) . predicates . extend ( extra_bounds) ;
4655
4756 let ty_name = & input. ident ;
@@ -117,6 +126,8 @@ struct ZeroizeAttrs {
117126 drop : bool ,
118127 /// Custom bounds as defined by the user
119128 bound : Option < Bounds > ,
129+ /// Type parameters in use by fields
130+ auto_params : Vec < Ident > ,
120131}
121132
122133/// Parsing helper for custom bounds
@@ -128,10 +139,37 @@ impl Parse for Bounds {
128139 }
129140}
130141
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+
131165impl ZeroizeAttrs {
132166 /// Parse attributes from the incoming AST
133167 fn parse ( input : & DeriveInput ) -> Self {
134168 let mut result = Self :: default ( ) ;
169+ let mut bound_accumulator = BoundAccumulator {
170+ generics : & input. generics ,
171+ params : Vec :: new ( ) ,
172+ } ;
135173
136174 for attr in & input. attrs {
137175 result. parse_attr ( attr, None , None ) ;
@@ -147,6 +185,9 @@ impl ZeroizeAttrs {
147185 for attr in & field. attrs {
148186 result. parse_attr ( attr, Some ( variant) , Some ( field) ) ;
149187 }
188+ if !attr_skip ( & field. attrs ) {
189+ bound_accumulator. visit_type ( & field. ty ) ;
190+ }
150191 }
151192 }
152193 }
@@ -155,11 +196,16 @@ impl ZeroizeAttrs {
155196 for attr in & field. attrs {
156197 result. parse_attr ( attr, None , Some ( field) ) ;
157198 }
199+ if !attr_skip ( & field. attrs ) {
200+ bound_accumulator. visit_type ( & field. ty ) ;
201+ }
158202 }
159203 }
160204 syn:: Data :: Union ( union_) => panic ! ( "Unsupported untagged union {:?}" , union_) ,
161205 }
162206
207+ result. auto_params = bound_accumulator. params ;
208+
163209 result
164210 }
165211
0 commit comments