* [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1)
@ 2026-07-10 16:20 Gary Guo
2026-07-10 16:20 ` [PATCH 1/7] rust: pin-init: internal: error on duplicate `#[pin]` attribute Gary Guo
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo, Luiz Georg, Mohamad Alsadhan, Mirko Adzic
This is a series that synchronize pin-init upstream.
It includes the following merged PR:
- internal: error on duplicate `#[pin]` attribute
https://github.com/Rust-for-Linux/pin-init/pull/120
It includes the following PR that I intend to merge soon:
- Lint cleanups
https://github.com/Rust-for-Linux/pin-init/pull/160
- unwind safety fixes
https://github.com/Rust-for-Linux/pin-init/pull/140
Signed-off-by: Gary Guo <gary@garyguo.net>
---
Gary Guo (4):
rust: pin-init: examples: fix incorrect drop
rust: pin-init: remove redundant clippy expects in doc tests
rust: pin-init: internal: stop using `expect` in macro expansion
rust: pin-init: internal: generate brace in macro for init code blocks
Luiz Georg (1):
rust: pin-init: internal: error on duplicate `#[pin]` attribute
Mirko Adzic (2):
rust: pin-init: make `[pin_]init_array_from_fn` unwind safe
rust: pin-init: make `[pin_]chain` unwind safe
rust/pin-init/examples/mutex.rs | 5 +-
rust/pin-init/internal/src/init.rs | 8 +-
rust/pin-init/internal/src/pin_data.rs | 10 +--
rust/pin-init/src/lib.rs | 151 ++++++++++++++++++++-------------
4 files changed, 101 insertions(+), 73 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260710-pin-init-sync-a4cee08c619c
Best regards,
--
Gary Guo <gary@garyguo.net>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] rust: pin-init: internal: error on duplicate `#[pin]` attribute
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 2/7] rust: pin-init: examples: fix incorrect drop Gary Guo
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo, Luiz Georg, Mohamad Alsadhan
From: Luiz Georg <luizgngeorg@gmail.com>
Duplicated `#[pin]` has no effect, thus error if misused.
Reported-by: Mohamad Alsadhan <mo@sdhn.cc>
Closes: https://github.com/Rust-for-Linux/pin-init/issues/119
Signed-off-by: Luiz Georg <luizgngeorg@gmail.com>
[ Reworded commit message, and change the logic so code generation still
continue after reporting error - Gary ]
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/pin_data.rs | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 9fbbd25bcaac..263f67300727 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -85,7 +85,10 @@ pub(crate) fn pin_data(
.map(|field| {
let len = field.attrs.len();
field.attrs.retain(|a| !a.path().is_ident("pin"));
- let pinned = len != field.attrs.len();
+ let pinned_count = len - field.attrs.len();
+ if pinned_count > 1 {
+ dcx.error(&field, "#[pin] attribute specified more than once");
+ }
let cfg_attrs = field
.attrs
@@ -95,7 +98,7 @@ pub(crate) fn pin_data(
FieldInfo {
field: &*field,
- pinned,
+ pinned: pinned_count != 0,
cfg_attrs,
}
})
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/7] rust: pin-init: examples: fix incorrect drop
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
2026-07-10 16:20 ` [PATCH 1/7] rust: pin-init: internal: error on duplicate `#[pin]` attribute Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 3/7] rust: pin-init: remove redundant clippy expects in doc tests Gary Guo
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo
Remove the drop and associated clippy allow. The warning reported by Clippy
here is genuine; the binding created is `Pin<&mut T>` so dropping it does
nothing. `stack_pin_init` created bindings are only dropped at the end of
scope.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/examples/mutex.rs | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs
index 35ecb5f68dc3..882f3e23f5dd 100644
--- a/rust/pin-init/examples/mutex.rs
+++ b/rust/pin-init/examples/mutex.rs
@@ -91,7 +91,7 @@ pub fn new(val: impl PinInit<T>) -> impl PinInit<Self> {
pub fn lock(&self) -> Pin<CMutexGuard<'_, T>> {
let mut sguard = self.spin_lock.acquire();
if self.locked.get() {
- stack_pin_init!(let wait_entry = WaitEntry::insert_new(&self.wait_list));
+ stack_pin_init!(let _wait_entry = WaitEntry::insert_new(&self.wait_list));
// println!("wait list length: {}", self.wait_list.size());
while self.locked.get() {
drop(sguard);
@@ -99,9 +99,6 @@ pub fn lock(&self) -> Pin<CMutexGuard<'_, T>> {
thread::park();
sguard = self.spin_lock.acquire();
}
- // This does have an effect, as the ListHead inside wait_entry implements Drop!
- #[expect(clippy::drop_non_drop)]
- drop(wait_entry);
}
self.locked.set(true);
unsafe {
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/7] rust: pin-init: remove redundant clippy expects in doc tests
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
2026-07-10 16:20 ` [PATCH 1/7] rust: pin-init: internal: error on duplicate `#[pin]` attribute Gary Guo
2026-07-10 16:20 ` [PATCH 2/7] rust: pin-init: examples: fix incorrect drop Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 4/7] rust: pin-init: internal: stop using `expect` in macro expansion Gary Guo
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo
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.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 7 -------
1 file changed, 7 deletions(-)
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 @@
/// # 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<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// # Examples
///
/// ```rust
- /// # #![expect(clippy::disallowed_names)]
/// use pin_init::{init, init_zeroed, Init};
///
/// struct Foo {
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/7] rust: pin-init: internal: stop using `expect` in macro expansion
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
` (2 preceding siblings ...)
2026-07-10 16:20 ` [PATCH 3/7] rust: pin-init: remove redundant clippy expects in doc tests Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 5/7] rust: pin-init: internal: generate brace in macro for init code blocks Gary Guo
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo
Most warnings are suppressed from external macro expansions by default, and
`unfulfilled_lint_expectations` is one of them. All of our `expect`s inside
macros therefore do nothing, and actually mislead people to the lints would
be actually emitted without them.
All `#[expect]`s on lints that do not fire inside external macros (and
without spans from users) are removed, while the rest is coverted to
`#[allow]`.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 2 +-
rust/pin-init/internal/src/pin_data.rs | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 28d30805d06b..c1197a994c82 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -334,7 +334,7 @@ fn make_field_check(
}),
};
quote! {
- #[allow(unreachable_code, clippy::diverging_sub_expression)]
+ #[allow(unreachable_code)]
// We use unreachable code to perform field checks. They're still checked by the compiler.
// SAFETY: this code is never executed.
let _ = || unsafe {
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 263f67300727..4438107682e0 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -245,7 +245,6 @@ fn drop(&mut self) {
// `Drop`. Additionally we will implement this trait for the struct leading to a conflict,
// if it also implements `Drop`
trait MustNotImplDrop {}
- #[expect(drop_bounds)]
impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {}
impl #impl_generics MustNotImplDrop for #ident #ty_generics
#whr
@@ -253,7 +252,6 @@ impl #impl_generics MustNotImplDrop for #ident #ty_generics
// We also take care to prevent users from writing a useless `PinnedDrop` implementation.
// They might implement `PinnedDrop` correctly for the struct, but forget to give
// `PinnedDrop` as the parameter to `#[pin_data]`.
- #[expect(non_camel_case_types)]
trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
impl<T: ::pin_init::PinnedDrop + ?::core::marker::Sized>
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
@@ -432,7 +430,6 @@ impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics
{}
#[allow(dead_code)] // Some functions might never be used and private.
- #[expect(clippy::missing_safety_doc)]
impl #impl_generics __ThePinData #ty_generics
#whr
{
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/7] rust: pin-init: internal: generate brace in macro for init code blocks
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
` (3 preceding siblings ...)
2026-07-10 16:20 ` [PATCH 4/7] rust: pin-init: internal: stop using `expect` in macro expansion Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 6/7] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe Gary Guo
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo
`init!` support interleaving code execution and initialization, and code
execution is done using `_: { ... }` syntax. If the code inside block is a
single statement, Rust may add a lint about unused braces, but the
suggestion will be incorrect as block is required by pin-init.
Currently we use `unused_brace` to suppress this, but this affect
everything nested inside as well. Use an alternative approach by generating
the block from the macro, then rustc will know to not emit the lint.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index c1197a994c82..fd0b5ea4a0a3 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -233,10 +233,12 @@ fn init_fields(
InitializerKind::Value { ident, .. } => ident,
InitializerKind::Init { ident, .. } => ident,
InitializerKind::Code { block, .. } => {
+ let stmt = &block.stmts;
res.extend(quote! {
#(#attrs)*
- #[allow(unused_braces)]
- #block
+ {
+ #(#stmt)*
+ }
});
continue;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/7] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
` (4 preceding siblings ...)
2026-07-10 16:20 ` [PATCH 5/7] rust: pin-init: internal: generate brace in macro for init code blocks Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-10 16:20 ` [PATCH 7/7] rust: pin-init: make `[pin_]chain` " Gary Guo
2026-07-13 11:50 ` [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
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 <gary@garyguo.net>
Closes: https://github.com/Rust-for-Linux/pin-init/issues/136
Signed-off-by: Mirko Adzic <adzicmirko97@gmail.com>
[ Split guard type and the initializer type, move the guard type to be
within __pinned_init. - Gary ]
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 122 +++++++++++++++++++++++++++++++----------------
1 file changed, 80 insertions(+), 42 deletions(-)
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<T, E>() -> impl Init<MaybeUninit<T>, E> {
unsafe { init_from_closure(|_| Ok(())) }
}
+/// Array initializer from element initializer.
+struct ArrayInit<T: ?Sized, F>(F, __internal::PhantomInvariant<T>);
+
+// 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<T, F, I, E, const N: usize> PinInit<[T; N], E> for ArrayInit<T, F>
+where
+ F: FnMut(usize) -> I,
+ I: PinInit<T, E>,
+{
+ 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<T> {
+ /// A pointer to the first element of the array.
+ ptr: *mut T,
+ /// The number of initialized elements in the array.
+ num_init: usize,
+ }
+
+ impl<T> Drop for ArrayInitGuard<T> {
+ #[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::<T>(),
+ 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<T, F, I, E, const N: usize> Init<[T; N], E> for ArrayInit<T, F>
+where
+ F: FnMut(usize) -> I,
+ I: Init<T, E>,
+{
+ #[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<T, E>() -> impl Init<MaybeUninit<T>, E> {
/// assert_eq!(array.len(), 1_000);
/// ```
pub fn init_array_from_fn<I, const N: usize, T, E>(
- mut make_init: impl FnMut(usize) -> I,
+ make_init: impl FnMut(usize) -> I,
) -> impl Init<[T; N], E>
where
I: Init<T, E>,
{
- let init = move |slot: *mut [T; N]| {
- let slot = slot.cast::<T>();
- 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 @@ pub fn init_array_from_fn<I, const N: usize, T, E>(
/// assert_eq!(array.len(), 1_000);
/// ```
pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
- mut make_init: impl FnMut(usize) -> I,
+ make_init: impl FnMut(usize) -> I,
) -> impl PinInit<[T; N], E>
where
I: PinInit<T, E>,
{
- let init = move |slot: *mut [T; N]| {
- let slot = slot.cast::<T>();
- 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.
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 7/7] rust: pin-init: make `[pin_]chain` unwind safe
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
` (5 preceding siblings ...)
2026-07-10 16:20 ` [PATCH 6/7] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe Gary Guo
@ 2026-07-10 16:20 ` Gary Guo
2026-07-13 11:50 ` [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-10 16:20 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
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 <gary@garyguo.net>
Closes: https://github.com/Rust-for-Linux/pin-init/issues/136
Suggested-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Mirko Adzic <adzicmirko97@gmail.com>
[ Fix Clippy missing safety comment false positive when `slot` and `guard`
creation are merged in a single line. - Gary ]
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
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 @@ unsafe impl<T: ?Sized, E, I, F> PinInit<T, E> for ChainPinInit<I, F, T, E>
{
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 @@ unsafe impl<T: ?Sized, E, I, F> Init<T, E> for ChainInit<I, F, T, E>
{
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(())
}
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1)
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
` (6 preceding siblings ...)
2026-07-10 16:20 ` [PATCH 7/7] rust: pin-init: make `[pin_]chain` " Gary Guo
@ 2026-07-13 11:50 ` Gary Guo
7 siblings, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-07-13 11:50 UTC (permalink / raw)
To: Gary Guo, Benno Lossin, Miguel Ojeda
Cc: Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
Luiz Georg, Mohamad Alsadhan, Mirko Adzic
On Fri Jul 10, 2026 at 5:20 PM BST, Gary Guo wrote:
> This is a series that synchronize pin-init upstream.
>
> It includes the following merged PR:
> - internal: error on duplicate `#[pin]` attribute
> https://github.com/Rust-for-Linux/pin-init/pull/120
>
> It includes the following PR that I intend to merge soon:
> - Lint cleanups
> https://github.com/Rust-for-Linux/pin-init/pull/160
> - unwind safety fixes
> https://github.com/Rust-for-Linux/pin-init/pull/140
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
> Gary Guo (4):
> rust: pin-init: examples: fix incorrect drop
> rust: pin-init: remove redundant clippy expects in doc tests
> rust: pin-init: internal: stop using `expect` in macro expansion
> rust: pin-init: internal: generate brace in macro for init code blocks
>
> Luiz Georg (1):
> rust: pin-init: internal: error on duplicate `#[pin]` attribute
>
> Mirko Adzic (2):
> rust: pin-init: make `[pin_]init_array_from_fn` unwind safe
> rust: pin-init: make `[pin_]chain` unwind safe
Applied to pin-init-next.
I reworded "rust: pin-init: internal: stop using `expect` in macro expansion"
based on Sashiko suggestion and picked up Benno's review on lint cleanup PR on
GitHub.
Best,
Gary
>
> rust/pin-init/examples/mutex.rs | 5 +-
> rust/pin-init/internal/src/init.rs | 8 +-
> rust/pin-init/internal/src/pin_data.rs | 10 +--
> rust/pin-init/src/lib.rs | 151 ++++++++++++++++++++-------------
> 4 files changed, 101 insertions(+), 73 deletions(-)
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 20260710-pin-init-sync-a4cee08c619c
>
> Best regards,
> --
> Gary Guo <gary@garyguo.net>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-07-13 11:50 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 16:20 [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
2026-07-10 16:20 ` [PATCH 1/7] rust: pin-init: internal: error on duplicate `#[pin]` attribute Gary Guo
2026-07-10 16:20 ` [PATCH 2/7] rust: pin-init: examples: fix incorrect drop Gary Guo
2026-07-10 16:20 ` [PATCH 3/7] rust: pin-init: remove redundant clippy expects in doc tests Gary Guo
2026-07-10 16:20 ` [PATCH 4/7] rust: pin-init: internal: stop using `expect` in macro expansion Gary Guo
2026-07-10 16:20 ` [PATCH 5/7] rust: pin-init: internal: generate brace in macro for init code blocks Gary Guo
2026-07-10 16:20 ` [PATCH 6/7] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe Gary Guo
2026-07-10 16:20 ` [PATCH 7/7] rust: pin-init: make `[pin_]chain` " Gary Guo
2026-07-13 11:50 ` [PATCH 0/7] rust: pin-init: upstream synchronization for 7.3 (round 1) Gary Guo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox