[PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros

Benno Lossin posted 1 patch 4 days, 11 hours ago
rust/pin-init/src/lib.rs    |  2 ++
rust/pin-init/src/macros.rs | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
[PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Benno Lossin 4 days, 11 hours ago
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
Re: [PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Danilo Krummrich 2 days, 8 hours ago
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>
Re: [PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Alice Ryhl 2 days, 15 hours ago
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
Re: [PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Danilo Krummrich 2 days, 14 hours ago
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.
Re: [PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Alice Ryhl 2 days, 14 hours ago
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
Re: [PATCH] rust: pin-init: add code blocks to `[try_][pin_]init!` macros
Posted by Danilo Krummrich 2 days, 14 hours ago
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