Skip to content

Commit 6c5c322

Browse files
BennoLossinhoshinolina
authored andcommitted
rust: add derive macro for Zeroable
Add a derive proc-macro for the `Zeroable` trait. The macro supports structs where every field implements the `Zeroable` trait. This way `unsafe` implementations can be avoided. Suggested-by: Asahi Lina <[email protected]> Signed-off-by: Benno Lossin <[email protected]>
1 parent 3c6391e commit 6c5c322

5 files changed

Lines changed: 81 additions & 1 deletion

File tree

rust/kernel/init/macros.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,3 +980,31 @@ macro_rules! __pin_data {
980980
}
981981
};
982982
}
983+
984+
#[doc(hidden)]
985+
#[macro_export]
986+
macro_rules! __derive_zeroable {
987+
(parse_input:
988+
@sig(
989+
$(#[$($struct_attr:tt)*])*
990+
$vis:vis struct $name:ident
991+
$(where $($whr:tt)*)?
992+
),
993+
@impl_generics($($impl_generics:tt)*),
994+
@ty_generics($($ty_generics:tt)*),
995+
@body({
996+
$(
997+
$(#[$($field_attr:tt)*])*
998+
$field:ident : $field_ty:ty
999+
),* $(,)?
1000+
}),
1001+
) => {
1002+
// SAFETY: every field type implements `Zeroable` and padding bytes may be zero.
1003+
#[automatically_derived]
1004+
unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*>
1005+
where
1006+
$($field_ty: $crate::Zeroable,)*
1007+
$($($whr)*)?
1008+
{}
1009+
};
1010+
}

rust/kernel/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use core::pin::Pin;
1818
pub use alloc::{boxed::Box, vec::Vec};
1919

2020
#[doc(no_inline)]
21-
pub use macros::{module, pin_data, pinned_drop, vtable};
21+
pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
2222

2323
pub use super::build_assert;
2424

rust/macros/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod pin_data;
1111
mod pinned_drop;
1212
mod versions;
1313
mod vtable;
14+
mod zeroable;
1415

1516
use proc_macro::TokenStream;
1617

@@ -253,3 +254,22 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
253254
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
254255
pinned_drop::pinned_drop(args, input)
255256
}
257+
258+
/// Derives the [`Zeroable`] trait for the given struct.
259+
///
260+
/// This can only be used for structs where every field implements the [`Zeroable`] trait.
261+
///
262+
/// # Examples
263+
///
264+
/// ```rust
265+
/// #[derive(Zeroable)]
266+
/// pub struct DriverData {
267+
/// id: i64,
268+
/// buf_ptr: *mut u8,
269+
/// len: usize,
270+
/// }
271+
/// ```
272+
#[proc_macro_derive(Zeroable)]
273+
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
274+
zeroable::derive(input)
275+
}

rust/macros/quote.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ macro_rules! quote_spanned {
124124
));
125125
quote_spanned!(@proc $v $span $($tt)*);
126126
};
127+
(@proc $v:ident $span:ident ; $($tt:tt)*) => {
128+
$v.push(::proc_macro::TokenTree::Punct(
129+
::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
130+
));
131+
quote_spanned!(@proc $v $span $($tt)*);
132+
};
127133
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
128134
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
129135
quote_spanned!(@proc $v $span $($tt)*);

rust/macros/zeroable.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use crate::{
2+
helpers::{parse_generics, Generics},
3+
quote,
4+
};
5+
use proc_macro::TokenStream;
6+
7+
pub(crate) fn derive(input: TokenStream) -> TokenStream {
8+
let (
9+
Generics {
10+
impl_generics,
11+
ty_generics,
12+
},
13+
mut rest,
14+
) = parse_generics(input);
15+
// This should be the body of the struct `{...}`.
16+
let last = rest.pop();
17+
quote! {
18+
::kernel::__derive_zeroable!(
19+
parse_input:
20+
@sig(#(#rest)*),
21+
@impl_generics(#(#impl_generics)*),
22+
@ty_generics(#(#ty_generics)*),
23+
@body(#last),
24+
);
25+
}
26+
}

0 commit comments

Comments
 (0)