mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]`
@ 2026-09-23 18:20 Gary Guo
  2026-09-23 18:20 ` [PATCH 1/5] rust: pin-init: internal: make `__init_data` and `__pin_data` safe Gary Guo
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

Improve the diagnostics of missing `#[pin_data]` and `#[pin]`, by adding
diagnostics attributes. For `#[pin_data]`, we have to change the expansion
to retrieve `PinData` in a two-step process, so we change the error message
from "method exists but trait bound not satisfied" to "trait not
implemented".

This is the new error message for missing `#[pin_data]`:

    error[E0277]: `Foo` cannot be used with `pin_init!` macro
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`

where it was previously

    error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
      |
    3 | struct Foo {
      | ---------- associated function or constant `__pin_data` not found for this struct
    ...
    9 |         pin_init!(Self { a: 42 })
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
      |
      = help: items from traits can only be used if the trait is implemented and in scope
      = note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
              candidate #1: `pin_init::__internal::HasPinData`

and this is the new error message for missing `#[pin]`:

    error[E0277]: `impl PinInit<usize>` cannot be used to movably initialize `usize` with error `_`
      --> tests/ui/compile-fail/pin_data/missing_pin.rs:12:18
       |
    12 |             a <- a,
       |             -----^
       |             |    |
       |             |    the trait `Init<usize, _>` is not implemented for `impl PinInit<usize>`
       |             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

where it was previously

    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

Signed-off-by: Gary Guo <gary@garyguo.net>
---
Gary Guo (5):
      rust: pin-init: internal: make `__init_data` and `__pin_data` safe
      rust: pin-init: internal: remove associated type of `HasInitData`
      rust: pin-init: internal: use `HasInitData` to provide inference help only
      rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented
      rust: pin-init: add diagnostic attribute for `PinInit` and `Init`

 rust/pin-init/internal/src/init.rs     | 25 +++++++++---------
 rust/pin-init/internal/src/pin_data.rs |  2 +-
 rust/pin-init/src/__internal.rs        | 48 +++++++++++++++-------------------
 rust/pin-init/src/lib.rs               | 11 +++++++-
 4 files changed, 45 insertions(+), 41 deletions(-)
---
base-commit: dfb6a037fd586f1ffcba3b143dab58f5c88294d1
change-id: 20260923-dev-pin-data-diag-65209ab751fc

Best regards,
--  
Gary Guo <gary@garyguo.net>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/5] rust: pin-init: internal: make `__init_data` and `__pin_data` safe
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
@ 2026-09-23 18:20 ` Gary Guo
  2026-09-23 18:20 ` [PATCH 2/5] rust: pin-init: internal: remove associated type of `HasInitData` Gary Guo
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

Remove the unsafe markers of `__init_data` and `__pin_data`. These methods
are for inference help and does not need to be unsafe.

The `HasInitData` cannot be implemented outside pin-init, so the `unsafe
trait` marker is not necessary.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/pin-init/internal/src/init.rs     |  3 +--
 rust/pin-init/internal/src/pin_data.rs |  2 +-
 rust/pin-init/src/__internal.rs        | 11 +++++------
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 1d2db93dd33d..1957be83a196 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -312,8 +312,7 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
     let field_check = make_field_check(&fields, init_kind, &path);
     Ok(quote_spanned! { Span::mixed_site() => {
         // Get the data about fields from the supplied type.
-        // SAFETY: TODO
-        let data = unsafe {
+        let data = {
             use ::pin_init::__internal::#has_data_trait;
             // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
             // generics (which need to be present with that syntax).
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 8cd9bf139567..30d9b8b54d8a 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -538,7 +538,7 @@ unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #
             type PinData = __ThePinData #ty_generics;
 
             #[inline]
-            unsafe fn __pin_data() -> Self::PinData {
+            fn __pin_data() -> Self::PinData {
                 __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() }
             }
         }
diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 8e9fd18b993f..51f6b40daa9e 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -81,12 +81,12 @@ pub unsafe fn new() -> Self {
 ///
 /// # Safety
 ///
-/// Only the `init` module is allowed to use this trait.
+/// `pin-init` relies on the correctness of the helper functions defined on `PinData`.
+/// Thus, only the `#[pin_data]` can implement this trait.
 pub unsafe trait HasPinData {
     type PinData;
 
-    #[expect(clippy::missing_safety_doc)]
-    unsafe fn __pin_data() -> Self::PinData;
+    fn __pin_data() -> Self::PinData;
 }
 
 /// This trait is automatically implemented for every type. It aims to provide the same type
@@ -98,8 +98,7 @@ pub unsafe trait HasPinData {
 pub unsafe trait HasInitData {
     type InitData;
 
-    #[expect(clippy::missing_safety_doc)]
-    unsafe fn __init_data() -> Self::InitData;
+    fn __init_data() -> Self::InitData;
 }
 
 pub struct AllData<T: ?Sized>(PhantomInvariant<T>);
@@ -129,7 +128,7 @@ unsafe impl<T: ?Sized> HasInitData for T {
     type InitData = AllData<T>;
 
     #[inline]
-    unsafe fn __init_data() -> Self::InitData {
+    fn __init_data() -> Self::InitData {
         AllData(PhantomInvariant::new())
     }
 }

-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/5] rust: pin-init: internal: remove associated type of `HasInitData`
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
  2026-09-23 18:20 ` [PATCH 1/5] rust: pin-init: internal: make `__init_data` and `__pin_data` safe Gary Guo
@ 2026-09-23 18:20 ` Gary Guo
  2026-09-23 18:20 ` [PATCH 3/5] rust: pin-init: internal: use `HasInitData` to provide inference help only Gary Guo
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

There is only a single implementation, the associated type is not
necessary. Remove it, and rename `AllData` to `InitData` to be a more
meaningful name.

The single implementation also means that "unsafe" is redundant, so remove
it as well.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/pin-init/src/__internal.rs | 37 ++++++++++++++-----------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 51f6b40daa9e..15eca4869bc3 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -89,30 +89,31 @@ pub unsafe trait HasPinData {
     fn __pin_data() -> Self::PinData;
 }
 
-/// This trait is automatically implemented for every type. It aims to provide the same type
-/// inference help as `HasPinData`.
+/// This trait is automatically implemented for every type.
 ///
-/// # Safety
-///
-/// Only the `init` module is allowed to use this trait.
-pub unsafe trait HasInitData {
-    type InitData;
-
-    fn __init_data() -> Self::InitData;
+/// It aims to provide type inference help; `PATH::__init_data()` is would be able to retrieve an
+/// instance of `InitData<PATH<Generics>>` without having to mention the generics explicitly.
+pub trait HasInitData {
+    #[inline]
+    fn __init_data() -> InitData<Self> {
+        InitData(PhantomInvariant::new())
+    }
 }
 
-pub struct AllData<T: ?Sized>(PhantomInvariant<T>);
+impl<T: ?Sized> HasInitData for T {}
+
+pub struct InitData<T: ?Sized>(PhantomInvariant<T>);
 
-impl<T: ?Sized> Clone for AllData<T> {
+impl<T: ?Sized> Clone for InitData<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<T: ?Sized> Copy for AllData<T> {}
+impl<T: ?Sized> Copy for InitData<T> {}
 
-impl<T: ?Sized> AllData<T> {
+impl<T: ?Sized> InitData<T> {
     /// Type inference helper function.
     #[inline(always)]
     pub fn __make_closure<F, E>(self, f: F) -> F
@@ -123,16 +124,6 @@ pub fn __make_closure<F, E>(self, f: F) -> F
     }
 }
 
-// SAFETY: TODO.
-unsafe impl<T: ?Sized> HasInitData for T {
-    type InitData = AllData<T>;
-
-    #[inline]
-    fn __init_data() -> Self::InitData {
-        AllData(PhantomInvariant::new())
-    }
-}
-
 /// Stack initializer helper type. Use [`stack_pin_init`] instead of this primitive.
 ///
 /// # Invariants

-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 3/5] rust: pin-init: internal: use `HasInitData` to provide inference help only
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
  2026-09-23 18:20 ` [PATCH 1/5] rust: pin-init: internal: make `__init_data` and `__pin_data` safe Gary Guo
  2026-09-23 18:20 ` [PATCH 2/5] rust: pin-init: internal: remove associated type of `HasInitData` Gary Guo
@ 2026-09-23 18:20 ` Gary Guo
  2026-09-23 18:20 ` [PATCH 4/5] rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented Gary Guo
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

Currently, type inference of the initialized type is done by use the
function calling syntax `PATH::__pin_data` or `PATH::__init_data` to obtain
the required init data type, without needing the user to explicitly mention
all generics. Switch to always use `HasInitData::__init_data` to provide
that inference, which will not produce method-not-found errors as it is
always available.

Change `__pin_data` to take `InitData<Self>` as the receiver, so for types
that require `HasPinData`, `HasPinData::__pin_data(data)` can be used to
obtain the needed type without having to mention the user-provided path
again. The expanded code also uses the span of the type, so diagnostics
will hint to user that the type is causing the issue.

With this change, the error message when `HasPinData` is not implemented
changes from

    error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
      |
    3 | struct Foo {
      | ---------- associated function or constant `__pin_data` not found for this struct
    ...
    9 |         pin_init!(Self { a: 42 })
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
      |
      = help: items from traits can only be used if the trait is implemented and in scope
      = note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
              candidate #1: `pin_init::__internal::HasPinData`

to

    error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/pin-init/internal/src/init.rs     | 22 ++++++++++++----------
 rust/pin-init/internal/src/pin_data.rs |  2 +-
 rust/pin-init/src/__internal.rs        |  2 +-
 rust/pin-init/src/lib.rs               |  3 ++-
 4 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 1957be83a196..e98182c65447 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -269,18 +269,17 @@ fn expand(
         },
         |(_, err)| Box::new(err),
     );
-    let (has_data_trait, get_data, init_from_closure) = if pinned {
+    let (get_pin_data, init_from_closure) = if pinned {
         (
-            format_ident!("HasPinData"),
-            format_ident!("__pin_data"),
+            Some(
+                quote_spanned! { path.span().resolved_at(Span::mixed_site()) =>
+                    let data = ::pin_init::__internal::HasPinData::__pin_data(data);
+                },
+            ),
             format_ident!("pin_init_from_closure"),
         )
     } else {
-        (
-            format_ident!("HasInitData"),
-            format_ident!("__init_data"),
-            format_ident!("init_from_closure"),
-        )
+        (None, format_ident!("init_from_closure"))
     };
     let init_kind = get_init_kind(rest, dcx);
     let zeroable_check = match init_kind {
@@ -313,11 +312,14 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
     Ok(quote_spanned! { Span::mixed_site() => {
         // Get the data about fields from the supplied type.
         let data = {
-            use ::pin_init::__internal::#has_data_trait;
+            use ::pin_init::__internal::HasInitData;
             // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
             // generics (which need to be present with that syntax).
-            #path::#get_data()
+            #path::__init_data()
         };
+
+        #get_pin_data
+
         // Ensure that `data` really is of type `data` and help with type inference:
         let init = data.__make_closure::<_, #error>(
             move |slot| {
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 30d9b8b54d8a..a12e5a44a512 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -538,7 +538,7 @@ unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #
             type PinData = __ThePinData #ty_generics;
 
             #[inline]
-            fn __pin_data() -> Self::PinData {
+            fn __pin_data(_: ::pin_init::__internal::InitData<Self>) -> Self::PinData {
                 __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() }
             }
         }
diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 15eca4869bc3..f236db47d18b 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -86,7 +86,7 @@ pub unsafe fn new() -> Self {
 pub unsafe trait HasPinData {
     type PinData;
 
-    fn __pin_data() -> Self::PinData;
+    fn __pin_data(_: InitData<Self>) -> Self::PinData;
 }
 
 /// This trait is automatically implemented for every type.
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 4110590348c6..319485dc18ce 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -920,7 +920,8 @@ macro_rules! assert_pinned {
     ($ty:ty, $field:ident, $field_ty:ty, inline) => {
         // SAFETY: This code is unreachable.
         let _ = move |ptr: *mut $ty| unsafe {
-            let data = <$ty as $crate::__internal::HasPinData>::__pin_data();
+            let data = <$ty as $crate::__internal::HasInitData>::__init_data();
+            let data = $crate::__internal::HasPinData::__pin_data(data);
             _ = data
                 .$field(ptr)
                 .init($crate::__internal::AlwaysFail::<$field_ty>::new());

-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4/5] rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
                   ` (2 preceding siblings ...)
  2026-09-23 18:20 ` [PATCH 3/5] rust: pin-init: internal: use `HasInitData` to provide inference help only Gary Guo
@ 2026-09-23 18:20 ` Gary Guo
  2026-09-23 18:20 ` [PATCH 5/5] rust: pin-init: add diagnostic attribute for `PinInit` and `Init` Gary Guo
  2026-09-25 20:41 ` [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

Produce a more helpful error message when `#[pin_data]` is omitted. The
error message changes from

    error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^

to

    error[E0277]: `Foo` cannot be used with `pin_init!` macro
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^
      = note: did you forget to add `#[pin_data]` attribute to the struct?

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/pin-init/src/__internal.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index f236db47d18b..cb7a0c3066b6 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -83,6 +83,10 @@ pub unsafe fn new() -> Self {
 ///
 /// `pin-init` relies on the correctness of the helper functions defined on `PinData`.
 /// Thus, only the `#[pin_data]` can implement this trait.
+#[diagnostic::on_unimplemented(
+    message = "`{Self}` cannot be used with `pin_init!` macro",
+    note = "did you forget to add `#[pin_data]` attribute to the struct?"
+)]
 pub unsafe trait HasPinData {
     type PinData;
 

-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 5/5] rust: pin-init: add diagnostic attribute for `PinInit` and `Init`
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
                   ` (3 preceding siblings ...)
  2026-09-23 18:20 ` [PATCH 4/5] rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented Gary Guo
@ 2026-09-23 18:20 ` Gary Guo
  2026-09-25 20:41 ` [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-23 18:20 UTC (permalink / raw)
  To: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
	Onur Özkan
  Cc: rust-for-linux, linux-kernel, Gary Guo

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@garyguo.net>
---
 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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]`
  2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
                   ` (4 preceding siblings ...)
  2026-09-23 18:20 ` [PATCH 5/5] rust: pin-init: add diagnostic attribute for `PinInit` and `Init` Gary Guo
@ 2026-09-25 20:41 ` Gary Guo
  5 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-09-25 20:41 UTC (permalink / raw)
  To: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan
  Cc: rust-for-linux, linux-kernel

On Wed Sep 23, 2026 at 7:20 PM BST, Gary Guo wrote:
> Improve the diagnostics of missing `#[pin_data]` and `#[pin]`, by adding
> diagnostics attributes. For `#[pin_data]`, we have to change the expansion
> to retrieve `PinData` in a two-step process, so we change the error message
> from "method exists but trait bound not satisfied" to "trait not
> implemented".
>
> This is the new error message for missing `#[pin_data]`:
>
>     error[E0277]: `Foo` cannot be used with `pin_init!` macro
>      --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
>       |
>     9 |         pin_init!(Self { a: 42 })
>       |                   ^^^^ unsatisfied trait bound
>       |
>     help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
>
> where it was previously
>
>     error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
>      --> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
>       |
>     3 | struct Foo {
>       | ---------- associated function or constant `__pin_data` not found for this struct
>     ...
>     9 |         pin_init!(Self { a: 42 })
>       |         ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
>       |
>       = help: items from traits can only be used if the trait is implemented and in scope
>       = note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
>               candidate #1: `pin_init::__internal::HasPinData`
>
> and this is the new error message for missing `#[pin]`:
>
>     error[E0277]: `impl PinInit<usize>` cannot be used to movably initialize `usize` with error `_`
>       --> tests/ui/compile-fail/pin_data/missing_pin.rs:12:18
>        |
>     12 |             a <- a,
>        |             -----^
>        |             |    |
>        |             |    the trait `Init<usize, _>` is not implemented for `impl PinInit<usize>`
>        |             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
>
> where it was previously
>
>     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
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
> Gary Guo (5):
>       rust: pin-init: internal: make `__init_data` and `__pin_data` safe
>       rust: pin-init: internal: remove associated type of `HasInitData`
>       rust: pin-init: internal: use `HasInitData` to provide inference help only
>       rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented
>       rust: pin-init: add diagnostic attribute for `PinInit` and `Init`

Applied to pin-init-next, with typo pointed out by Sashiko fixed.

Best,
Gary

>
>  rust/pin-init/internal/src/init.rs     | 25 +++++++++---------
>  rust/pin-init/internal/src/pin_data.rs |  2 +-
>  rust/pin-init/src/__internal.rs        | 48 +++++++++++++++-------------------
>  rust/pin-init/src/lib.rs               | 11 +++++++-
>  4 files changed, 45 insertions(+), 41 deletions(-)
> ---
> base-commit: dfb6a037fd586f1ffcba3b143dab58f5c88294d1
> change-id: 20260923-dev-pin-data-diag-65209ab751fc
>
> Best regards,
> --  
> Gary Guo <gary@garyguo.net>



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-25 20:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 18:20 [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo
2026-09-23 18:20 ` [PATCH 1/5] rust: pin-init: internal: make `__init_data` and `__pin_data` safe Gary Guo
2026-09-23 18:20 ` [PATCH 2/5] rust: pin-init: internal: remove associated type of `HasInitData` Gary Guo
2026-09-23 18:20 ` [PATCH 3/5] rust: pin-init: internal: use `HasInitData` to provide inference help only Gary Guo
2026-09-23 18:20 ` [PATCH 4/5] rust: pin-init: internal: add custom diagnostic when `#[pin_data]` is not implemented Gary Guo
2026-09-23 18:20 ` [PATCH 5/5] rust: pin-init: add diagnostic attribute for `PinInit` and `Init` Gary Guo
2026-09-25 20:41 ` [PATCH 0/5] rust: pin-init: improve diagnostics of missing `#[pin_data]` and `#[pin]` Gary Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®