From 690d82bf1da92f0a073df3728b76d4dbc99b5172 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 10 Jul 2026 17:20:33 +0100 Subject: rust: pin-init: remove redundant clippy expects in doc tests These lints are automatically suppressed inside doc tests. Previously this is needed because kernel builds doc tests with the default set of clippy flags; but now `clippy::disallowed_names` is globally allowed inside doc tests. Reviewed-by: Benno Lossin Link: https://patch.msgid.link/20260710-pin-init-sync-v1-3-8fa16cde87ae@garyguo.net Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index fd40c8f244a1..90e9d501d44a 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -70,7 +70,6 @@ //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. //! //! ```rust -//! # #![expect(clippy::disallowed_names)] //! # #![feature(allocator_api)] //! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; //! # use core::pin::Pin; @@ -94,7 +93,6 @@ //! (or just the stack) to actually initialize a `Foo`: //! //! ```rust -//! # #![expect(clippy::disallowed_names)] //! # #![feature(allocator_api)] //! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; //! # use core::{alloc::AllocError, pin::Pin}; @@ -456,7 +454,6 @@ pub use ::pin_init_internal::MaybeZeroable; /// # Examples /// /// ```rust -/// # #![expect(clippy::disallowed_names)] /// # #![feature(allocator_api)] /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; /// # use pin_init::*; @@ -508,7 +505,6 @@ macro_rules! stack_pin_init { /// # Examples /// /// ```rust -/// # #![expect(clippy::disallowed_names)] /// # #![feature(allocator_api)] /// # #[path = "../examples/error.rs"] mod error; use error::Error; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; @@ -535,7 +531,6 @@ macro_rules! stack_pin_init { /// ``` /// /// ```rust -/// # #![expect(clippy::disallowed_names)] /// # #![feature(allocator_api)] /// # #[path = "../examples/error.rs"] mod error; use error::Error; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; @@ -658,7 +653,6 @@ macro_rules! stack_try_pin_init { /// Users of `Foo` can now create it like this: /// /// ```rust -/// # #![expect(clippy::disallowed_names)] /// # use pin_init::*; /// # use core::pin::Pin; /// # #[pin_data] @@ -1031,7 +1025,6 @@ pub unsafe trait Init: PinInit { /// # Examples /// /// ```rust - /// # #![expect(clippy::disallowed_names)] /// use pin_init::{init, init_zeroed, Init}; /// /// struct Foo { -- cgit v1.2.3 From 7e4d9c946de525cac36bb693c42a147b8e9f03c5 Mon Sep 17 00:00:00 2001 From: Mirko Adzic Date: Fri, 10 Jul 2026 17:20:36 +0100 Subject: rust: pin-init: make `[pin_]init_array_from_fn` unwind safe The previous code only ran cleanup on the explicit error path. If the per- element initializer panicked partway through, the elements already written into the array would be leaked: their `Drop` impls would never run. This violates the pinning requirement. Fix the unwind safety issue by adding a guard type that drops element on both error and panic path. To avoid having to duplicate code between `pin_init_array_from_fn` and the non-pin variant, extract the code to a shared `ArrayInit` type; this type is internal and not visible via API. Reported-by: Gary Guo Closes: https://github.com/Rust-for-Linux/pin-init/issues/136 Signed-off-by: Mirko Adzic Link: https://patch.msgid.link/20260710-pin-init-sync-v1-6-8fa16cde87ae@garyguo.net [ Split guard type and the initializer type, move the guard type to be within __pinned_init. - Gary ] Co-developed-by: Gary Guo Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 122 +++++++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 42 deletions(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 90e9d501d44a..3fc4a674a487 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1186,6 +1186,82 @@ pub fn uninit() -> impl Init, E> { unsafe { init_from_closure(|_| Ok(())) } } +/// Array initializer from element initializer. +struct ArrayInit(F, __internal::PhantomInvariant); + +// SAFETY: On success, all `N` elements of the array have been initialized. On error or panic, the +// elements that have been initialized so far are dropped, thus leaving the array uninitialized and +// ready to deallocate. +unsafe impl PinInit<[T; N], E> for ArrayInit +where + F: FnMut(usize) -> I, + I: PinInit, +{ + unsafe fn __pinned_init(mut self, slot: *mut [T; N]) -> Result<(), E> { + /// # Invariants + /// + /// - `ptr[..num_init]` contains initialized elements of type `T` + /// - `ptr[num_init..N]` (where N is the size of the array) contains uninitialized memory + struct ArrayInitGuard { + /// A pointer to the first element of the array. + ptr: *mut T, + /// The number of initialized elements in the array. + num_init: usize, + } + + impl Drop for ArrayInitGuard { + #[inline] + fn drop(&mut self) { + // SAFETY: Per type invariant, `self.ptr[..self.num_init]` are initialized. + unsafe { + core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( + self.ptr, + self.num_init, + )) + }; + } + } + + // INVARIANT: nothing is initialized yet. + let mut guard = ArrayInitGuard { + ptr: slot.cast::(), + num_init: 0, + }; + + for i in 0..N { + // INVARIANT: Elements `self.ptr[..self.num_init]` have been initialized + // thus far. This holds true for every `self.num_init = i`. + guard.num_init = i; + + let init = (self.0)(i); + // SAFETY: + // - The subslot is derived from `slot` with a valid offset. + // - If `Err` is touched, the subslot is not touched further, the guard will drop + // previously initialized elements only. + // - `slot` is pinned so is the subslot. + unsafe { init.__pinned_init(&raw mut (*slot)[i]) }?; + } + + // Dismiss the drop guard now that all elements are initialized. + core::mem::forget(guard); + Ok(()) + } +} + +// SAFETY: Follows the `PinInit` impl. `__init` executes the same code as `__pinned_init`. +unsafe impl Init<[T; N], E> for ArrayInit +where + F: FnMut(usize) -> I, + I: Init, +{ + #[inline(always)] + unsafe fn __init(self, slot: *mut [T; N]) -> Result<(), E> { + // SAFETY: `I: Init` cancels out the pinning requirement on subslots. The other safety + // requirements follow that of `__init`. + unsafe { self.__pinned_init(slot) } + } +} + /// Initializes an array by initializing each element via the provided initializer. /// /// # Examples @@ -1197,31 +1273,12 @@ pub fn uninit() -> impl Init, E> { /// assert_eq!(array.len(), 1_000); /// ``` pub fn init_array_from_fn( - mut make_init: impl FnMut(usize) -> I, + make_init: impl FnMut(usize) -> I, ) -> impl Init<[T; N], E> where I: Init, { - let init = move |slot: *mut [T; N]| { - let slot = slot.cast::(); - for i in 0..N { - let init = make_init(i); - // SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`. - let ptr = unsafe { slot.add(i) }; - // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` - // requirements. - if let Err(e) = unsafe { init.__init(ptr) } { - // SAFETY: The loop has initialized the elements `slot[0..i]` and since we return - // `Err` below, `slot` will be considered uninitialized memory. - unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; - return Err(e); - } - } - Ok(()) - }; - // SAFETY: The initializer above initializes every element of the array. On failure it drops - // any initialized elements and returns `Err`. - unsafe { init_from_closure(init) } + ArrayInit(make_init, __internal::PhantomInvariant::new()) } /// Initializes an array by initializing each element via the provided initializer. @@ -1240,31 +1297,12 @@ where /// assert_eq!(array.len(), 1_000); /// ``` pub fn pin_init_array_from_fn( - mut make_init: impl FnMut(usize) -> I, + make_init: impl FnMut(usize) -> I, ) -> impl PinInit<[T; N], E> where I: PinInit, { - let init = move |slot: *mut [T; N]| { - let slot = slot.cast::(); - for i in 0..N { - let init = make_init(i); - // SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`. - let ptr = unsafe { slot.add(i) }; - // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` - // requirements. - if let Err(e) = unsafe { init.__pinned_init(ptr) } { - // SAFETY: The loop has initialized the elements `slot[0..i]` and since we return - // `Err` below, `slot` will be considered uninitialized memory. - unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; - return Err(e); - } - } - Ok(()) - }; - // SAFETY: The initializer above initializes every element of the array. On failure it drops - // any initialized elements and returns `Err`. - unsafe { pin_init_from_closure(init) } + ArrayInit(make_init, __internal::PhantomInvariant::new()) } /// Construct an initializer in a closure and run it. -- cgit v1.2.3 From 0c20f77a26b89bc911d31cd79f1abe1a7ae57f60 Mon Sep 17 00:00:00 2001 From: Mirko Adzic Date: Fri, 10 Jul 2026 17:20:37 +0100 Subject: rust: pin-init: make `[pin_]chain` unwind safe Add a drop guard before the call to the chained closure so that the value initialized by the first stage is dropped if the closure errors or panics; `mem::forget` the guard on success. The previous code only ran cleanup on the explicit error path, leaking the first-stage value if the chained closure panicked. Reported-by: Gary Guo Closes: https://github.com/Rust-for-Linux/pin-init/issues/136 Suggested-by: Gary Guo Signed-off-by: Mirko Adzic Link: https://patch.msgid.link/20260710-pin-init-sync-v1-7-8fa16cde87ae@garyguo.net [ Fix Clippy missing safety comment false positive when `slot` and `guard` creation are merged in a single line. - Gary ] Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 3fc4a674a487..ef9f20b11034 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -959,13 +959,11 @@ where { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { // SAFETY: All requirements fulfilled since this function is `__pinned_init`. - unsafe { self.0.__pinned_init(slot)? }; - // SAFETY: The above call initialized `slot` and we still have unique access. - let val = unsafe { &mut *slot }; - // SAFETY: `slot` is considered pinned. - let val = unsafe { Pin::new_unchecked(val) }; - // SAFETY: `slot` was initialized above. - (self.1)(val).inspect_err(|_| unsafe { core::ptr::drop_in_place(slot) }) + let slot = unsafe { __internal::Slot::<__internal::Pinned, _>::new(slot) }; + let mut guard = slot.init(self.0)?; + (self.1)(guard.let_binding())?; + core::mem::forget(guard); + Ok(()) } } @@ -1065,11 +1063,11 @@ where { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: All requirements fulfilled since this function is `__init`. - unsafe { self.0.__pinned_init(slot)? }; - // SAFETY: The above call initialized `slot` and we still have unique access. - (self.1)(unsafe { &mut *slot }).inspect_err(|_| - // SAFETY: `slot` was initialized above. - unsafe { core::ptr::drop_in_place(slot) }) + let slot = unsafe { __internal::Slot::<__internal::Unpinned, _>::new(slot) }; + let mut guard = slot.init(self.0)?; + (self.1)(guard.let_binding())?; + core::mem::forget(guard); + Ok(()) } } -- cgit v1.2.3 From 9e813b9abdfb626f0607b1ec94d201a2b8691f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Antinori?= Date: Thu, 23 Jul 2026 19:19:45 +0100 Subject: rust: pin-init: docs: link `Zeroable::zeroed` and `pin_init::zeroed` in documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify the comments in the `pin_init::zeroed` and `Zeroable::zeroed` functions to cross-reference each other and make developers aware of both options. This also adapts the example code in `Zeroable::zeroed` doc comments to use that function. Suggested-by: Miguel Ojeda Link: https://lore.kernel.org/rust-for-linux/CANiq72kdCAyRUmXFcqQfkHpk1miG8Gagsn0_5U8p4WpKxv9d_g@mail.gmail.com/ Signed-off-by: Nicolás Antinori [ Fix link. - Gary ] Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index ef9f20b11034..1f5005c110cd 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1539,10 +1539,13 @@ pub unsafe trait Zeroable { /// Whenever a type implements [`Zeroable`], this function should be preferred over /// [`core::mem::zeroed()`] or using `MaybeUninit::zeroed().assume_init()`. /// + /// As const traits are not yet stable, [`pin_init::zeroed()`] can be used instead + /// when initialization is required in a `const` context. + /// /// # Examples /// /// ``` - /// use pin_init::{Zeroable, zeroed}; + /// use pin_init::Zeroable; /// /// #[derive(Zeroable)] /// struct Point { @@ -1550,7 +1553,7 @@ pub unsafe trait Zeroable { /// y: u32, /// } /// - /// let point: Point = zeroed(); + /// let point: Point = Zeroable::zeroed(); /// assert_eq!(point.x, 0); /// assert_eq!(point.y, 0); /// ``` @@ -1582,6 +1585,9 @@ pub fn init_zeroed() -> impl Init { /// Whenever a type implements [`Zeroable`], this function should be preferred over /// [`core::mem::zeroed()`] or using `MaybeUninit::zeroed().assume_init()`. /// +/// While const traits remain unstable, this function serves as the `const` version of +/// [`Zeroable::zeroed()`]. +/// /// # Examples /// /// ``` -- cgit v1.2.3 From 6d0795b507fb1db2e6aefe533d949db3a4abf4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Antinori?= Date: Thu, 23 Jul 2026 19:19:46 +0100 Subject: rust: pin-init: mark `pin_init::zeroed` and `Zeroable::zeroed` as `#[inline]` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `pin_init::zeroed` function is a trivial wrapper around `unsafe { core::mem::zeroed() }`, whereas `Zeroable::zeroed` is a trivial wrapper around `pin_init::zeroed`. Mark them both as `#[inline]` to avoid generating unnecessary symbols for them. Signed-off-by: Nicolás Antinori Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 1f5005c110cd..f4ccb0e87200 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1557,6 +1557,7 @@ pub unsafe trait Zeroable { /// assert_eq!(point.x, 0); /// assert_eq!(point.y, 0); /// ``` + #[inline] fn zeroed() -> Self where Self: Sized, @@ -1603,6 +1604,7 @@ pub fn init_zeroed() -> impl Init { /// assert_eq!(point.x, 0); /// assert_eq!(point.y, 0); /// ``` +#[inline] pub const fn zeroed() -> T { // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`. unsafe { core::mem::zeroed() } -- cgit v1.2.3 From 91665820d9bf511e0c3fdf3edb464ba23130dafe Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 29 Jul 2026 16:38:44 +0100 Subject: rust: pin-init: merge `__pinned_init` and `__init` These functions have the same requirements and are also required to execute the same code. Prevent duplication by merging them to the single function and document the additional relaxation of `Init::__init` on both the merged function and the safety requirement of `Init`. The existing `__pinned_init` function is deprecated and kept for compatibility for existing users. For `cfg(kernel)`, it is soft-deprecated for now and will be removed when all users are migrated. Link: https://patch.msgid.link/20260729-merge-init-v2-2-26adf47109e7@garyguo.net Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 146 ++++++++++++++++++----------------------------- 1 file changed, 57 insertions(+), 89 deletions(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index f4ccb0e87200..fde53473763f 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -889,7 +889,7 @@ macro_rules! assert_pinned { /// When implementing this trait you will need to take great care. Also there are probably very few /// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible. /// -/// The [`PinInit::__pinned_init`] function: +/// The [`PinInit::__init`] function: /// - returns `Ok(())` if it initialized every field of `slot`, /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: /// - `slot` can be deallocated without UB occurring, @@ -909,6 +909,20 @@ macro_rules! assert_pinned { #[cfg_attr(not(kernel), doc = "[`Box`]: alloc::alloc::boxed::Box")] #[must_use = "An initializer must be used in order to create its value."] pub unsafe trait PinInit: Sized { + /// Alias of [`PinInit::__init`]. + /// + /// New code should use `__init` instead. + /// + /// # Safety + /// + /// Same as `__init`. + #[inline(always)] + #[cfg_attr(not(kernel), deprecated = "use `__init` instead")] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: Per safety requirement. + unsafe { self.__init(slot) } + } + /// Initializes `slot`. /// /// # Safety @@ -917,7 +931,8 @@ pub unsafe trait PinInit: Sized { /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. /// - `slot` will not move until it is dropped, i.e. it will be pinned. - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; + /// If `Self: Init`, this requirement is cancelled and it may be moved. + unsafe fn __init(self, slot: *mut T) -> Result<(), E>; /// First initializes the value using `self` then calls the function `f` with the initialized /// value. @@ -948,7 +963,7 @@ pub unsafe trait PinInit: Sized { /// An initializer returned by [`PinInit::pin_chain`]. pub struct ChainPinInit(I, F, __internal::PhantomInvariant<(E, T)>); -// SAFETY: The `__pinned_init` function is implemented such that it +// SAFETY: The `__init` function is implemented such that it // - returns `Ok(())` on successful initialization, // - returns `Err(err)` on error and in this case `slot` will be dropped. // - considers `slot` pinned. @@ -957,8 +972,8 @@ where I: PinInit, F: FnOnce(Pin<&mut T>) -> Result<(), E>, { - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: All requirements fulfilled since this function is `__pinned_init`. + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: All requirements fulfilled since this function is `__init`. let slot = unsafe { __internal::Slot::<__internal::Pinned, _>::new(slot) }; let mut guard = slot.init(self.0)?; (self.1)(guard.let_binding())?; @@ -980,19 +995,8 @@ where /// When implementing this trait you will need to take great care. Also there are probably very few /// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible. /// -/// The [`Init::__init`] function: -/// - returns `Ok(())` if it initialized every field of `slot`, -/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: -/// - `slot` can be deallocated without UB occurring, -/// - `slot` does not need to be dropped, -/// - `slot` is not partially initialized. -/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. -/// -/// The `__pinned_init` function from the supertrait [`PinInit`] needs to execute the exact same -/// code as `__init`. -/// -/// Contrary to its supertype [`PinInit`] the caller is allowed to -/// move the pointee after initialization. +/// The [`PinInit::__init`] function must work without the pinning requirement; the caller is +/// allowed to move the pointee after initialization. /// #[cfg_attr( kernel, @@ -1006,15 +1010,6 @@ where #[cfg_attr(not(kernel), doc = "[`Box`]: alloc::alloc::boxed::Box")] #[must_use = "An initializer must be used in order to create its value."] pub unsafe trait Init: PinInit { - /// Initializes `slot`. - /// - /// # Safety - /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to - /// deallocate. - unsafe fn __init(self, slot: *mut T) -> Result<(), E>; - /// First initializes the value using `self` then calls the function `f` with the initialized /// value. /// @@ -1053,10 +1048,18 @@ pub unsafe trait Init: PinInit { /// An initializer returned by [`Init::chain`]. pub struct ChainInit(I, F, __internal::PhantomInvariant<(E, T)>); +// SAFETY: The `__init` function does not rely on the pinning requirement. +unsafe impl Init for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ +} + // SAFETY: The `__init` function is implemented such that it // - returns `Ok(())` on successful initialization, // - returns `Err(err)` on error and in this case `slot` will be dropped. -unsafe impl Init for ChainInit +unsafe impl PinInit for ChainInit where I: Init, F: FnOnce(&mut T) -> Result<(), E>, @@ -1071,44 +1074,28 @@ where } } -// SAFETY: `__pinned_init` behaves exactly the same as `__init`. -unsafe impl PinInit for ChainInit -where - I: Init, - F: FnOnce(&mut T) -> Result<(), E>, -{ - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. - unsafe { self.__init(slot) } - } -} - /// Implement `PinInit` and `Init` for closures. /// /// It is unsafe to create this type, since the closure needs to fulfill the same safety -/// requirement as the `__pinned_init`/`__init` functions. +/// requirement as the `__init` functions. struct InitClosure(F, __internal::PhantomInvariant); -// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the -// `__init` invariants. -unsafe impl Init for InitClosure -where - F: FnOnce(*mut T) -> Result<(), E>, +// SAFETY: When constructing via `init_from_closure`, the `__init` function does not rely on the +// pinning requirement. When constructing via `pin_init_from_closure`, the opaque type prevents this +// implementation from being visible. +unsafe impl Init for InitClosure where + F: FnOnce(*mut T) -> Result<(), E> { - #[inline] - unsafe fn __init(self, slot: *mut T) -> Result<(), E> { - (self.0)(slot) - } } // SAFETY: While constructing the `InitClosure`, the user promised that it upholds the -// `__pinned_init` invariants. +// `__init` invariants. unsafe impl PinInit for InitClosure where F: FnOnce(*mut T) -> Result<(), E>, { #[inline] - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { (self.0)(slot) } } @@ -1160,7 +1147,7 @@ pub const unsafe fn init_from_closure( pub const unsafe fn cast_pin_init(init: impl PinInit) -> impl PinInit { // SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety // requirements. - unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::())) } + unsafe { pin_init_from_closure(|ptr: *mut U| init.__init(ptr.cast::())) } } /// Changes the to be initialized type. @@ -1195,7 +1182,7 @@ where F: FnMut(usize) -> I, I: PinInit, { - unsafe fn __pinned_init(mut self, slot: *mut [T; N]) -> Result<(), E> { + unsafe fn __init(mut self, slot: *mut [T; N]) -> Result<(), E> { /// # Invariants /// /// - `ptr[..num_init]` contains initialized elements of type `T` @@ -1237,7 +1224,7 @@ where // - If `Err` is touched, the subslot is not touched further, the guard will drop // previously initialized elements only. // - `slot` is pinned so is the subslot. - unsafe { init.__pinned_init(&raw mut (*slot)[i]) }?; + unsafe { init.__init(&raw mut (*slot)[i]) }?; } // Dismiss the drop guard now that all elements are initialized. @@ -1246,18 +1233,13 @@ where } } -// SAFETY: Follows the `PinInit` impl. `__init` executes the same code as `__pinned_init`. +// SAFETY: `I: Init` cancels out the pinning requirement on subslots, which is the only place in the +// `__init` function that relies on `slot` being pinned. unsafe impl Init<[T; N], E> for ArrayInit where F: FnMut(usize) -> I, I: Init, { - #[inline(always)] - unsafe fn __init(self, slot: *mut [T; N]) -> Result<(), E> { - // SAFETY: `I: Init` cancels out the pinning requirement on subslots. The other safety - // requirements follow that of `__init`. - unsafe { self.__pinned_init(slot) } - } } /// Initializes an array by initializing each element via the provided initializer. @@ -1336,13 +1318,13 @@ where { // SAFETY: // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized, - // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__pinned_init`. - // - The safety requirements of `init.__pinned_init` are fulfilled, since it's being called - // from an initializer. + // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__init`. + // - The safety requirements of `init.__init` are fulfilled, since it's being called from an + // initializer. unsafe { pin_init_from_closure(move |slot: *mut T| -> Result<(), E> { let init = make_init()?; - init.__pinned_init(slot) + init.__init(slot) }) } } @@ -1390,41 +1372,27 @@ where } } -// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. -unsafe impl Init for T { - unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { - // SAFETY: `slot` is valid for writes by the safety requirements of this function. - unsafe { slot.write(self) }; - Ok(()) - } -} +// SAFETY: The `__init` function does not rely on slot being pinned after it returns. +unsafe impl Init for T {} -// SAFETY: the `__pinned_init` function always returns `Ok(())` and initializes every field of +// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of // `slot`. Additionally, all pinning invariants of `T` are upheld. unsafe impl PinInit for T { - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> { + unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; Ok(()) } } -// SAFETY: when the `__init` function returns with -// - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. -// - `Err(err)`, slot was not written to. -unsafe impl Init for Result { - unsafe fn __init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `slot` is valid for writes by the safety requirements of this function. - unsafe { slot.write(self?) }; - Ok(()) - } -} +// SAFETY: The `__init` function does not rely on slot being pinned after it returns. +unsafe impl Init for Result {} -// SAFETY: when the `__pinned_init` function returns with +// SAFETY: when the `__init` function returns with // - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. // - `Err(err)`, slot was not written to. unsafe impl PinInit for Result { - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self?) }; Ok(()) @@ -1467,7 +1435,7 @@ impl InPlaceWrite for &'static mut MaybeUninit { // // The `'static` borrow guarantees the data will not be // moved/invalidated until it gets dropped (which is never). - unsafe { init.__pinned_init(slot)? }; + unsafe { init.__init(slot)? }; // SAFETY: The above call initialized the memory. Ok(Pin::static_mut(unsafe { self.assume_init_mut() })) -- cgit v1.2.3 From d5492db2bf30b7e617e41d4fe3dba22475a1a354 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 29 Jul 2026 16:38:45 +0100 Subject: rust: pin-init: add `raw_init` and `raw_try_init` and recommend over `__init` The `__init` method is not designed to be a public API (existence of "__" is a hint for this); but currently there is no other API that allows raw initialization on pointers. Add `raw_init` and `raw_try_init` and recommend people to use this instead if raw pointer initialization is needed. Link: https://patch.msgid.link/20260729-merge-init-v2-3-26adf47109e7@garyguo.net [ Renamed from `ptr_[try_]init` to `raw_[try_]init`. - Gary ] Reviewed-by: Benno Lossin Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index fde53473763f..97eaef6f2958 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -917,7 +917,7 @@ pub unsafe trait PinInit: Sized { /// /// Same as `__init`. #[inline(always)] - #[cfg_attr(not(kernel), deprecated = "use `__init` instead")] + #[cfg_attr(not(kernel), deprecated = "use `raw_try_init` instead")] unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { // SAFETY: Per safety requirement. unsafe { self.__init(slot) } @@ -925,6 +925,8 @@ pub unsafe trait PinInit: Sized { /// Initializes `slot`. /// + /// It is not recommended to call this directly. Use [`raw_init`] or [`raw_try_init`]. + /// /// # Safety /// /// - `slot` is a valid pointer to uninitialized memory. @@ -960,6 +962,34 @@ pub unsafe trait PinInit: Sized { } } +/// Initializes `slot` with an initializer. +/// +/// # Safety +/// +/// - `slot` is a valid pointer to uninitialized memory. +/// - `slot` will not move until it is dropped, i.e. it will be pinned. +/// If `init` implements `Init`, this requirement is cancelled and it may be moved. +#[inline(always)] +pub unsafe fn raw_init(slot: *mut T, init: impl PinInit) { + // SAFETY: Per safety requirement. + unsafe { init.__init(slot).unwrap_or_else(|e| match e {}) } +} + +/// Fallibly initializes `slot` with an initializer. +/// +/// # Safety +/// +/// - `slot` is a valid pointer to uninitialized memory. +/// - the caller does not touch `slot` when `Err` is returned, they are only permitted to +/// deallocate. +/// - `slot` will not move until it is dropped, i.e. it will be pinned. +/// If `init` implements `Init`, this requirement is cancelled and it may be moved. +#[inline(always)] +pub unsafe fn raw_try_init(slot: *mut T, init: impl PinInit) -> Result<(), E> { + // SAFETY: Per safety requirement. + unsafe { init.__init(slot) } +} + /// An initializer returned by [`PinInit::pin_chain`]. pub struct ChainPinInit(I, F, __internal::PhantomInvariant<(E, T)>); -- cgit v1.2.3 From 1f7fa1374d3bb455944128fe5c30c19f8d3501c7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 29 Jul 2026 16:38:47 +0100 Subject: rust: pin-init: remove `__pinned_init` method for `cfg(kernel)` Remove `__pinned_init` for kernel configuration, with all users gone. Still perserve it temporarily as deprecated so other users have time to move off it. Link: https://patch.msgid.link/20260729-merge-init-v2-5-26adf47109e7@garyguo.net Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 97eaef6f2958..6e9eb90db52c 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -917,7 +917,8 @@ pub unsafe trait PinInit: Sized { /// /// Same as `__init`. #[inline(always)] - #[cfg_attr(not(kernel), deprecated = "use `raw_try_init` instead")] + #[cfg(not(kernel))] + #[deprecated = "use `raw_try_init` instead"] unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { // SAFETY: Per safety requirement. unsafe { self.__init(slot) } -- cgit v1.2.3 From 1e26aea0355ad2afa1ccbc62885c01f5bcfc58ca Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 3 Aug 2026 14:02:01 +0100 Subject: rust: pin-init: add `#[inline]` to small functions Currently `pin-init` crate is missing many inline annotations. They are all generic so still get inlined in normal builds, but are not inlined in `-C opt-level=s` build. Mark these functions as `#[inline]` so they are considered for inlining regardless. Signed-off-by: Gary Guo --- rust/pin-init/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'rust/pin-init/src/lib.rs') diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 6e9eb90db52c..7600cdbbbf98 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -955,6 +955,7 @@ pub unsafe trait PinInit: Sized { /// Ok(()) /// }); /// ``` + #[inline] fn pin_chain(self, f: F) -> ChainPinInit where F: FnOnce(Pin<&mut T>) -> Result<(), E>, @@ -1003,6 +1004,7 @@ where I: PinInit, F: FnOnce(Pin<&mut T>) -> Result<(), E>, { + #[inline] unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: All requirements fulfilled since this function is `__init`. let slot = unsafe { __internal::Slot::<__internal::Pinned, _>::new(slot) }; @@ -1068,6 +1070,7 @@ pub unsafe trait Init: PinInit { /// Ok(()) /// }); /// ``` + #[inline] fn chain(self, f: F) -> ChainInit where F: FnOnce(&mut T) -> Result<(), E>, @@ -1095,6 +1098,7 @@ where I: Init, F: FnOnce(&mut T) -> Result<(), E>, { + #[inline] unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: All requirements fulfilled since this function is `__init`. let slot = unsafe { __internal::Slot::<__internal::Unpinned, _>::new(slot) }; @@ -1175,6 +1179,7 @@ pub const unsafe fn init_from_closure( /// /// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a /// pointer must result in a valid `U`. +#[inline] pub const unsafe fn cast_pin_init(init: impl PinInit) -> impl PinInit { // SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety // requirements. @@ -1187,6 +1192,7 @@ pub const unsafe fn cast_pin_init(init: impl PinInit) -> impl Pin /// /// - `*mut U` must be castable to `*mut T` and any value of type `T` written through such a /// pointer must result in a valid `U`. +#[inline] pub const unsafe fn cast_init(init: impl Init) -> impl Init { // SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety // requirements. @@ -1283,6 +1289,7 @@ where /// let array: Box<[usize; 1_000]> = Box::init(init_array_from_fn(|i| i)).unwrap(); /// assert_eq!(array.len(), 1_000); /// ``` +#[inline] pub fn init_array_from_fn( make_init: impl FnMut(usize) -> I, ) -> impl Init<[T; N], E> @@ -1307,6 +1314,7 @@ where /// Arc::pin_init(pin_init_array_from_fn(|i| CMutex::new(i))).unwrap(); /// assert_eq!(array.len(), 1_000); /// ``` +#[inline] pub fn pin_init_array_from_fn( make_init: impl FnMut(usize) -> I, ) -> impl PinInit<[T; N], E> @@ -1342,6 +1350,7 @@ where /// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the /// initializer itself will fail with that error. If it returned `Ok`, then it will run the /// initializer returned by the [`pin_init!`] invocation. +#[inline] pub fn pin_init_scope(make_init: F) -> impl PinInit where F: FnOnce() -> Result, @@ -1385,6 +1394,7 @@ where /// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the /// initializer itself will fail with that error. If it returned `Ok`, then it will run the /// initializer returned by the [`init!`] invocation. +#[inline] pub fn init_scope(make_init: F) -> impl Init where F: FnOnce() -> Result, @@ -1409,6 +1419,7 @@ unsafe impl Init for T {} // SAFETY: the `__init` function always returns `Ok(())` and initializes every field of // `slot`. Additionally, all pinning invariants of `T` are upheld. unsafe impl PinInit for T { + #[inline] unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self) }; @@ -1423,6 +1434,7 @@ unsafe impl Init for Result {} // - `Ok(())`, `slot` was initialized and all pinned invariants of `T` are upheld. // - `Err(err)`, slot was not written to. unsafe impl PinInit for Result { + #[inline] unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: `slot` is valid for writes by the safety requirements of this function. unsafe { slot.write(self?) }; @@ -1449,6 +1461,7 @@ pub trait InPlaceWrite { impl InPlaceWrite for &'static mut MaybeUninit { type Initialized = &'static mut T; + #[inline] fn write_init(self, init: impl Init) -> Result { let slot = self.as_mut_ptr(); @@ -1459,6 +1472,7 @@ impl InPlaceWrite for &'static mut MaybeUninit { unsafe { Ok(self.assume_init_mut()) } } + #[inline] fn write_pin_init(self, init: impl PinInit) -> Result, E> { let slot = self.as_mut_ptr(); @@ -1764,6 +1778,7 @@ pub trait Wrapper { } impl Wrapper for UnsafeCell { + #[inline] fn pin_init(value_init: impl PinInit) -> impl PinInit { // SAFETY: `UnsafeCell` has a compatible layout to `T`. unsafe { cast_pin_init(value_init) } @@ -1771,6 +1786,7 @@ impl Wrapper for UnsafeCell { } impl Wrapper for MaybeUninit { + #[inline] fn pin_init(value_init: impl PinInit) -> impl PinInit { // SAFETY: `MaybeUninit` has a compatible layout to `T`. unsafe { cast_pin_init(value_init) } @@ -1779,6 +1795,7 @@ impl Wrapper for MaybeUninit { #[cfg(all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED))] impl Wrapper for core::pin::UnsafePinned { + #[inline] fn pin_init(init: impl PinInit) -> impl PinInit { // SAFETY: `UnsafePinned` has a compatible layout to `T`. unsafe { cast_pin_init(init) } -- cgit v1.2.3