diff options
| author | Benjamin Tissoires <bentiss@kernel.org> | 2025-09-30 16:31:10 +0200 | 
|---|---|---|
| committer | Benjamin Tissoires <bentiss@kernel.org> | 2025-09-30 16:31:10 +0200 | 
| commit | d325efac5938efa3c2a25df72a1bd1af16cd0ed8 (patch) | |
| tree | 6bb0db4f21bd6359bb32f3beeb63231477b09ef3 /rust/pin-init | |
| parent | bba920e6f803138587248079de47ad3464a396f6 (diff) | |
| parent | d1dd75c6500c74b91c5286fd3277710371d3e3ca (diff) | |
Merge branch 'for-6.18/core' into for-linus
- allow HID-BPF to rebind a driver to hid-multitouch (Benjamin
  Tissoires)
- Change hid_driver to use a const char* for .name (Rahul Rameshbabu)
Diffstat (limited to 'rust/pin-init')
| -rw-r--r-- | rust/pin-init/README.md | 2 | ||||
| -rw-r--r-- | rust/pin-init/examples/big_struct_in_place.rs | 28 | ||||
| -rw-r--r-- | rust/pin-init/examples/linked_list.rs | 10 | ||||
| -rw-r--r-- | rust/pin-init/examples/mutex.rs | 97 | ||||
| -rw-r--r-- | rust/pin-init/examples/pthread_mutex.rs | 4 | ||||
| -rw-r--r-- | rust/pin-init/examples/static_init.rs | 75 | ||||
| -rw-r--r-- | rust/pin-init/src/__internal.rs | 1 | ||||
| -rw-r--r-- | rust/pin-init/src/lib.rs | 120 | ||||
| -rw-r--r-- | rust/pin-init/src/macros.rs | 16 | 
9 files changed, 237 insertions, 116 deletions
| diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md index 2d0cda961d45..a4c01a8d78b2 100644 --- a/rust/pin-init/README.md +++ b/rust/pin-init/README.md @@ -125,7 +125,7 @@ impl DriverData {      fn new() -> impl PinInit<Self, Error> {          try_pin_init!(Self {              status <- CMutex::new(0), -            buffer: Box::init(pin_init::zeroed())?, +            buffer: Box::init(pin_init::init_zeroed())?,          }? Error)      }  } diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs index 30d44a334ffd..c05139927486 100644 --- a/rust/pin-init/examples/big_struct_in_place.rs +++ b/rust/pin-init/examples/big_struct_in_place.rs @@ -4,6 +4,7 @@ use pin_init::*;  // Struct with size over 1GiB  #[derive(Debug)] +#[allow(dead_code)]  pub struct BigStruct {      buf: [u8; 1024 * 1024 * 1024],      a: u64, @@ -20,20 +21,23 @@ pub struct ManagedBuf {  impl ManagedBuf {      pub fn new() -> impl Init<Self> { -        init!(ManagedBuf { buf <- zeroed() }) +        init!(ManagedBuf { buf <- init_zeroed() })      }  }  fn main() { -    // we want to initialize the struct in-place, otherwise we would get a stackoverflow -    let buf: Box<BigStruct> = Box::init(init!(BigStruct { -        buf <- zeroed(), -        a: 7, -        b: 186, -        c: 7789, -        d: 34, -        managed_buf <- ManagedBuf::new(), -    })) -    .unwrap(); -    println!("{}", core::mem::size_of_val(&*buf)); +    #[cfg(any(feature = "std", feature = "alloc"))] +    { +        // we want to initialize the struct in-place, otherwise we would get a stackoverflow +        let buf: Box<BigStruct> = Box::init(init!(BigStruct { +            buf <- init_zeroed(), +            a: 7, +            b: 186, +            c: 7789, +            d: 34, +            managed_buf <- ManagedBuf::new(), +        })) +        .unwrap(); +        println!("{}", core::mem::size_of_val(&*buf)); +    }  } diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs index 0bbc7b8d83a1..f9e117c7dfe0 100644 --- a/rust/pin-init/examples/linked_list.rs +++ b/rust/pin-init/examples/linked_list.rs @@ -14,8 +14,9 @@ use core::{  use pin_init::*; -#[expect(unused_attributes)] +#[allow(unused_attributes)]  mod error; +#[allow(unused_imports)]  use error::Error;  #[pin_data(PinnedDrop)] @@ -39,6 +40,7 @@ impl ListHead {      }      #[inline] +    #[allow(dead_code)]      pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {          try_pin_init!(&this in Self {              prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}), @@ -112,6 +114,7 @@ impl Link {      }      #[inline] +    #[allow(dead_code)]      fn prev(&self) -> &Link {          unsafe { &(*self.0.get().as_ptr()).prev }      } @@ -138,7 +141,12 @@ impl Link {  }  #[allow(dead_code)] +#[cfg(not(any(feature = "std", feature = "alloc")))] +fn main() {} + +#[allow(dead_code)]  #[cfg_attr(test, test)] +#[cfg(any(feature = "std", feature = "alloc"))]  fn main() -> Result<(), Error> {      let a = Box::pin_init(ListHead::new())?;      stack_pin_init!(let b = ListHead::insert_next(&a)); diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs index 3e3630780c96..9f295226cd64 100644 --- a/rust/pin-init/examples/mutex.rs +++ b/rust/pin-init/examples/mutex.rs @@ -12,14 +12,15 @@ use core::{      pin::Pin,      sync::atomic::{AtomicBool, Ordering},  }; +#[cfg(feature = "std")]  use std::{      sync::Arc, -    thread::{self, park, sleep, Builder, Thread}, +    thread::{self, sleep, Builder, Thread},      time::Duration,  };  use pin_init::*; -#[expect(unused_attributes)] +#[allow(unused_attributes)]  #[path = "./linked_list.rs"]  pub mod linked_list;  use linked_list::*; @@ -36,6 +37,7 @@ impl SpinLock {              .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)              .is_err()          { +            #[cfg(feature = "std")]              while self.inner.load(Ordering::Relaxed) {                  thread::yield_now();              } @@ -94,7 +96,8 @@ impl<T> CMutex<T> {              // println!("wait list length: {}", self.wait_list.size());              while self.locked.get() {                  drop(sguard); -                park(); +                #[cfg(feature = "std")] +                thread::park();                  sguard = self.spin_lock.acquire();              }              // This does have an effect, as the ListHead inside wait_entry implements Drop! @@ -131,8 +134,11 @@ impl<T> Drop for CMutexGuard<'_, T> {          let sguard = self.mtx.spin_lock.acquire();          self.mtx.locked.set(false);          if let Some(list_field) = self.mtx.wait_list.next() { -            let wait_entry = list_field.as_ptr().cast::<WaitEntry>(); -            unsafe { (*wait_entry).thread.unpark() }; +            let _wait_entry = list_field.as_ptr().cast::<WaitEntry>(); +            #[cfg(feature = "std")] +            unsafe { +                (*_wait_entry).thread.unpark() +            };          }          drop(sguard);      } @@ -159,52 +165,61 @@ impl<T> DerefMut for CMutexGuard<'_, T> {  struct WaitEntry {      #[pin]      wait_list: ListHead, +    #[cfg(feature = "std")]      thread: Thread,  }  impl WaitEntry {      #[inline]      fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ { -        pin_init!(Self { -            thread: thread::current(), -            wait_list <- ListHead::insert_prev(list), -        }) +        #[cfg(feature = "std")] +        { +            pin_init!(Self { +                thread: thread::current(), +                wait_list <- ListHead::insert_prev(list), +            }) +        } +        #[cfg(not(feature = "std"))] +        { +            pin_init!(Self { +                wait_list <- ListHead::insert_prev(list), +            }) +        }      }  } -#[cfg(not(any(feature = "std", feature = "alloc")))] -fn main() {} - -#[allow(dead_code)]  #[cfg_attr(test, test)] -#[cfg(any(feature = "std", feature = "alloc"))] +#[allow(dead_code)]  fn main() { -    let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); -    let mut handles = vec![]; -    let thread_count = 20; -    let workload = if cfg!(miri) { 100 } else { 1_000 }; -    for i in 0..thread_count { -        let mtx = mtx.clone(); -        handles.push( -            Builder::new() -                .name(format!("worker #{i}")) -                .spawn(move || { -                    for _ in 0..workload { -                        *mtx.lock() += 1; -                    } -                    println!("{i} halfway"); -                    sleep(Duration::from_millis((i as u64) * 10)); -                    for _ in 0..workload { -                        *mtx.lock() += 1; -                    } -                    println!("{i} finished"); -                }) -                .expect("should not fail"), -        ); -    } -    for h in handles { -        h.join().expect("thread panicked"); +    #[cfg(feature = "std")] +    { +        let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); +        let mut handles = vec![]; +        let thread_count = 20; +        let workload = if cfg!(miri) { 100 } else { 1_000 }; +        for i in 0..thread_count { +            let mtx = mtx.clone(); +            handles.push( +                Builder::new() +                    .name(format!("worker #{i}")) +                    .spawn(move || { +                        for _ in 0..workload { +                            *mtx.lock() += 1; +                        } +                        println!("{i} halfway"); +                        sleep(Duration::from_millis((i as u64) * 10)); +                        for _ in 0..workload { +                            *mtx.lock() += 1; +                        } +                        println!("{i} finished"); +                    }) +                    .expect("should not fail"), +            ); +        } +        for h in handles { +            h.join().expect("thread panicked"); +        } +        println!("{:?}", &*mtx.lock()); +        assert_eq!(*mtx.lock(), workload * thread_count * 2);      } -    println!("{:?}", &*mtx.lock()); -    assert_eq!(*mtx.lock(), workload * thread_count * 2);  } diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs index 5acc5108b954..49b004c8c137 100644 --- a/rust/pin-init/examples/pthread_mutex.rs +++ b/rust/pin-init/examples/pthread_mutex.rs @@ -44,6 +44,7 @@ mod pthread_mtx {      pub enum Error {          #[allow(dead_code)]          IO(std::io::Error), +        #[allow(dead_code)]          Alloc,      } @@ -61,6 +62,7 @@ mod pthread_mtx {      }      impl<T> PThreadMutex<T> { +        #[allow(dead_code)]          pub fn new(data: T) -> impl PinInit<Self, Error> {              fn init_raw() -> impl PinInit<UnsafeCell<libc::pthread_mutex_t>, Error> {                  let init = |slot: *mut UnsafeCell<libc::pthread_mutex_t>| { @@ -103,6 +105,7 @@ mod pthread_mtx {          }? Error)          } +        #[allow(dead_code)]          pub fn lock(&self) -> PThreadMutexGuard<'_, T> {              // SAFETY: raw is always initialized              unsafe { libc::pthread_mutex_lock(self.raw.get()) }; @@ -137,6 +140,7 @@ mod pthread_mtx {  }  #[cfg_attr(test, test)] +#[cfg_attr(all(test, miri), ignore)]  fn main() {      #[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))]      { diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs index 48531413ab94..0e165daa9798 100644 --- a/rust/pin-init/examples/static_init.rs +++ b/rust/pin-init/examples/static_init.rs @@ -3,6 +3,7 @@  #![allow(clippy::undocumented_unsafe_blocks)]  #![cfg_attr(feature = "alloc", feature(allocator_api))]  #![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))] +#![allow(unused_imports)]  use core::{      cell::{Cell, UnsafeCell}, @@ -12,12 +13,13 @@ use core::{      time::Duration,  };  use pin_init::*; +#[cfg(feature = "std")]  use std::{      sync::Arc,      thread::{sleep, Builder},  }; -#[expect(unused_attributes)] +#[allow(unused_attributes)]  mod mutex;  use mutex::*; @@ -82,42 +84,41 @@ unsafe impl PinInit<CMutex<usize>> for CountInit {  pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit); -#[cfg(not(any(feature = "std", feature = "alloc")))] -fn main() {} - -#[cfg(any(feature = "std", feature = "alloc"))]  fn main() { -    let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); -    let mut handles = vec![]; -    let thread_count = 20; -    let workload = 1_000; -    for i in 0..thread_count { -        let mtx = mtx.clone(); -        handles.push( -            Builder::new() -                .name(format!("worker #{i}")) -                .spawn(move || { -                    for _ in 0..workload { -                        *COUNT.lock() += 1; -                        std::thread::sleep(std::time::Duration::from_millis(10)); -                        *mtx.lock() += 1; -                        std::thread::sleep(std::time::Duration::from_millis(10)); -                        *COUNT.lock() += 1; -                    } -                    println!("{i} halfway"); -                    sleep(Duration::from_millis((i as u64) * 10)); -                    for _ in 0..workload { -                        std::thread::sleep(std::time::Duration::from_millis(10)); -                        *mtx.lock() += 1; -                    } -                    println!("{i} finished"); -                }) -                .expect("should not fail"), -        ); -    } -    for h in handles { -        h.join().expect("thread panicked"); +    #[cfg(feature = "std")] +    { +        let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); +        let mut handles = vec![]; +        let thread_count = 20; +        let workload = 1_000; +        for i in 0..thread_count { +            let mtx = mtx.clone(); +            handles.push( +                Builder::new() +                    .name(format!("worker #{i}")) +                    .spawn(move || { +                        for _ in 0..workload { +                            *COUNT.lock() += 1; +                            std::thread::sleep(std::time::Duration::from_millis(10)); +                            *mtx.lock() += 1; +                            std::thread::sleep(std::time::Duration::from_millis(10)); +                            *COUNT.lock() += 1; +                        } +                        println!("{i} halfway"); +                        sleep(Duration::from_millis((i as u64) * 10)); +                        for _ in 0..workload { +                            std::thread::sleep(std::time::Duration::from_millis(10)); +                            *mtx.lock() += 1; +                        } +                        println!("{i} finished"); +                    }) +                    .expect("should not fail"), +            ); +        } +        for h in handles { +            h.join().expect("thread panicked"); +        } +        println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); +        assert_eq!(*mtx.lock(), workload * thread_count * 2);      } -    println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); -    assert_eq!(*mtx.lock(), workload * thread_count * 2);  } diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs index 557b5948cddc..90f18e9a2912 100644 --- a/rust/pin-init/src/__internal.rs +++ b/rust/pin-init/src/__internal.rs @@ -188,6 +188,7 @@ impl<T> StackInit<T> {  }  #[test] +#[cfg(feature = "std")]  fn stack_init_reuse() {      use ::std::{borrow::ToOwned, println, string::String};      use core::pin::pin; diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index f4e034497cdd..62e013a5cc20 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -148,7 +148,7 @@  //!     fn new() -> impl PinInit<Self, Error> {  //!         try_pin_init!(Self {  //!             status <- CMutex::new(0), -//!             buffer: Box::init(pin_init::zeroed())?, +//!             buffer: Box::init(pin_init::init_zeroed())?,  //!         }? Error)  //!     }  //! } @@ -742,7 +742,7 @@ macro_rules! stack_try_pin_init {  /// - Fields that you want to initialize in-place have to use `<-` instead of `:`.  /// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]  ///   pointer named `this` inside of the initializer. -/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the +/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the  ///   struct, this initializes every field with 0 and then runs all initializers specified in the  ///   body. This can only be done if [`Zeroable`] is implemented for the struct.  /// @@ -769,7 +769,7 @@ macro_rules! stack_try_pin_init {  /// });  /// let init = pin_init!(Buf {  ///     buf: [1; 64], -///     ..Zeroable::zeroed() +///     ..Zeroable::init_zeroed()  /// });  /// ```  /// @@ -805,7 +805,7 @@ macro_rules! pin_init {  /// ```rust  /// # #![feature(allocator_api)]  /// # #[path = "../examples/error.rs"] mod error; use error::Error; -/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed}; +/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};  ///  /// #[pin_data]  /// struct BigBuf { @@ -817,7 +817,7 @@ macro_rules! pin_init {  /// impl BigBuf {  ///     fn new() -> impl PinInit<Self, Error> {  ///         try_pin_init!(Self { -///             big: Box::init(zeroed())?, +///             big: Box::init(init_zeroed())?,  ///             small: [0; 1024 * 1024],  ///             ptr: core::ptr::null_mut(),  ///         }? Error) @@ -866,7 +866,7 @@ macro_rules! try_pin_init {  /// # #[path = "../examples/error.rs"] mod error; use error::Error;  /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;  /// # use pin_init::InPlaceInit; -/// use pin_init::{init, Init, zeroed}; +/// use pin_init::{init, Init, init_zeroed};  ///  /// struct BigBuf {  ///     small: [u8; 1024 * 1024], @@ -875,7 +875,7 @@ macro_rules! try_pin_init {  /// impl BigBuf {  ///     fn new() -> impl Init<Self> {  ///         init!(Self { -///             small <- zeroed(), +///             small <- init_zeroed(),  ///         })  ///     }  /// } @@ -913,7 +913,7 @@ macro_rules! init {  /// # #![feature(allocator_api)]  /// # use core::alloc::AllocError;  /// # use pin_init::InPlaceInit; -/// use pin_init::{try_init, Init, zeroed}; +/// use pin_init::{try_init, Init, init_zeroed};  ///  /// struct BigBuf {  ///     big: Box<[u8; 1024 * 1024 * 1024]>, @@ -923,7 +923,7 @@ macro_rules! init {  /// impl BigBuf {  ///     fn new() -> impl Init<Self, AllocError> {  ///         try_init!(Self { -///             big: Box::init(zeroed())?, +///             big: Box::init(init_zeroed())?,  ///             small: [0; 1024 * 1024],  ///         }? AllocError)  ///     } @@ -953,7 +953,7 @@ macro_rules! try_init {  /// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is  /// structurally pinned.  /// -/// # Example +/// # Examples  ///  /// This will succeed:  /// ``` @@ -1170,7 +1170,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {      ///      /// ```rust      /// # #![expect(clippy::disallowed_names)] -    /// use pin_init::{init, zeroed, Init}; +    /// use pin_init::{init, init_zeroed, Init};      ///      /// struct Foo {      ///     buf: [u8; 1_000_000], @@ -1183,7 +1183,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {      /// }      ///      /// let foo = init!(Foo { -    ///     buf <- zeroed() +    ///     buf <- init_zeroed()      /// }).chain(|foo| {      ///     foo.setup();      ///     Ok(()) @@ -1495,7 +1495,45 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {  /// ```rust,ignore  /// let val: Self = unsafe { core::mem::zeroed() };  /// ``` -pub unsafe trait Zeroable {} +pub unsafe trait Zeroable { +    /// Create a new zeroed `Self`. +    /// +    /// The returned initializer will write `0x00` to every byte of the given `slot`. +    #[inline] +    fn init_zeroed() -> impl Init<Self> +    where +        Self: Sized, +    { +        init_zeroed() +    } + +    /// Create a `Self` consisting of all zeroes. +    /// +    /// Whenever a type implements [`Zeroable`], this function should be preferred over +    /// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`. +    /// +    /// # Examples +    /// +    /// ``` +    /// use pin_init::{Zeroable, zeroed}; +    /// +    /// #[derive(Zeroable)] +    /// struct Point { +    ///     x: u32, +    ///     y: u32, +    /// } +    /// +    /// let point: Point = zeroed(); +    /// assert_eq!(point.x, 0); +    /// assert_eq!(point.y, 0); +    /// ``` +    fn zeroed() -> Self +    where +        Self: Sized, +    { +        zeroed() +    } +}  /// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write  /// `None` to that location. @@ -1508,11 +1546,21 @@ pub unsafe trait ZeroableOption {}  // SAFETY: by the safety requirement of `ZeroableOption`, this is valid.  unsafe impl<T: ZeroableOption> Zeroable for Option<T> {} -/// Create a new zeroed T. +// SAFETY: `Option<&T>` is part of the option layout optimization guarantee: +// <https://doc.rust-lang.org/stable/std/option/index.html#representation>. +unsafe impl<T> ZeroableOption for &T {} +// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: +// <https://doc.rust-lang.org/stable/std/option/index.html#representation>. +unsafe impl<T> ZeroableOption for &mut T {} +// SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee: +// <https://doc.rust-lang.org/stable/std/option/index.html#representation>. +unsafe impl<T> ZeroableOption for NonNull<T> {} + +/// Create an initializer for a zeroed `T`.  ///  /// The returned initializer will write `0x00` to every byte of the given `slot`.  #[inline] -pub fn zeroed<T: Zeroable>() -> impl Init<T> { +pub fn init_zeroed<T: Zeroable>() -> impl Init<T> {      // SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`      // and because we write all zeroes, the memory is initialized.      unsafe { @@ -1523,6 +1571,31 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {      }  } +/// Create a `T` consisting of all zeroes. +/// +/// Whenever a type implements [`Zeroable`], this function should be preferred over +/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`. +/// +/// # Examples +/// +/// ``` +/// use pin_init::{Zeroable, zeroed}; +/// +/// #[derive(Zeroable)] +/// struct Point { +///     x: u32, +///     y: u32, +/// } +/// +/// let point: Point = zeroed(); +/// assert_eq!(point.x, 0); +/// assert_eq!(point.y, 0); +/// ``` +pub const fn zeroed<T: Zeroable>() -> T { +    // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`. +    unsafe { core::mem::zeroed() } +} +  macro_rules! impl_zeroable {      ($($({$($generics:tt)*})? $t:ty, )*) => {          // SAFETY: Safety comments written in the macro invocation. @@ -1560,7 +1633,6 @@ impl_zeroable! {      Option<NonZeroU128>, Option<NonZeroUsize>,      Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,      Option<NonZeroI128>, Option<NonZeroIsize>, -    {<T>} Option<NonNull<T>>,      // SAFETY: `null` pointer is valid.      // @@ -1590,6 +1662,22 @@ macro_rules! impl_tuple_zeroable {  impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); +macro_rules! impl_fn_zeroable_option { +    ([$($abi:literal),* $(,)?] $args:tt) => { +        $(impl_fn_zeroable_option!({extern $abi} $args);)* +        $(impl_fn_zeroable_option!({unsafe extern $abi} $args);)* +    }; +    ({$($prefix:tt)*} {$(,)?}) => {}; +    ({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => { +        // SAFETY: function pointers are part of the option layout optimization: +        // <https://doc.rust-lang.org/stable/std/option/index.html#representation>. +        unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {} +        impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,}); +    }; +} + +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 }); +  /// This trait allows creating an instance of `Self` which contains exactly one  /// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).  /// diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index 935d77745d1d..9ced630737b8 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -1030,7 +1030,7 @@ macro_rules! __pin_data {  ///  /// This macro has multiple internal call configurations, these are always the very first ident:  /// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. -/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled. +/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled.  /// - `init_slot`: recursively creates the code that initializes all fields in `slot`.  /// - `make_initializer`: recursively create the struct initializer that guarantees that every  ///   field has been initialized exactly once. @@ -1059,7 +1059,7 @@ macro_rules! __init_internal {              @data($data, $($use_data)?),              @has_data($has_data, $get_data),              @construct_closure($construct_closure), -            @zeroed(), // Nothing means default behavior. +            @init_zeroed(), // Nothing means default behavior.          )      };      ( @@ -1074,7 +1074,7 @@ macro_rules! __init_internal {          @has_data($has_data:ident, $get_data:ident),          // `pin_init_from_closure` or `init_from_closure`.          @construct_closure($construct_closure:ident), -        @munch_fields(..Zeroable::zeroed()), +        @munch_fields(..Zeroable::init_zeroed()),      ) => {          $crate::__init_internal!(with_update_parsed:              @this($($this)?), @@ -1084,7 +1084,7 @@ macro_rules! __init_internal {              @data($data, $($use_data)?),              @has_data($has_data, $get_data),              @construct_closure($construct_closure), -            @zeroed(()), // `()` means zero all fields not mentioned. +            @init_zeroed(()), // `()` means zero all fields not mentioned.          )      };      ( @@ -1124,7 +1124,7 @@ macro_rules! __init_internal {          @has_data($has_data:ident, $get_data:ident),          // `pin_init_from_closure` or `init_from_closure`.          @construct_closure($construct_closure:ident), -        @zeroed($($init_zeroed:expr)?), +        @init_zeroed($($init_zeroed:expr)?),      ) => {{          // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return          // type and shadow it later when we insert the arbitrary user code. That way there will be @@ -1196,7 +1196,7 @@ macro_rules! __init_internal {          @data($data:ident),          @slot($slot:ident),          @guards($($guards:ident,)*), -        @munch_fields($(..Zeroable::zeroed())? $(,)?), +        @munch_fields($(..Zeroable::init_zeroed())? $(,)?),      ) => {          // Endpoint of munching, no fields are left. If execution reaches this point, all fields          // have been initialized. Therefore we can now dismiss the guards by forgetting them. @@ -1300,11 +1300,11 @@ macro_rules! __init_internal {      (make_initializer:          @slot($slot:ident),          @type_name($t:path), -        @munch_fields(..Zeroable::zeroed() $(,)?), +        @munch_fields(..Zeroable::init_zeroed() $(,)?),          @acc($($acc:tt)*),      ) => {          // Endpoint, nothing more to munch, create the initializer. Since the users specified -        // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have +        // `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have          // not been overwritten are thus zero and initialized. We still check that all fields are          // actually accessible by using the struct update syntax ourselves.          // We are inside of a closure that is never executed and thus we can abuse `slot` to | 
