[PATCH 5/5] rust: pin-init: add diagnostic attribute for `PinInit` and `Init`

From: Gary Guo

Date: Wed Sep 23 2026 - 14:42:25 EST


Give a slightly more useful error message when these traits are not
implemented.

Before this change:

error[E0277]: the trait bound `impl pin_init::PinInit<Bar>: Init<Bar, _>` is not satisfied
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -------^^^^^^^^^^
| | |
| | the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| required by a bound introduced by this call

After this change:

error[E0277]: `impl pin_init::PinInit<Bar>` cannot be used to movably initialize `Bar` with error `_`
--> tests/ui/compile-fail/init/invalid_init.rs:19:16
|
19 | bar <- Bar::new(),
| -------^^^^^^^^^^
| | |
| | the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
| required by a bound introduced by this call
|
= note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields

Ideally, we would generate differnet message when `PinInit` is implemented
but not `Init`; that is not feasible with today's
`diagnostics::on_unimplemented` attribute. However, the added note is worth
it because in `init!()` is more rarely used compared to `pin_init!()`; in
most cases `Init` being unimplemented is the result of missing `#[pin]`.

Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/pin-init/src/lib.rs | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 319485dc18ce..d1ed0561bb27 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -966,6 +966,9 @@ macro_rules! assert_pinned {
#[cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")]
#[cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")]
#[must_use = "An initializer must be used in order to create its value."]
+#[diagnostic::on_unimplemented(
+ message = "`{Self}` cannot be used to initialize `{T}` with error `{E}`"
+)]
pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
/// Alias of [`PinInit::__init`].
///
@@ -1100,6 +1103,11 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
#[cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")]
#[cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")]
#[must_use = "An initializer must be used in order to create its value."]
+#[diagnostic::on_unimplemented(
+ message = "`{Self}` cannot be used to movably initialize `{T}` with error `{E}`",
+ note = "if your type implements `PinInit` but not `Init`, \
+ you might be forgetting a `#[pin]` annotation on fields"
+)]
pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// First initializes the value using `self` then calls the function `f` with the initialized
/// value.

--
2.54.0