rust/pin-init/src/lib.rs | 2 ++ rust/pin-init/src/macros.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+)
Allow writing `_: { /* any number of statements */ }` in initializers to
run arbitrary code during initialization.
try_init!(MyStruct {
_: {
if check_something() {
return Err(MyError);
}
},
foo: Foo::new(val),
_: {
println!("successfully initialized `MyStruct`");
},
})
Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f
Signed-off-by: Benno Lossin <lossin@kernel.org>
---
I originally wanted to do some more modifications to the syntax of
initializer macros, but I didn't have the time this cycle. See
https://github.com/Rust-for-Linux/pin-init/pull/69
For the development of that syntax, it's probably going to be like a
closure where in order to support formatting via rustfmt. But it still
needs some disucssion around removing `<-`.
That change would allow having a `let` that binds a value for use in the
initializer. IIRC @Alice, you needed that for something.
---
rust/pin-init/src/lib.rs | 2 ++
rust/pin-init/src/macros.rs | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 62e013a5cc20..8b556b0e106a 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -740,6 +740,8 @@ macro_rules! stack_try_pin_init {
/// As already mentioned in the examples above, inside of `pin_init!` a `struct` initializer with
/// the following modifications is expected:
/// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
+/// - You can use `_: { /* run any user-code here */ },` anywhere where you can place fields in
+/// order to run arbitrary code.
/// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
/// pointer named `this` inside of the initializer.
/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the
diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs
index 9ced630737b8..752e77db998c 100644
--- a/rust/pin-init/src/macros.rs
+++ b/rust/pin-init/src/macros.rs
@@ -1202,6 +1202,21 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
$(::core::mem::forget($guards);)*
};
+ (init_slot($($use_data:ident)?):
+ @data($data:ident),
+ @slot($slot:ident),
+ @guards($($guards:ident,)*),
+ // arbitrary code block
+ @munch_fields(_: { $($code:tt)* }, $($rest:tt)*),
+ ) => {
+ { $($code)* }
+ $crate::__init_internal!(init_slot($($use_data)?):
+ @data($data),
+ @slot($slot),
+ @guards($($guards,)*),
+ @munch_fields($($rest)*),
+ );
+ };
(init_slot($use_data:ident): // `use_data` is present, so we use the `data` to init fields.
@data($data:ident),
@slot($slot:ident),
@@ -1351,6 +1366,20 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
);
}
};
+ (make_initializer:
+ @slot($slot:ident),
+ @type_name($t:path),
+ @munch_fields(_: { $($code:tt)* }, $($rest:tt)*),
+ @acc($($acc:tt)*),
+ ) => {
+ // code blocks are ignored for the initializer check
+ $crate::__init_internal!(make_initializer:
+ @slot($slot),
+ @type_name($t),
+ @munch_fields($($rest)*),
+ @acc($($acc)*),
+ );
+ };
(make_initializer:
@slot($slot:ident),
@type_name($t:path),
base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
--
2.50.1
On Fri Sep 5, 2025 at 4:05 PM CEST, Benno Lossin wrote: > Allow writing `_: { /* any number of statements */ }` in initializers to > run arbitrary code during initialization. > > try_init!(MyStruct { > _: { > if check_something() { > return Err(MyError); > } > }, > foo: Foo::new(val), > _: { > println!("successfully initialized `MyStruct`"); > }, > }) > > Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f > Signed-off-by: Benno Lossin <lossin@kernel.org> Tested-by: Danilo Krummrich <dakr@kernel.org>
On Fri, Sep 05, 2025 at 04:05:31PM +0200, Benno Lossin wrote: > Allow writing `_: { /* any number of statements */ }` in initializers to > run arbitrary code during initialization. > > try_init!(MyStruct { > _: { > if check_something() { > return Err(MyError); > } > }, > foo: Foo::new(val), > _: { > println!("successfully initialized `MyStruct`"); > }, > }) > > Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f > Signed-off-by: Benno Lossin <lossin@kernel.org> Nice! Would it be possible to include a user so I can see it work in practice? E.g., for the irq feature? Alice
On Sun Sep 7, 2025 at 12:57 PM CEST, Alice Ryhl wrote: > On Fri, Sep 05, 2025 at 04:05:31PM +0200, Benno Lossin wrote: >> Allow writing `_: { /* any number of statements */ }` in initializers to >> run arbitrary code during initialization. >> >> try_init!(MyStruct { >> _: { >> if check_something() { >> return Err(MyError); >> } >> }, >> foo: Foo::new(val), >> _: { >> println!("successfully initialized `MyStruct`"); >> }, >> }) >> >> Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f >> Signed-off-by: Benno Lossin <lossin@kernel.org> > > Nice! Would it be possible to include a user so I can see it work in > practice? E.g., for the irq feature? Devres needs this too, but the corresponding devres stuff was a fix and is in the current -rc only, so that's not a candidate. The IRQ stuff is in driver-core-next going to Linus for v6.18, hence, using it there, this patch would have to go through the driver-core tree as well. For me it is fine either way.
On Sun, Sep 07, 2025 at 01:20:39PM +0200, Danilo Krummrich wrote: > On Sun Sep 7, 2025 at 12:57 PM CEST, Alice Ryhl wrote: > > On Fri, Sep 05, 2025 at 04:05:31PM +0200, Benno Lossin wrote: > >> Allow writing `_: { /* any number of statements */ }` in initializers to > >> run arbitrary code during initialization. > >> > >> try_init!(MyStruct { > >> _: { > >> if check_something() { > >> return Err(MyError); > >> } > >> }, > >> foo: Foo::new(val), > >> _: { > >> println!("successfully initialized `MyStruct`"); > >> }, > >> }) > >> > >> Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f > >> Signed-off-by: Benno Lossin <lossin@kernel.org> > > > > Nice! Would it be possible to include a user so I can see it work in > > practice? E.g., for the irq feature? > > Devres needs this too, but the corresponding devres stuff was a fix and is in > the current -rc only, so that's not a candidate. > > The IRQ stuff is in driver-core-next going to Linus for v6.18, hence, using it > there, this patch would have to go through the driver-core tree as well. > > For me it is fine either way. It doesn't have to land together. I would be happy with: THIS CYCLE: Land just this patch. NEXT CYCLE: Land the irq and/or devres user. But I'd like to see it work in practice before I give a Reviewed-by. It's hard to evaluate this kind of macro change just from the macro itself. Alice
On Sun Sep 7, 2025 at 1:33 PM CEST, Alice Ryhl wrote: > On Sun, Sep 07, 2025 at 01:20:39PM +0200, Danilo Krummrich wrote: >> On Sun Sep 7, 2025 at 12:57 PM CEST, Alice Ryhl wrote: >> > On Fri, Sep 05, 2025 at 04:05:31PM +0200, Benno Lossin wrote: >> >> Allow writing `_: { /* any number of statements */ }` in initializers to >> >> run arbitrary code during initialization. >> >> >> >> try_init!(MyStruct { >> >> _: { >> >> if check_something() { >> >> return Err(MyError); >> >> } >> >> }, >> >> foo: Foo::new(val), >> >> _: { >> >> println!("successfully initialized `MyStruct`"); >> >> }, >> >> }) >> >> >> >> Link: https://github.com/Rust-for-Linux/pin-init/pull/84/commits/2880a9b898336e2d54f80715f00ce00f21f74d2f >> >> Signed-off-by: Benno Lossin <lossin@kernel.org> >> > >> > Nice! Would it be possible to include a user so I can see it work in >> > practice? E.g., for the irq feature? >> >> Devres needs this too, but the corresponding devres stuff was a fix and is in >> the current -rc only, so that's not a candidate. >> >> The IRQ stuff is in driver-core-next going to Linus for v6.18, hence, using it >> there, this patch would have to go through the driver-core tree as well. >> >> For me it is fine either way. > > It doesn't have to land together. I would be happy with: > > THIS CYCLE: Land just this patch. > NEXT CYCLE: Land the irq and/or devres user. > > But I'd like to see it work in practice before I give a Reviewed-by. > It's hard to evaluate this kind of macro change just from the macro > itself. Here's a patch for using it in devres (we backmerged -rc3 into driver-core-next): From 23e48f081b7ba6bebd375c6fa929f070f7977fc5 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich <dakr@kernel.org> Date: Sun, 7 Sep 2025 13:44:43 +0200 Subject: [PATCH] rust: devres: take advantage of initializer code blocks Use pin-init initializer code blocks to register the devres action. This resolved the TODO introduced by commit 75a7b151e808 ("rust: devres: fix leaking call to devm_add_action()"). Signed-off-by: Danilo Krummrich <dakr@kernel.org> --- rust/kernel/devres.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 132545962218..430fc4880ddb 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -119,7 +119,6 @@ pub struct Devres<T: Send> { // explicit `Send` and `Sync' impls can be removed. #[pin] inner: Opaque<Inner<T>>, - _add_action: (), } impl<T: Send> Devres<T> { @@ -146,10 +145,7 @@ pub fn new<'a, E>( revoke <- Completion::new(), data <- Revocable::new(data), })), - // TODO: Replace with "initializer code blocks" [1] once available. - // - // [1] https://github.com/Rust-for-Linux/pin-init/pull/69 - _add_action: { + _: { // SAFETY: `this` is a valid pointer to uninitialized memory. let inner = unsafe { &raw mut (*this.as_ptr()).inner }; base-commit: 544c94f0e155614551e0210074597a23d117830c -- 2.51.0
© 2016 - 2025 Red Hat, Inc.