mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
rust: pin-init: add MaybeZeroable
derive macro
This derive macro implements `Zeroable` for structs & unions precisely
if all fields also implement `Zeroable` and does nothing otherwise. The
plain `Zeroable` derive macro instead errors when it cannot derive
`Zeroable` safely. The `MaybeZeroable` derive macro is useful in cases
where manual checking is infeasible such as with the bindings crate.
Move the zeroable generics parsing into a standalone function in order
to avoid code duplication between the two derive macros.
Link: 1165cdad1a
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
This commit is contained in:
parent
a313d41a2b
commit
00fccd3ecc
4 changed files with 120 additions and 1 deletions
|
@ -47,3 +47,8 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
zeroable::derive(input.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(MaybeZeroable)]
|
||||
pub fn maybe_derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
zeroable::maybe_derive(input.into()).into()
|
||||
}
|
||||
|
|
|
@ -6,7 +6,14 @@ use proc_macro2 as proc_macro;
|
|||
use crate::helpers::{parse_generics, Generics};
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
||||
pub(crate) fn parse_zeroable_derive_input(
|
||||
input: TokenStream,
|
||||
) -> (
|
||||
Vec<TokenTree>,
|
||||
Vec<TokenTree>,
|
||||
Vec<TokenTree>,
|
||||
Option<TokenTree>,
|
||||
) {
|
||||
let (
|
||||
Generics {
|
||||
impl_generics,
|
||||
|
@ -64,6 +71,11 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
|||
if in_generic && !inserted {
|
||||
new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
|
||||
}
|
||||
(rest, new_impl_generics, ty_generics, last)
|
||||
}
|
||||
|
||||
pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
||||
let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
|
||||
quote! {
|
||||
::pin_init::__derive_zeroable!(
|
||||
parse_input:
|
||||
|
@ -74,3 +86,16 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_derive(input: TokenStream) -> TokenStream {
|
||||
let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
|
||||
quote! {
|
||||
::pin_init::__maybe_derive_zeroable!(
|
||||
parse_input:
|
||||
@sig(#(#rest)*),
|
||||
@impl_generics(#(#new_impl_generics)*),
|
||||
@ty_generics(#(#ty_generics)*),
|
||||
@body(#last),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,6 +413,36 @@ pub use ::pin_init_internal::pinned_drop;
|
|||
/// ```
|
||||
pub use ::pin_init_internal::Zeroable;
|
||||
|
||||
/// Derives the [`Zeroable`] trait for the given struct if all fields implement [`Zeroable`].
|
||||
///
|
||||
/// Contrary to the derive macro named [`macro@Zeroable`], this one silently fails when a field
|
||||
/// doesn't implement [`Zeroable`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use pin_init::MaybeZeroable;
|
||||
///
|
||||
/// // implmements `Zeroable`
|
||||
/// #[derive(MaybeZeroable)]
|
||||
/// pub struct DriverData {
|
||||
/// id: i64,
|
||||
/// buf_ptr: *mut u8,
|
||||
/// len: usize,
|
||||
/// }
|
||||
///
|
||||
/// // does not implmement `Zeroable`
|
||||
/// #[derive(MaybeZeroable)]
|
||||
/// pub struct DriverData2 {
|
||||
/// id: i64,
|
||||
/// buf_ptr: *mut u8,
|
||||
/// len: usize,
|
||||
/// // this field doesn't implement `Zeroable`
|
||||
/// other_data: &'static i32,
|
||||
/// }
|
||||
/// ```
|
||||
pub use ::pin_init_internal::MaybeZeroable;
|
||||
|
||||
/// Initialize and pin a type directly on the stack.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -1443,3 +1443,62 @@ macro_rules! __derive_zeroable {
|
|||
};
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __maybe_derive_zeroable {
|
||||
(parse_input:
|
||||
@sig(
|
||||
$(#[$($struct_attr:tt)*])*
|
||||
$vis:vis struct $name:ident
|
||||
$(where $($whr:tt)*)?
|
||||
),
|
||||
@impl_generics($($impl_generics:tt)*),
|
||||
@ty_generics($($ty_generics:tt)*),
|
||||
@body({
|
||||
$(
|
||||
$(#[$($field_attr:tt)*])*
|
||||
$field_vis:vis $field:ident : $field_ty:ty
|
||||
),* $(,)?
|
||||
}),
|
||||
) => {
|
||||
// SAFETY: Every field type implements `Zeroable` and padding bytes may be zero.
|
||||
#[automatically_derived]
|
||||
unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*>
|
||||
where
|
||||
$(
|
||||
// the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds`
|
||||
// feature <https://github.com/rust-lang/rust/issues/48214#issuecomment-2557829956>.
|
||||
$field_ty: for<'__dummy> $crate::Zeroable,
|
||||
)*
|
||||
$($($whr)*)?
|
||||
{}
|
||||
};
|
||||
(parse_input:
|
||||
@sig(
|
||||
$(#[$($struct_attr:tt)*])*
|
||||
$vis:vis union $name:ident
|
||||
$(where $($whr:tt)*)?
|
||||
),
|
||||
@impl_generics($($impl_generics:tt)*),
|
||||
@ty_generics($($ty_generics:tt)*),
|
||||
@body({
|
||||
$(
|
||||
$(#[$($field_attr:tt)*])*
|
||||
$field_vis:vis $field:ident : $field_ty:ty
|
||||
),* $(,)?
|
||||
}),
|
||||
) => {
|
||||
// SAFETY: Every field type implements `Zeroable` and padding bytes may be zero.
|
||||
#[automatically_derived]
|
||||
unsafe impl<$($impl_generics)*> $crate::Zeroable for $name<$($ty_generics)*>
|
||||
where
|
||||
$(
|
||||
// the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds`
|
||||
// feature <https://github.com/rust-lang/rust/issues/48214#issuecomment-2557829956>.
|
||||
$field_ty: for<'__dummy> $crate::Zeroable,
|
||||
)*
|
||||
$($($whr)*)?
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue