Skip to content

Commit 4b06984

Browse files
authored
zeroize_derive: Inject where clauses; skip unused (#882)
The where clauses I was previously injecting *were* load bearing, but they needed to be filtered for skipped fields. Fixes #878
1 parent 8c650ca commit 4b06984

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

zeroize/derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ proc-macro = true
1717
[dependencies]
1818
proc-macro2 = "1"
1919
quote = "1"
20-
syn = {version = "2", features = ["full", "extra-traits"]}
20+
syn = {version = "2", features = ["full", "extra-traits", "visit"]}
2121

2222
[package.metadata.docs.rs]
2323
rustdoc-args = ["--document-private-items"]

zeroize/derive/src/lib.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use proc_macro2::{Ident, TokenStream};
88
use quote::{format_ident, quote};
99
use 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
3638
fn 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+
131165
impl 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

zeroize/tests/zeroize_derive.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,12 @@ fn derive_zeroize_with_marker() {
351351

352352
trait Marker {}
353353
}
354+
355+
#[test]
356+
// Issue #878
357+
fn derive_zeroize_used_param() {
358+
#[derive(Zeroize)]
359+
struct Z<T> {
360+
used: T,
361+
}
362+
}

0 commit comments

Comments
 (0)