diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9fc01aa..c34b3db6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -449,6 +449,7 @@ jobs: fi working-directory: pin-init - name: Run checkpatch.pl + continue-on-error: true run: | if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/pin-init-next)" ]; then # when there are no new commits, we can succeed directly diff --git a/internal/src/init.rs b/internal/src/init.rs index 1d2db93d..e98182c6 100644 --- a/internal/src/init.rs +++ b/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 { @@ -312,13 +311,15 @@ fn expand( 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 { - use ::pin_init::__internal::#has_data_trait; + let data = { + 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/internal/src/pin_data.rs b/internal/src/pin_data.rs index 8cd9bf13..a12e5a44 100644 --- a/internal/src/pin_data.rs +++ b/internal/src/pin_data.rs @@ -538,7 +538,7 @@ fn generate_the_pin_data( type PinData = __ThePinData #ty_generics; #[inline] - unsafe fn __pin_data() -> Self::PinData { + fn __pin_data(_: ::pin_init::__internal::InitData) -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() } } } diff --git a/src/__internal.rs b/src/__internal.rs index 8e9fd18b..f924fe57 100644 --- a/src/__internal.rs +++ b/src/__internal.rs @@ -81,39 +81,43 @@ impl InitOk { /// /// # 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. +#[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; - #[expect(clippy::missing_safety_doc)] - unsafe fn __pin_data() -> Self::PinData; + fn __pin_data(_: InitData) -> 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; - - #[expect(clippy::missing_safety_doc)] - unsafe fn __init_data() -> Self::InitData; +/// It aims to provide type inference help; `PATH::__init_data()` would be able to retrieve an +/// instance of `InitData>` without having to mention the generics explicitly. +pub trait HasInitData { + #[inline] + fn __init_data() -> InitData { + InitData(PhantomInvariant::new()) + } } -pub struct AllData(PhantomInvariant); +impl HasInitData for T {} + +pub struct InitData(PhantomInvariant); -impl Clone for AllData { +impl Clone for InitData { #[inline] fn clone(&self) -> Self { *self } } -impl Copy for AllData {} +impl Copy for InitData {} -impl AllData { +impl InitData { /// Type inference helper function. #[inline(always)] pub fn __make_closure(self, f: F) -> F @@ -124,16 +128,6 @@ impl AllData { } } -// SAFETY: TODO. -unsafe impl HasInitData for T { - type InitData = AllData; - - #[inline] - unsafe fn __init_data() -> Self::InitData { - AllData(PhantomInvariant::new()) - } -} - /// Stack initializer helper type. Use [`stack_pin_init`] instead of this primitive. /// /// # Invariants diff --git a/src/lib.rs b/src/lib.rs index 41105903..d1ed0561 100644 --- a/src/lib.rs +++ b/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()); @@ -965,6 +966,9 @@ macro_rules! assert_pinned { #[cfg_attr(not(kernel), doc = "[`Arc`]: alloc::alloc::sync::Arc")] #[cfg_attr(not(kernel), doc = "[`Box`]: 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: Sized { /// Alias of [`PinInit::__init`]. /// @@ -1099,6 +1103,11 @@ where #[cfg_attr(not(kernel), doc = "[`Arc`]: alloc::alloc::sync::Arc")] #[cfg_attr(not(kernel), doc = "[`Box`]: 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: PinInit { /// First initializes the value using `self` then calls the function `f` with the initialized /// value. diff --git a/tests/ui/compile-fail/init/invalid_init.stderr b/tests/ui/compile-fail/init/invalid_init.stderr index 6c10c0de..a8a57f19 100644 --- a/tests/ui/compile-fail/init/invalid_init.stderr +++ b/tests/ui/compile-fail/init/invalid_init.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not satisfied +error[E0277]: `impl pin_init::PinInit` cannot be used to movably initialize `Bar` with error `_` --> tests/ui/compile-fail/init/invalid_init.rs:19:16 | 19 | bar <- Bar::new(), @@ -7,6 +7,7 @@ error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not | | the trait `Init` is not implemented for `impl pin_init::PinInit` | 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 help: the following other types implement trait `Init` --> src/lib.rs | diff --git a/tests/ui/compile-fail/init/missing_pin_data.stderr b/tests/ui/compile-fail/init/missing_pin_data.stderr index 03cdfe28..32899257 100644 --- a/tests/ui/compile-fail/init/missing_pin_data.stderr +++ b/tests/ui/compile-fail/init/missing_pin_data.stderr @@ -1,13 +1,13 @@ -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 +error[E0277]: `Foo` cannot be used with `pin_init!` macro + --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19 | -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` + | ^^^^ 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 | - = 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` +3 | struct Foo { + | ^^^^^^^^^^ + = note: did you forget to add `#[pin_data]` attribute to the struct? = note: this error originates in the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/missing_pin.stderr b/tests/ui/compile-fail/pin_data/missing_pin.stderr index d28ef460..7225cd1b 100644 --- a/tests/ui/compile-fail/pin_data/missing_pin.stderr +++ b/tests/ui/compile-fail/pin_data/missing_pin.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `impl PinInit: Init` is not satisfied +error[E0277]: `impl PinInit` cannot be used to movably initialize `usize` with error `_` --> tests/ui/compile-fail/pin_data/missing_pin.rs:12:18 | 12 | a <- a, @@ -7,6 +7,7 @@ error[E0277]: the trait bound `impl PinInit: Init` is not satis | | the trait `Init` is not implemented for `impl PinInit` | 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 help: the trait `Init` is not implemented for `impl PinInit` but trait `Init, !>` is implemented for it --> src/lib.rs diff --git a/tests/ui/compile-fail/pinned_drop/no_pin_data_but_pinned_drop.stderr b/tests/ui/compile-fail/pinned_drop/no_pin_data_but_pinned_drop.stderr index 80f94c62..9b721c91 100644 --- a/tests/ui/compile-fail/pinned_drop/no_pin_data_but_pinned_drop.stderr +++ b/tests/ui/compile-fail/pinned_drop/no_pin_data_but_pinned_drop.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied +error[E0277]: `Foo` cannot be used with `pin_init!` macro --> tests/ui/compile-fail/pinned_drop/no_pin_data_but_pinned_drop.rs:7:21 | 7 | impl PinnedDrop for Foo { @@ -9,6 +9,7 @@ help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo` | 4 | struct Foo {} | ^^^^^^^^^^ + = note: did you forget to add `#[pin_data]` attribute to the struct? note: required by a bound in `PinnedDrop` --> src/lib.rs | diff --git a/tests/ui/expand/many_generics.expanded.rs b/tests/ui/expand/many_generics.expanded.rs index 4007476e..dd337b02 100644 --- a/tests/ui/expand/many_generics.expanded.rs +++ b/tests/ui/expand/many_generics.expanded.rs @@ -155,7 +155,7 @@ const _: () = { { type PinData = __ThePinData<'a, 'b, T, SIZE>; #[inline] - unsafe fn __pin_data() -> Self::PinData { + fn __pin_data(_: ::pin_init::__internal::InitData) -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new(), } diff --git a/tests/ui/expand/pin-data.expanded.rs b/tests/ui/expand/pin-data.expanded.rs index c29811a1..f4846594 100644 --- a/tests/ui/expand/pin-data.expanded.rs +++ b/tests/ui/expand/pin-data.expanded.rs @@ -94,7 +94,7 @@ const _: () = { unsafe impl ::pin_init::__internal::HasPinData for Foo { type PinData = __ThePinData; #[inline] - unsafe fn __pin_data() -> Self::PinData { + fn __pin_data(_: ::pin_init::__internal::InitData) -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new(), } diff --git a/tests/ui/expand/pinned_drop.expanded.rs b/tests/ui/expand/pinned_drop.expanded.rs index bd1ff78a..aa5efec1 100644 --- a/tests/ui/expand/pinned_drop.expanded.rs +++ b/tests/ui/expand/pinned_drop.expanded.rs @@ -94,7 +94,7 @@ const _: () = { unsafe impl ::pin_init::__internal::HasPinData for Foo { type PinData = __ThePinData; #[inline] - unsafe fn __pin_data() -> Self::PinData { + fn __pin_data(_: ::pin_init::__internal::InitData) -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new(), } diff --git a/tests/ui/expand/simple-init.expanded.rs b/tests/ui/expand/simple-init.expanded.rs index 0dfc1cb4..fa621a24 100644 --- a/tests/ui/expand/simple-init.expanded.rs +++ b/tests/ui/expand/simple-init.expanded.rs @@ -2,7 +2,7 @@ use pin_init::*; struct Foo {} fn main() { let _ = { - let data = unsafe { + let data = { use ::pin_init::__internal::HasInitData; Foo::__init_data() }; diff --git a/tests/ui/expand/tuple_struct.expanded.rs b/tests/ui/expand/tuple_struct.expanded.rs index 61aefecc..9944a0c3 100644 --- a/tests/ui/expand/tuple_struct.expanded.rs +++ b/tests/ui/expand/tuple_struct.expanded.rs @@ -109,7 +109,7 @@ const _: () = { for Foo<'a, T, N> { type PinData = __ThePinData<'a, T, N>; #[inline] - unsafe fn __pin_data() -> Self::PinData { + fn __pin_data(_: ::pin_init::__internal::InitData) -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new(), } @@ -142,7 +142,7 @@ const _: () = { fn main() { let mut first = [1u8, 2, 3]; let _ = { - let data = unsafe { + let data = { use ::pin_init::__internal::HasInitData; Foo::__init_data() }; @@ -200,7 +200,7 @@ fn main() { }; let mut second = [4u8, 5, 6]; let _ = { - let data = unsafe { + let data = { use ::pin_init::__internal::HasInitData; Foo::__init_data() };