* [PATCH 1/8] rust: pin-init: internal: pin_data: filter non-`#[cfg]` attr in generated code
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 2/8] rust: pin-init: internal: suppress `non_snake_case` lint in `#[pin_data]` Gary Guo
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Martin Kletzander
From: Martin Kletzander <mkletzan@redhat.com>
When using a macro with custom attributes in a `#[pin_data]` struct it
can mess up the generated code. The generated code needs nothing more than
the `#[cfg]` attribute, thus strip away all other attributes.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
[ Rebased and updated to only include `#[cfg]` instead of both `#[cfg]` and
`#[doc]`; doc is not needed for the generated hidden items. - Gary ]
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/pin_data.rs | 52 ++++++++++++++++++----------------
1 file changed, 28 insertions(+), 24 deletions(-)
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 2284256a6220..9ca8235ed3d6 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -7,7 +7,7 @@
parse_quote, parse_quote_spanned,
spanned::Spanned,
visit_mut::VisitMut,
- Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,
+ Attribute, Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,
};
use crate::diagnostics::{DiagCtxt, ErrorGuaranteed};
@@ -38,6 +38,7 @@ fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
struct FieldInfo<'a> {
field: &'a Field,
pinned: bool,
+ cfg_attrs: Vec<&'a Attribute>,
}
pub(crate) fn pin_data(
@@ -86,9 +87,16 @@ pub(crate) fn pin_data(
field.attrs.retain(|a| !a.path().is_ident("pin"));
let pinned = len != field.attrs.len();
+ let cfg_attrs = field
+ .attrs
+ .iter()
+ .filter(|a| a.path().is_ident("cfg"))
+ .collect();
+
FieldInfo {
field: &*field,
pinned,
+ cfg_attrs,
}
})
.collect();
@@ -171,7 +179,15 @@ fn generate_unpin_impl(
else {
unreachable!()
};
- let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| f.field);
+ let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| {
+ let ident = f.field.ident.as_ref().unwrap();
+ let ty = &f.field.ty;
+ let cfg_attrs = &f.cfg_attrs;
+ quote!(
+ #(#cfg_attrs)*
+ #ident: #ty
+ )
+ });
quote! {
// This struct will be used for the unpin analysis. It is needed, because only structurally
// pinned fields are relevant whether the struct should implement `Unpin`.
@@ -259,27 +275,20 @@ fn generate_projections(
let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields
.iter()
.map(|field| {
- let Field {
- vis,
- ident,
- ty,
- attrs,
- ..
- } = &field.field;
-
- let mut no_doc_attrs = attrs.clone();
- no_doc_attrs.retain(|a| !a.path().is_ident("doc"));
+ let Field { vis, ident, ty, .. } = &field.field;
+ let cfg_attrs = &field.cfg_attrs;
+
let ident = ident
.as_ref()
.expect("only structs with named fields are supported");
if field.pinned {
(
quote!(
- #(#attrs)*
+ #(#cfg_attrs)*
#vis #ident: ::core::pin::Pin<&'__pin mut #ty>,
),
quote!(
- #(#no_doc_attrs)*
+ #(#cfg_attrs)*
// SAFETY: this field is structurally pinned.
#ident: unsafe { ::core::pin::Pin::new_unchecked(&mut #this.#ident) },
),
@@ -287,11 +296,11 @@ fn generate_projections(
} else {
(
quote!(
- #(#attrs)*
+ #(#cfg_attrs)*
#vis #ident: &'__pin mut #ty,
),
quote!(
- #(#no_doc_attrs)*
+ #(#cfg_attrs)*
#ident: &mut #this.#ident,
),
)
@@ -358,13 +367,8 @@ fn generate_the_pin_data(
let field_accessors = fields
.iter()
.map(|f| {
- let Field {
- vis,
- ident,
- ty,
- attrs,
- ..
- } = f.field;
+ let Field { vis, ident, ty, .. } = f.field;
+ let cfg_attrs = &f.cfg_attrs;
let field_name = ident
.as_ref()
@@ -381,7 +385,7 @@ fn generate_the_pin_data(
/// - `(*slot).#field_name` is properly aligned.
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed
/// memory.
- #(#attrs)*
+ #(#cfg_attrs)*
#[inline(always)]
#vis unsafe fn #field_name(
self,
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 2/8] rust: pin-init: internal: suppress `non_snake_case` lint in `#[pin_data]`
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
2026-05-27 17:19 ` [PATCH 1/8] rust: pin-init: internal: pin_data: filter non-`#[cfg]` attr in generated code Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 3/8] rust: pin-init: internal: suppress `non_snake_case` lint in `[pin_]init!` Gary Guo
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
Allows `non_snake_case` lint on struct fields generated by `#[pin_data]`.
Since the same warning will be reported by the compiler on the struct
definition, having extra warnings for the generated code is unnecessary
and confusing.
Signed-off-by: Mirko Adzic <adzicmirko97@gmail.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/pin_data.rs | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 9ca8235ed3d6..9fbbd25bcaac 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -191,7 +191,10 @@ fn generate_unpin_impl(
quote! {
// This struct will be used for the unpin analysis. It is needed, because only structurally
// pinned fields are relevant whether the struct should implement `Unpin`.
- #[allow(dead_code)] // The fields below are never used.
+ #[allow(
+ dead_code, // The fields below are never used.
+ non_snake_case // The warning will be emitted on the struct definition.
+ )]
struct __Unpin #generics_with_pin_lt
#where_token
#predicates
@@ -318,7 +321,9 @@ fn generate_projections(
let docs = format!(" Pin-projections of [`{ident}`]");
quote! {
#[doc = #docs]
- #[allow(dead_code)]
+ // Allow `non_snake_case` since the same warning will be emitted on
+ // the struct definition.
+ #[allow(dead_code, non_snake_case)]
#[doc(hidden)]
#vis struct #projection #generics_with_pin_lt
#whr
@@ -386,6 +391,9 @@ fn generate_the_pin_data(
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed
/// memory.
#(#cfg_attrs)*
+ // Allow `non_snake_case` since the same warning will be emitted on
+ // the struct definition.
+ #[allow(non_snake_case)]
#[inline(always)]
#vis unsafe fn #field_name(
self,
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 3/8] rust: pin-init: internal: suppress `non_snake_case` lint in `[pin_]init!`
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
2026-05-27 17:19 ` [PATCH 1/8] rust: pin-init: internal: pin_data: filter non-`#[cfg]` attr in generated code Gary Guo
2026-05-27 17:19 ` [PATCH 2/8] rust: pin-init: internal: suppress `non_snake_case` lint in `#[pin_data]` Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 4/8] rust: pin-init: docs: fix typos in MaybeZeroable documentation Gary Guo
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
Allows `non_snake_case` lint on local variables generated in `[pin_]init!`.
Conceptually the identifiers in `[pin_]init!` just references the field
names, and are not defining them, so the warning should not be generated,
similar to how constructing a struct with non-snake-case field names do no
generate these warnings.
Reported-by: Gary Guo <gary@garyguo.net>
Closes: https://github.com/Rust-for-Linux/pin-init/issues/125
Closes: https://lore.kernel.org/rust-for-linux/DGTBJBIVFZ2K.2F1ZEFGY0G7NK@garyguo.net/
Fixes: 42415d163e5d ("rust: pin-init: add references to previously initialized fields")
Signed-off-by: Mirko Adzic <adzicmirko97@gmail.com>
[ Reworded commit message - Gary ]
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/internal/src/init.rs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 699b105570a5..041a84593730 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -296,7 +296,9 @@ fn init_fields(
#init
#(#cfgs)*
- #[allow(unused_variables)]
+ // Allow `non_snake_case` since the same warning is going to be reported for the struct
+ // field.
+ #[allow(unused_variables, non_snake_case)]
let #ident = #guard.let_binding();
});
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 4/8] rust: pin-init: docs: fix typos in MaybeZeroable documentation
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (2 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 3/8] rust: pin-init: internal: suppress `non_snake_case` lint in `[pin_]init!` Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 5/8] rust: pin-init: move `InitClosure` out from `__internal` Gary Guo
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Xiaobo Liu
From: Xiaobo Liu <cppcoffee@gmail.com>
Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index c9e2cbe27915..84099474324e 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -431,7 +431,7 @@
/// ```
/// use pin_init::MaybeZeroable;
///
-/// // implmements `Zeroable`
+/// // implements `Zeroable`
/// #[derive(MaybeZeroable)]
/// pub struct DriverData {
/// pub(crate) id: i64,
@@ -439,7 +439,7 @@
/// len: usize,
/// }
///
-/// // does not implmement `Zeroable`
+/// // does not implement `Zeroable`
/// #[derive(MaybeZeroable)]
/// pub struct DriverData2 {
/// pub(crate) id: i64,
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 5/8] rust: pin-init: move `InitClosure` out from `__internal`
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (3 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 4/8] rust: pin-init: docs: fix typos in MaybeZeroable documentation Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 6/8] rust: pin-init: remove `E` from `InitClosure` Gary Guo
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo
The `__internal` module is for exposing internal items publicly to
procedural macros (pin-init-internal). Types that are crate-local only can
just have proper visibility and does not need to be in `__internal`.
The type name of `InitClosure` can often shows up in symbol names, this
reduces the length slightly.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/__internal.rs | 30 ------------------------------
rust/pin-init/src/lib.rs | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 540add6cee8a..56dc655e323e 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -58,36 +58,6 @@ pub const fn new() -> Self {
}
}
-/// Module-internal type implementing `PinInit` and `Init`.
-///
-/// It is unsafe to create this type, since the closure needs to fulfill the same safety
-/// requirement as the `__pinned_init`/`__init` functions.
-pub(crate) struct InitClosure<F, T: ?Sized, E>(pub(crate) F, pub(crate) PhantomInvariant<(E, T)>);
-
-// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the
-// `__init` invariants.
-unsafe impl<T: ?Sized, F, E> Init<T, E> for InitClosure<F, T, E>
-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.
-unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E>
-where
- F: FnOnce(*mut T) -> Result<(), E>,
-{
- #[inline]
- unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
- (self.0)(slot)
- }
-}
-
/// Token type to signify successful initialization.
///
/// Can only be constructed via the unsafe [`Self::new`] function. The initializer macros use this
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 84099474324e..9732af32795c 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -1092,6 +1092,36 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
}
}
+/// 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.
+struct InitClosure<F, T: ?Sized, E>(F, __internal::PhantomInvariant<(E, T)>);
+
+// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the
+// `__init` invariants.
+unsafe impl<T: ?Sized, F, E> Init<T, E> for InitClosure<F, T, E>
+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.
+unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E>
+where
+ F: FnOnce(*mut T) -> Result<(), E>,
+{
+ #[inline]
+ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
+ (self.0)(slot)
+ }
+}
+
/// Creates a new [`PinInit<T, E>`] from the given closure.
///
/// # Safety
@@ -1108,7 +1138,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
pub const unsafe fn pin_init_from_closure<T: ?Sized, E>(
f: impl FnOnce(*mut T) -> Result<(), E>,
) -> impl PinInit<T, E> {
- __internal::InitClosure(f, __internal::PhantomInvariant::new())
+ InitClosure(f, __internal::PhantomInvariant::new())
}
/// Creates a new [`Init<T, E>`] from the given closure.
@@ -1127,7 +1157,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
pub const unsafe fn init_from_closure<T: ?Sized, E>(
f: impl FnOnce(*mut T) -> Result<(), E>,
) -> impl Init<T, E> {
- __internal::InitClosure(f, __internal::PhantomInvariant::new())
+ InitClosure(f, __internal::PhantomInvariant::new())
}
/// Changes the to be initialized type.
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 6/8] rust: pin-init: remove `E` from `InitClosure`
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (4 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 5/8] rust: pin-init: move `InitClosure` out from `__internal` Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 7/8] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe Gary Guo
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo
Move `E` from type to trait impl block. This greatly shortens the
monomorphized type names. The `__pinned_init` function name is only
slightly shortened as it still encodes the `E` as part of `PinInit<T, E>`
in the symbol.
`T` cannot be moved to trait impl block otherwise it will start to conflict
with the `impl Init<T> for T` as Rust cannot deduce that there're no types
that fulfill `T: FnOnce(*mut T)`.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 9732af32795c..fd40c8f244a1 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -1096,11 +1096,11 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
///
/// It is unsafe to create this type, since the closure needs to fulfill the same safety
/// requirement as the `__pinned_init`/`__init` functions.
-struct InitClosure<F, T: ?Sized, E>(F, __internal::PhantomInvariant<(E, T)>);
+struct InitClosure<F, T: ?Sized>(F, __internal::PhantomInvariant<T>);
// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the
// `__init` invariants.
-unsafe impl<T: ?Sized, F, E> Init<T, E> for InitClosure<F, T, E>
+unsafe impl<T: ?Sized, F, E> Init<T, E> for InitClosure<F, T>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
@@ -1112,7 +1112,7 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the
// `__pinned_init` invariants.
-unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E>
+unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 7/8] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (5 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 6/8] rust: pin-init: remove `E` from `InitClosure` Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-27 17:19 ` [PATCH 8/8] rust: pin-init: make `[pin_]chain` " Gary Guo
2026-05-29 21:04 ` [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
Adds a guard type that safely initializes an array by running an
initializer on each element, keeping track of the number of initialized
elements. In the case of a panic or error in the per-element initializer,
the guard drops the already-initialized portion of the array; nothing is
dropped on success.
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.
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>
[ Add `#[inline]` to `ArrayInit::drop` - Gary ]
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/pin-init/src/lib.rs | 157 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 115 insertions(+), 42 deletions(-)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index fd40c8f244a1..1fdf9c2366ff 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -1193,6 +1193,117 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
unsafe { init_from_closure(|_| Ok(())) }
}
+/// Allows safe (pinned and non-pinned) initialization of an array.
+///
+/// Drops the already initialized elements of the array if an error or panic occurs
+/// partway through the initialization process.
+///
+/// # Invariants
+///
+/// If `ptr` is not null:
+/// - `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 ArrayInit<T, F> {
+ /// A pointer to the first element of the array.
+ ptr: *mut T,
+ /// The number of initialized elements in the array.
+ num_init: usize,
+ /// Initialization function factory.
+ make_init: F,
+}
+
+impl<T, F> ArrayInit<T, F> {
+ #[inline]
+ fn new(make_init: F) -> Self {
+ Self {
+ // INVARIANT: `ptr` is null prior to any initialization.
+ ptr: core::ptr::null_mut(),
+ num_init: 0,
+ make_init,
+ }
+ }
+}
+
+/// SAFETY: On success, all `N` elements of the array have been initialized through
+/// `I: Init`. On error or panic, the elements that have been initialized so far are
+/// dropped, thus leaving the array uninitialized and ready to deallocate. The `Init`
+/// implementation executes the same code as that of `PinInit`.
+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>,
+{
+ unsafe fn __init(mut self, slot: *mut [T; N]) -> Result<(), E> {
+ debug_assert!(!slot.is_null());
+ // INVARIANT: `self.ptr` is non-null once initialization starts.
+ self.ptr = slot.cast::<T>();
+ for i in 0..N {
+ // INVARIANT: Elements `self.ptr[..self.num_init]` have been initialized
+ // thus far. This hold true for every `self.num_init = i`.
+ self.num_init = i;
+ let init = (self.make_init)(i);
+ // SAFETY: `self.ptr.add(i)` is in bounds.
+ let ptr = unsafe { self.ptr.add(i) };
+ // SAFETY: The pointer is derived from `slot` with a valid offset. It is
+ // thus valid for writes and points uninitialized memory.
+ unsafe { init.__init(ptr) }?;
+ }
+ // INVARIANT: `self.ptr` is null after the array is initialized.
+ self.ptr = core::ptr::null_mut();
+ Ok(())
+ }
+}
+
+/// SAFETY: On success, all `N` elements of the array have been initialized through
+/// `I`. Since `I: PinInit` guarantees that the pinning invariants of `T` are upheld,
+/// the guarantees of `[T; N]` are also upheld. 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> {
+ debug_assert!(!slot.is_null());
+ // INVARIANT: `self.ptr` is non-null once initialization starts.
+ self.ptr = slot.cast::<T>();
+ for i in 0..N {
+ // INVARIANT: Elements `self.ptr[..self.num_init]` have been initialized
+ // thus far. This hold true for every `self.num_init = i`.
+ self.num_init = i;
+ let init = (self.make_init)(i);
+ // SAFETY: `self.ptr.add(i)` is in bounds.
+ let ptr = unsafe { self.ptr.add(i) };
+ // SAFETY: The pointer is derived from `slot` with a valid offset. It is
+ // thus valid for writes and points uninitialized memory.
+ unsafe { init.__pinned_init(ptr) }?;
+ }
+ // INVARIANT: `self.ptr` is null after the array is initialized.
+ self.ptr = core::ptr::null_mut();
+ Ok(())
+ }
+}
+
+impl<T, F> Drop for ArrayInit<T, F> {
+ #[inline]
+ fn drop(&mut self) {
+ if self.ptr.is_null() {
+ // Since `self.ptr` is null - either no initialization has been attempted
+ // or the array was successfully initialized, per type invariant. Nothing
+ // to drop.
+ return;
+ }
+
+ // SAFETY: Since `self.ptr` is not null - the initialization has failed
+ // partway. Drop `self.ptr[..self.num_init]` which are initialized per
+ // type invariant.
+ unsafe {
+ core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(self.ptr, self.num_init))
+ };
+ }
+}
+
/// Initializes an array by initializing each element via the provided initializer.
///
/// # Examples
@@ -1204,31 +1315,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::new(make_init)
}
/// Initializes an array by initializing each element via the provided initializer.
@@ -1247,31 +1339,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::new(make_init)
}
/// Construct an initializer in a closure and run it.
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 8/8] rust: pin-init: make `[pin_]chain` unwind safe
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (6 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 7/8] rust: pin-init: make `[pin_]init_array_from_fn` unwind safe Gary Guo
@ 2026-05-27 17:19 ` Gary Guo
2026-05-29 21:04 ` [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-27 17:19 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Gary Guo, Mirko Adzic
From: Mirko Adzic <adzicmirko97@gmail.com>
Adds 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>
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 1fdf9c2366ff..b5af88c9e48b 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -965,13 +965,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 mut guard =
+ unsafe { __internal::Slot::<__internal::Pinned, _>::new(slot) }.init(self.0)?;
+ (self.1)(guard.let_binding())?;
+ core::mem::forget(guard);
+ Ok(())
}
}
@@ -1072,11 +1070,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 mut guard =
+ unsafe { __internal::Slot::<__internal::Unpinned, _>::new(slot) }.init(self.0)?;
+ (self.1)(guard.let_binding())?;
+ core::mem::forget(guard);
+ Ok(())
}
}
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2)
2026-05-27 17:19 [PATCH 0/8] rust: pin-init upstream sync for v7.2 (round 2) Gary Guo
` (7 preceding siblings ...)
2026-05-27 17:19 ` [PATCH 8/8] rust: pin-init: make `[pin_]chain` " Gary Guo
@ 2026-05-29 21:04 ` Gary Guo
8 siblings, 0 replies; 10+ messages in thread
From: Gary Guo @ 2026-05-29 21:04 UTC (permalink / raw)
To: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich
Cc: rust-for-linux, linux-kernel, Martin Kletzander, Mirko Adzic, Xiaobo Liu
On Wed May 27, 2026 at 6:19 PM BST, Gary Guo wrote:
> This is a second round of patch syncs from upstream pin-init repo.
> The following patches are included.
>
> - Allow other attributes in #[pin_data] structs
> https://github.com/Rust-for-Linux/pin-init/pull/122
>
> - init: allow `nonstandard_style` for generated accessor/value
> https://github.com/Rust-for-Linux/pin-init/pull/127
>
> - docs: fix typos in MaybeZeroable documentation
> https://github.com/Rust-for-Linux/pin-init/pull/154
>
> - Optimize symbol name length of `InitClosure`
> https://github.com/Rust-for-Linux/pin-init/pull/153
>
> - unwind safety fixes
> https://github.com/Rust-for-Linux/pin-init/pull/140
>
> Notably the `nonstandard_style` fix will allow a bunch of `#[allow]`s to be
> removed from Nova's codebase.
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
> Gary Guo (2):
> rust: pin-init: move `InitClosure` out from `__internal`
> rust: pin-init: remove `E` from `InitClosure`
>
> Martin Kletzander (1):
> rust: pin-init: internal: pin_data: filter non-`#[cfg]` attr in generated code
>
> Mirko Adzic (2):
> rust: pin-init: internal: suppress `non_snake_case` lint in `#[pin_data]`
> rust: pin-init: internal: suppress `non_snake_case` lint in `[pin_]init!`
>
> Xiaobo Liu (1):
> rust: pin-init: docs: fix typos in MaybeZeroable documentation
I've applied the above patches to pin-init-next. The two patches below are not
applied and would need a respin.
> Mirko Adzic (2):
> rust: pin-init: make `[pin_]init_array_from_fn` unwind safe
This one has an issue reported by a Sashiko.
> rust: pin-init: make `[pin_]chain` unwind safe
And this one triggers a false positive lint in Clippy 1.85, which appears to be
fixed in 1.96. I didn't bother bisecting.
Best,
Gary
>
> rust/pin-init/internal/src/init.rs | 4 +-
> rust/pin-init/internal/src/pin_data.rs | 64 ++++++----
> rust/pin-init/src/__internal.rs | 30 -----
> rust/pin-init/src/lib.rs | 217 ++++++++++++++++++++++++---------
> 4 files changed, 200 insertions(+), 115 deletions(-)
^ permalink raw reply [flat|nested] 10+ messages in thread