From 71c469f0420f95e679265d9b0cfa77b932fc8988 Mon Sep 17 00:00:00 2001 From: Mohamad Alsadhan Date: Tue, 10 Mar 2026 09:49:41 +0300 Subject: [PATCH 1/3] cleanup `Zeroable` and `ZeroableOptions` Place definitions and implementations (incl. macro invocations) of the `Zeroable` trait first in the relevant section of `src/lib.rs`, followed by the ZeroableOption trait and its implementations. Rename `impl_non_zero_int_zeroable_option` to `impl_zeroable_option` for consistency. This commit should not introduce any functional changes. Signed-off-by: Mohamad Alsadhan --- src/lib.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4f50994b..e34c9bdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1517,27 +1517,6 @@ pub unsafe trait Zeroable { } } -/// Marker trait for types that allow `Option` to be set to all zeroes in order to write -/// `None` to that location. -/// -/// # Safety -/// -/// The implementer needs to ensure that `unsafe impl Zeroable for Option {}` is sound. -pub unsafe trait ZeroableOption {} - -// SAFETY: by the safety requirement of `ZeroableOption`, this is valid. -unsafe impl Zeroable for Option {} - -// SAFETY: `Option<&T>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for &T {} -// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for &mut T {} -// SAFETY: `Option>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for NonNull {} - /// Create an initializer for a zeroed `T`. /// /// The returned initializer will write `0x00` to every byte of the given `slot`. @@ -1643,6 +1622,27 @@ macro_rules! impl_tuple_zeroable { impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); +/// Marker trait for types that allow `Option` to be set to all zeroes in order to write +/// `None` to that location. +/// +/// # Safety +/// +/// The implementer needs to ensure that `unsafe impl Zeroable for Option {}` is sound. +pub unsafe trait ZeroableOption {} + +// SAFETY: by the safety requirement of `ZeroableOption`, this is valid. +unsafe impl Zeroable for Option {} + +// SAFETY: `Option<&T>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for &T {} +// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for &mut T {} +// SAFETY: `Option>` is part of the option layout optimization guarantee: +// . +unsafe impl ZeroableOption for NonNull {} + macro_rules! impl_fn_zeroable_option { ([$($abi:literal),* $(,)?] $args:tt) => { $(impl_fn_zeroable_option!({extern $abi} $args);)* @@ -1668,14 +1668,14 @@ macro_rules! impl_fn_zeroable_option { impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U }); -macro_rules! impl_non_zero_int_zeroable_option { +macro_rules! impl_zeroable_option { ($($int:ty),* $(,)?) => { // SAFETY: Safety comment written in the macro invocation. $(unsafe impl ZeroableOption for $int {})* }; } -impl_non_zero_int_zeroable_option! { +impl_zeroable_option! { // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee: // ). NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize, From 6cc37c40910d7f99ed732f06e42e067576e3f4e2 Mon Sep 17 00:00:00 2001 From: Mohamad Alsadhan Date: Tue, 10 Mar 2026 10:42:38 +0300 Subject: [PATCH 2/3] extend `impl_zeroable_option` macro to handle generics Improve impl_zeroable_option macro to handle generic impls for types like `&T`, `&mut T`, `NonNull`, and others (for which `Option` is guaranteed to be zeroable) with similar approach to `impl_zeroable`. Also, update old declarations to use generics e.g. `NonZeroU8` to `NonZero`. Signed-off-by: Mohamad Alsadhan --- src/lib.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e34c9bdb..9b76cf55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1633,16 +1633,6 @@ pub unsafe trait ZeroableOption {} // SAFETY: by the safety requirement of `ZeroableOption`, this is valid. unsafe impl Zeroable for Option {} -// SAFETY: `Option<&T>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for &T {} -// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for &mut T {} -// SAFETY: `Option>` is part of the option layout optimization guarantee: -// . -unsafe impl ZeroableOption for NonNull {} - macro_rules! impl_fn_zeroable_option { ([$($abi:literal),* $(,)?] $args:tt) => { $(impl_fn_zeroable_option!({extern $abi} $args);)* @@ -1669,17 +1659,26 @@ macro_rules! impl_fn_zeroable_option { impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U }); macro_rules! impl_zeroable_option { - ($($int:ty),* $(,)?) => { - // SAFETY: Safety comment written in the macro invocation. - $(unsafe impl ZeroableOption for $int {})* + ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. + $(unsafe impl$($($generics)*)? ZeroableOption for $t {})* }; } impl_zeroable_option! { + // SAFETY: `Option<&T>` is part of the option layout optimization guarantee: + // . + {} &T, + // SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: + // . + {} &mut T, + // SAFETY: `Option>` is part of the option layout optimization guarantee: + // . + {} NonNull, // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee: // ). - NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize, - NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, + NonZero, NonZero, NonZero, NonZero, NonZero, NonZero, + NonZero, NonZero, NonZero, NonZero, NonZero, NonZero, } /// This trait allows creating an instance of `Self` which contains exactly one From 965d503f0575f8672b65ca020ea4e47ce04dc9f6 Mon Sep 17 00:00:00 2001 From: Mohamad Alsadhan Date: Tue, 10 Mar 2026 10:46:03 +0300 Subject: [PATCH 3/3] tests: add testing ZeroableOption with generics Minimal testing including: - add `tests/zeroing.rs` coverage that `zeroed::>()` is `None` for refs, `NonNull`, and nonzero ints. - add generic compile-check coverage for `T: ZeroableOption` (`&u8`, `&mut u8`, `NonNull`, `NonZeroU8`). - add UI compile-fail test `zeroable/option_string_not_zeroable.rs` to verify `Option` is not `Zeroable`. Not entirely sure how useful these tests are but it's on a different commit so feel free to not include them. Signed-off-by: Mohamad Alsadhan --- .../zeroable/option_string_not_zeroable.rs | 8 +++++ .../option_string_not_zeroable.stderr | 23 ++++++++++++++ tests/zeroing.rs | 31 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs create mode 100644 tests/ui/compile-fail/zeroable/option_string_not_zeroable.stderr diff --git a/tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs b/tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs new file mode 100644 index 00000000..76ee220e --- /dev/null +++ b/tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs @@ -0,0 +1,8 @@ +use pin_init::*; + +#[derive(Zeroable)] +struct Foo { + x: Option, +} + +fn main() {} diff --git a/tests/ui/compile-fail/zeroable/option_string_not_zeroable.stderr b/tests/ui/compile-fail/zeroable/option_string_not_zeroable.stderr new file mode 100644 index 00000000..ea3fb763 --- /dev/null +++ b/tests/ui/compile-fail/zeroable/option_string_not_zeroable.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `String: ZeroableOption` is not satisfied + --> tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs:5:8 + | +5 | x: Option, + | ^^^^^^^^^^^^^^ the trait `ZeroableOption` is not implemented for `String` + | + = help: the following other types implement trait `ZeroableOption`: + &T + &mut T + Box + NonNull + NonZero + NonZero + NonZero + NonZero + and $N others + = note: required for `Option` to implement `pin_init::Zeroable` +note: required by a bound in `assert_zeroable` + --> tests/ui/compile-fail/zeroable/option_string_not_zeroable.rs:3:10 + | +3 | #[derive(Zeroable)] + | ^^^^^^^^ required by this bound in `assert_zeroable` + = note: this error originates in the derive macro `Zeroable` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/zeroing.rs b/tests/zeroing.rs index 176f597d..b52394a5 100644 --- a/tests/zeroing.rs +++ b/tests/zeroing.rs @@ -1,5 +1,9 @@ use std::marker::PhantomPinned; +use core::{ + num::{NonZeroI32, NonZeroU8, NonZeroUsize}, + ptr::NonNull, +}; use pin_init::*; const MARKS: usize = 64; @@ -32,3 +36,30 @@ impl Foo { fn test() { let _ = Box::pin_init(Foo::new()).unwrap(); } + +#[test] +fn zeroed_option_runtime_values() { + let ref_opt: Option<&u8> = zeroed(); + let mut_ref_opt: Option<&mut u8> = zeroed(); + let non_null_opt: Option> = zeroed(); + let non_zero_unsigned: Option = zeroed(); + let non_zero_signed: Option = zeroed(); + + assert!(ref_opt.is_none()); + assert!(mut_ref_opt.is_none()); + assert!(non_null_opt.is_none()); + assert!(non_zero_unsigned.is_none()); + assert!(non_zero_signed.is_none()); +} + +fn assert_zeroable_option() { + let _: Option = zeroed(); +} + +#[test] +fn zeroed_option_generic_compile_check() { + assert_zeroable_option::<&u8>(); + assert_zeroable_option::<&mut u8>(); + assert_zeroable_option::>(); + assert_zeroable_option::(); +}