diff --git a/internal/src/init.rs b/internal/src/init.rs index b0bfe446..699b1055 100644 --- a/internal/src/init.rs +++ b/internal/src/init.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned}; +use quote::{format_ident, quote}; use syn::{ braced, parse::{End, Parse}, @@ -103,17 +103,15 @@ pub(crate) fn expand( |(_, err)| Box::new(err), ); let slot = format_ident!("slot"); - let (has_data_trait, data_trait, get_data, init_from_closure) = if pinned { + let (has_data_trait, get_data, init_from_closure) = if pinned { ( format_ident!("HasPinData"), - format_ident!("PinData"), format_ident!("__pin_data"), format_ident!("pin_init_from_closure"), ) } else { ( format_ident!("HasInitData"), - format_ident!("InitData"), format_ident!("__init_data"), format_ident!("init_from_closure"), ) @@ -157,8 +155,7 @@ pub(crate) fn expand( #path::#get_data() }; // Ensure that `#data` really is of type `#data` and help with type inference: - let init = ::pin_init::__internal::#data_trait::make_closure::<_, #error>( - #data, + let init = #data.__make_closure::<_, #error>( move |slot| { #zeroable_check #this @@ -231,107 +228,80 @@ fn init_fields( cfgs.retain(|attr| attr.path().is_ident("cfg")); cfgs }; + + let ident = match kind { + InitializerKind::Value { ident, .. } => ident, + InitializerKind::Init { ident, .. } => ident, + InitializerKind::Code { block, .. } => { + res.extend(quote! { + #(#attrs)* + #[allow(unused_braces)] + #block + }); + continue; + } + }; + + let slot = if pinned { + quote! { + // SAFETY: + // - `slot` is valid and properly aligned. + // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. + // - `make_field_check` prevents `#ident` from being used twice, therefore + // `(*slot).#ident` is exclusively accessed and has not been initialized. + (unsafe { #data.#ident(#slot) }) + } + } else { + quote! { + // For `init!()` macro, everything is unpinned. + // SAFETY: + // - `&raw mut (*slot).#ident` is valid. + // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. + // - `make_field_check` prevents `#ident` from being used twice, therefore + // `(*slot).#ident` is exclusively accessed and has not been initialized. + (unsafe { + ::pin_init::__internal::Slot::<::pin_init::__internal::Unpinned, _>::new( + &raw mut (*#slot).#ident + ) + }) + } + }; + + // `mixed_site` ensures that the guard is not accessible to the user-controlled code. + let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); + let init = match kind { InitializerKind::Value { ident, value } => { - let mut value_ident = ident.clone(); - let value_prep = value.as_ref().map(|value| &value.1).map(|value| { - // Setting the span of `value_ident` to `value`'s span improves error messages - // when the type of `value` is wrong. - value_ident.set_span(value.span()); - quote!(let #value_ident = #value;) - }); - // Again span for better diagnostics - let write = quote_spanned!(ident.span()=> ::core::ptr::write); + let value = value + .as_ref() + .map(|(_, value)| quote!(#value)) + .unwrap_or_else(|| quote!(#ident)); + quote! { #(#attrs)* - { - #value_prep - // SAFETY: TODO - unsafe { #write(&raw mut (*#slot).#ident, #value_ident) }; - } + let mut #guard = #slot.write(#value); + } } - InitializerKind::Init { ident, value, .. } => { - // Again span for better diagnostics - let init = format_ident!("init", span = value.span()); - let value_init = if pinned { - quote! { - // SAFETY: - // - `slot` is valid, because we are inside of an initializer closure, we - // return when an error/panic occurs. - // - We also use `#data` to require the correct trait (`Init` or `PinInit`) - // for `#ident`. - unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? }; - } - } else { - quote! { - // SAFETY: `slot` is valid, because we are inside of an initializer - // closure, we return when an error/panic occurs. - unsafe { - ::pin_init::Init::__init( - #init, - &raw mut (*#slot).#ident, - )? - }; - } - }; + InitializerKind::Init { value, .. } => { quote! { #(#attrs)* - { - let #init = #value; - #value_init - } + let mut #guard = #slot.init(#value)?; } } - InitializerKind::Code { block: value, .. } => quote! { - #(#attrs)* - #[allow(unused_braces)] - #value - }, + InitializerKind::Code { .. } => unreachable!(), }; - res.extend(init); - if let Some(ident) = kind.ident() { - // `mixed_site` ensures that the guard is not accessible to the user-controlled code. - let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); - // NOTE: The reference is derived from the guard so that it only lives as long as the - // guard does and cannot escape the scope. If it's created via `&mut (*#slot).#ident` - // like the unaligned field guard, it will become effectively `'static`. - let accessor = if pinned { - let project_ident = format_ident!("__project_{ident}"); - quote! { - // SAFETY: the initialization is pinned. - unsafe { #data.#project_ident(#guard.let_binding()) } - } - } else { - quote! { - #guard.let_binding() - } - }; + res.extend(quote! { + #init - res.extend(quote! { - #(#cfgs)* - // Create the drop guard. - // - // SAFETY: - // - `&raw mut (*slot).#ident` is valid. - // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. - // - `(*slot).#ident` has been initialized above. - // - We only need the ownership to the pointee back when initialization has - // succeeded, where we `forget` the guard. - let mut #guard = unsafe { - ::pin_init::__internal::DropGuard::new( - &raw mut (*slot).#ident - ) - }; + #(#cfgs)* + #[allow(unused_variables)] + let #ident = #guard.let_binding(); + }); - #(#cfgs)* - #[allow(unused_variables)] - let #ident = #accessor; - }); - guards.push(guard); - guard_attrs.push(cfgs); - } + guards.push(guard); + guard_attrs.push(cfgs); } quote! { #res diff --git a/internal/src/pin_data.rs b/internal/src/pin_data.rs index 44d0bd18..2284256a 100644 --- a/internal/src/pin_data.rs +++ b/internal/src/pin_data.rs @@ -352,10 +352,9 @@ fn generate_the_pin_data( let (impl_generics, ty_generics, whr) = generics.split_for_impl(); // For every field, we create an initializing projection function according to its projection - // type. If a field is structurally pinned, then it must be initialized via `PinInit`, if it is - // not structurally pinned, then it can be initialized via `Init`. - // - // The functions are `unsafe` to prevent accidentally calling them. + // type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be + // initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with + // `Unpinned` which allows initialization via `Init`. let field_accessors = fields .iter() .map(|f| { @@ -370,57 +369,29 @@ fn generate_the_pin_data( let field_name = ident .as_ref() .expect("only structs with named fields are supported"); - let project_ident = format_ident!("__project_{field_name}"); - let (init_ty, init_fn, project_ty, project_body, pin_safety) = if f.pinned { - ( - quote!(PinInit), - quote!(__pinned_init), - quote!(::core::pin::Pin<&'__slot mut #ty>), - // SAFETY: this field is structurally pinned. - quote!(unsafe { ::core::pin::Pin::new_unchecked(slot) }), - quote!( - /// - `slot` will not move until it is dropped, i.e. it will be pinned. - ), - ) + let pin_marker = if f.pinned { + quote!(Pinned) } else { - ( - quote!(Init), - quote!(__init), - quote!(&'__slot mut #ty), - quote!(slot), - quote!(), - ) + quote!(Unpinned) }; - let slot_safety = format!( - " `slot` points at the field `{field_name}` inside of `{struct_name}`, which is pinned.", - ); quote! { /// # Safety /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - #pin_safety - #(#attrs)* - #vis unsafe fn #field_name( - self, - slot: *mut #ty, - init: impl ::pin_init::#init_ty<#ty, E>, - ) -> ::core::result::Result<(), E> { - // SAFETY: this function has the same safety requirements as the __init function - // called below. - unsafe { ::pin_init::#init_ty::#init_fn(init, slot) } - } - - /// # Safety - /// - #[doc = #slot_safety] + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. #(#attrs)* - #vis unsafe fn #project_ident<'__slot>( + #[inline(always)] + #vis unsafe fn #field_name( self, - slot: &'__slot mut #ty, - ) -> #project_ty { - #project_body + slot: *mut #struct_name #ty_generics, + ) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> { + // SAFETY: + // - If `#pin_marker` is `Pinned`, the corresponding field is structurally + // pinned. + // - Other safety requirements follows the safety requirement. + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) } } } }) @@ -450,6 +421,16 @@ fn generate_the_pin_data( impl #impl_generics __ThePinData #ty_generics #whr { + /// Type inference helper function. + #[inline(always)] + #vis fn __make_closure<__F, __E>(self, f: __F) -> __F + where + __F: FnOnce(*mut #struct_name #ty_generics) -> + ::core::result::Result<::pin_init::__internal::InitOk, __E>, + { + f + } + #field_accessors } @@ -464,13 +445,6 @@ fn generate_the_pin_data( __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() } } } - - // SAFETY: TODO - unsafe impl #impl_generics ::pin_init::__internal::PinData for __ThePinData #ty_generics - #whr - { - type Datee = #struct_name #ty_generics; - } } } diff --git a/src/__internal.rs b/src/__internal.rs index e54d90a4..540add6c 100644 --- a/src/__internal.rs +++ b/src/__internal.rs @@ -113,30 +113,12 @@ impl InitOk { /// /// Only the `init` module is allowed to use this trait. pub unsafe trait HasPinData { - type PinData: PinData; + type PinData; #[expect(clippy::missing_safety_doc)] unsafe fn __pin_data() -> Self::PinData; } -/// Marker trait for pinning data of structs. -/// -/// # Safety -/// -/// Only the `init` module is allowed to use this trait. -pub unsafe trait PinData: Copy { - type Datee: ?Sized + HasPinData; - - /// Type inference helper function. - #[inline(always)] - fn make_closure(self, f: F) -> F - where - F: FnOnce(*mut Self::Datee) -> Result, - { - f - } -} - /// This trait is automatically implemented for every type. It aims to provide the same type /// inference help as `HasPinData`. /// @@ -144,30 +126,12 @@ pub unsafe trait PinData: Copy { /// /// Only the `init` module is allowed to use this trait. pub unsafe trait HasInitData { - type InitData: InitData; + type InitData; #[expect(clippy::missing_safety_doc)] unsafe fn __init_data() -> Self::InitData; } -/// Same function as `PinData`, but for arbitrary data. -/// -/// # Safety -/// -/// Only the `init` module is allowed to use this trait. -pub unsafe trait InitData: Copy { - type Datee: ?Sized + HasInitData; - - /// Type inference helper function. - #[inline(always)] - fn make_closure(self, f: F) -> F - where - F: FnOnce(*mut Self::Datee) -> Result, - { - f - } -} - pub struct AllData(PhantomInvariant); impl Clone for AllData { @@ -178,9 +142,15 @@ impl Clone for AllData { impl Copy for AllData {} -// SAFETY: TODO. -unsafe impl InitData for AllData { - type Datee = T; +impl AllData { + /// Type inference helper function. + #[inline(always)] + pub fn __make_closure(self, f: F) -> F + where + F: FnOnce(*mut T) -> Result, + { + f + } } // SAFETY: TODO. @@ -277,6 +247,87 @@ fn stack_init_reuse() { println!("{value:?}"); } +// Marker types that determines type of `DropGuard`'s let bindings. +pub struct Pinned; +pub struct Unpinned; + +/// Represent an uninitialized field. +/// +/// # Invariants +/// +/// - `ptr` is valid, properly aligned and points to uninitialized and exclusively accessed memory. +/// - If `P` is `Pinned`, then `ptr` is structurally pinned. +pub struct Slot { + ptr: *mut T, + _phantom: PhantomData

, +} + +impl Slot { + /// # Safety + /// + /// - `ptr` is valid, properly aligned and points to uninitialized and exclusively accessed + /// memory. + /// - If `P` is `Pinned`, then `ptr` is structurally pinned. + #[inline(always)] + pub unsafe fn new(ptr: *mut T) -> Self { + // INVARIANT: Per safety requirement. + Self { + ptr, + _phantom: PhantomData, + } + } + + /// Initialize the field by value. + #[inline(always)] + pub fn write(self, value: T) -> DropGuard + where + T: Sized, + { + // SAFETY: `self.ptr` is a valid and aligned pointer for write. + unsafe { self.ptr.write(value) } + // SAFETY: + // - `self.ptr` is valid and properly aligned per type invariant. + // - `*self.ptr` is initialized above and the ownership is transferred to the guard. + // - If `P` is `Pinned`, `self.ptr` is pinned. + unsafe { DropGuard::new(self.ptr) } + } +} + +impl Slot { + /// Initialize the field. + #[inline(always)] + pub fn init(self, init: impl Init) -> Result, E> { + // SAFETY: + // - `self.ptr` is valid and properly aligned. + // - when `Err` is returned, we also propagate the error without touching `slot`; + // also `self` is consumed so it cannot be touched further. + unsafe { init.__init(self.ptr)? }; + + // SAFETY: + // - `self.ptr` is valid and properly aligned per type invariant. + // - `*self.ptr` is initialized above and the ownership is transferred to the guard. + Ok(unsafe { DropGuard::new(self.ptr) }) + } +} + +impl Slot { + /// Initialize the field. + #[inline(always)] + pub fn init(self, init: impl PinInit) -> Result, E> { + // SAFETY: + // - `self.ptr` is valid and properly aligned. + // - when `Err` is returned, we also propagate the error without touching `ptr`; + // also `self` is consumed so it cannot be touched further. + // - the drop guard will not hand out `&mut` (only `Pin<&mut T>`). + unsafe { init.__pinned_init(self.ptr)? }; + + // SAFETY: + // - `self.ptr` is valid, properly aligned and pinned per type invariant. + // - `*self.ptr` is initialized above and the ownership is transferred to the guard. + Ok(unsafe { DropGuard::new(self.ptr) }) + } +} + /// When a value of this type is dropped, it drops a `T`. /// /// Can be forgotten to prevent the drop. @@ -285,11 +336,13 @@ fn stack_init_reuse() { /// /// - `ptr` is valid and properly aligned. /// - `*ptr` is initialized and owned by this guard. -pub struct DropGuard { +/// - if `P` is `Pinned`, `ptr` is pinned. +pub struct DropGuard { ptr: *mut T, + phantom: PhantomData

, } -impl DropGuard { +impl DropGuard { /// Creates a drop guard and transfer the ownership of the pointer content. /// /// The ownership is only relinguished if the guard is forgotten via [`core::mem::forget`]. @@ -298,12 +351,18 @@ impl DropGuard { /// /// - `ptr` is valid and properly aligned. /// - `*ptr` is initialized, and the ownership is transferred to this guard. + /// - if `P` is `Pinned`, `ptr` is pinned. #[inline] pub unsafe fn new(ptr: *mut T) -> Self { // INVARIANT: By safety requirement. - Self { ptr } + Self { + ptr, + phantom: PhantomData, + } } +} +impl DropGuard { /// Create a let binding for accessor use. #[inline] pub fn let_binding(&mut self) -> &mut T { @@ -312,7 +371,17 @@ impl DropGuard { } } -impl Drop for DropGuard { +impl DropGuard { + /// Create a let binding for accessor use. + #[inline] + pub fn let_binding(&mut self) -> Pin<&mut T> { + // SAFETY: `self.ptr` is valid, properly aligned, initialized, exclusively accessible and + // pinned per type invariant. + unsafe { Pin::new_unchecked(&mut *self.ptr) } + } +} + +impl Drop for DropGuard { #[inline] fn drop(&mut self) { // SAFETY: `self.ptr` is valid, properly aligned and `*self.ptr` is owned by this guard. diff --git a/src/lib.rs b/src/lib.rs index 4098c65d..c9e2cbe2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -867,12 +867,12 @@ pub use pin_init_internal::init; #[macro_export] macro_rules! assert_pinned { ($ty:ty, $field:ident, $field_ty:ty, inline) => { - let _ = move |ptr: *mut $field_ty| { - // SAFETY: This code is unreachable. - let data = unsafe { <$ty as $crate::__internal::HasPinData>::__pin_data() }; - let init = $crate::__internal::AlwaysFail::<$field_ty>::new(); - // SAFETY: This code is unreachable. - unsafe { data.$field(ptr, init) }.ok(); + // SAFETY: This code is unreachable. + let _ = move |ptr: *mut $ty| unsafe { + let data = <$ty as $crate::__internal::HasPinData>::__pin_data(); + _ = data + .$field(ptr) + .init($crate::__internal::AlwaysFail::<$field_ty>::new()); }; }; diff --git a/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr b/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr index f5d9ee7b..bc6ee146 100644 --- a/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr +++ b/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr @@ -5,14 +5,23 @@ error[E0308]: mismatched types | ------------------ the found opaque type ... 21 | pin_init!(Self { bar: Bar::new() }) - | --- ^^^^^^^^^^ expected `Bar`, found opaque type - | | - | arguments to this function are incorrect + | ----------------------^^^^^^^^^^--- + | | | + | | expected `Bar`, found opaque type + | arguments to this method are incorrect | = note: expected struct `Bar` found opaque type `impl pin_init::PinInit` -note: function defined here - --> $RUST/core/src/ptr/mod.rs +help: the return type of this call is `impl pin_init::PinInit` due to the type of the argument passed + --> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:9 | - | pub const unsafe fn write(dst: *mut T, src: T) { - | ^^^^^ +21 | pin_init!(Self { bar: Bar::new() }) + | ^^^^^^^^^^^^^^^^^^^^^^----------^^^ + | | + | this argument influences the return type of `write` +note: method defined here + --> src/__internal.rs + | + | pub fn write(self, value: T) -> DropGuard + | ^^^^^ + = 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/init/field_value_wrong_type.stderr b/tests/ui/compile-fail/init/field_value_wrong_type.stderr index f6470767..d506bf0b 100644 --- a/tests/ui/compile-fail/init/field_value_wrong_type.stderr +++ b/tests/ui/compile-fail/init/field_value_wrong_type.stderr @@ -2,12 +2,21 @@ error[E0308]: mismatched types --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28 | 8 | let _ = init!(Foo { a: () }); - | - ^^ expected `usize`, found `()` - | | - | arguments to this function are incorrect + | ---------------^^--- + | | | + | | expected `usize`, found `()` + | arguments to this method are incorrect | -note: function defined here - --> $RUST/core/src/ptr/mod.rs +help: the return type of this call is `()` due to the type of the argument passed + --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:13 | - | pub const unsafe fn write(dst: *mut T, src: T) { - | ^^^^^ +8 | let _ = init!(Foo { a: () }); + | ^^^^^^^^^^^^^^^--^^^ + | | + | this argument influences the return type of `write` +note: method defined here + --> src/__internal.rs + | + | pub fn write(self, value: T) -> DropGuard + | ^^^^^ + = note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/invalid_init.stderr b/tests/ui/compile-fail/init/invalid_init.stderr index dd317b60..137c1fae 100644 --- a/tests/ui/compile-fail/init/invalid_init.stderr +++ b/tests/ui/compile-fail/init/invalid_init.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not satisfied +error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not satisfied --> tests/ui/compile-fail/init/invalid_init.rs:19:16 | 18 | let _ = init!(Foo { | _____________- 19 | | bar <- Bar::new(), - | | ^^^^^^^^^^ the trait `Init` is not implemented for `impl pin_init::PinInit` + | | ^^^^^^^^^^ the trait `Init` is not implemented for `impl pin_init::PinInit` 20 | | }); | |______- required by a bound introduced by this call | @@ -19,3 +19,8 @@ help: the following other types implement trait `Init` ... | unsafe impl Init for Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Result` +note: required by a bound in `pin_init::__internal::Slot::::init` + --> src/__internal.rs + | + | pub fn init(self, init: impl Init) -> Result, E> { + | ^^^^^^^^^^ required by this bound in `Slot::::init` diff --git a/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr b/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr index 865615d2..a2978266 100644 --- a/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr +++ b/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr @@ -1,18 +1,30 @@ error[E0308]: mismatched types --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:12:12 | -12 | a: 0..Zeroable::init_zeroed() - | - ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Range<{integer}>` - | | - | arguments to this function are incorrect +11 | let _ = init!(Foo { + | _____________- +12 | | a: 0..Zeroable::init_zeroed() + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Range<{integer}>` +13 | | }); + | |______- arguments to this method are incorrect | = note: expected type `usize` found struct `std::ops::Range<{integer}>` -note: function defined here - --> $RUST/core/src/ptr/mod.rs +help: the return type of this call is `std::ops::Range<{integer}>` due to the type of the argument passed + --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:13 | - | pub const unsafe fn write(dst: *mut T, src: T) { - | ^^^^^ +11 | let _ = init!(Foo { + | _____________^ +12 | | a: 0..Zeroable::init_zeroed() + | | -------------------------- this argument influences the return type of `write` +13 | | }); + | |______^ +note: method defined here + --> src/__internal.rs + | + | pub fn write(self, value: T) -> DropGuard + | ^^^^^ + = note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0063]: missing field `b` in initializer of `Foo` --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:19 diff --git a/tests/ui/compile-fail/init/shadowing_field.stderr b/tests/ui/compile-fail/init/shadowing_field.stderr index d9ba3f59..af21f62a 100644 --- a/tests/ui/compile-fail/init/shadowing_field.stderr +++ b/tests/ui/compile-fail/init/shadowing_field.stderr @@ -2,15 +2,24 @@ error[E0308]: mismatched types --> tests/ui/compile-fail/init/shadowing_field.rs:10:31 | 10 | let _ = init!(Foo { x, y: x }); - | - ^ expected `usize`, found `&mut usize` - | | - | arguments to this function are incorrect + | ------------------^--- + | | | + | | expected `usize`, found `&mut usize` + | arguments to this method are incorrect | -note: function defined here - --> $RUST/core/src/ptr/mod.rs +help: the return type of this call is `&mut usize` due to the type of the argument passed + --> tests/ui/compile-fail/init/shadowing_field.rs:10:13 | - | pub const unsafe fn write(dst: *mut T, src: T) { - | ^^^^^ +10 | let _ = init!(Foo { x, y: x }); + | ^^^^^^^^^^^^^^^^^^-^^^ + | | + | this argument influences the return type of `write` +note: method defined here + --> src/__internal.rs + | + | pub fn write(self, value: T) -> DropGuard + | ^^^^^ + = note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider dereferencing the borrow | 10 | let _ = init!(Foo { x, y: *x }); diff --git a/tests/ui/compile-fail/pin_data/missing_pin.stderr b/tests/ui/compile-fail/pin_data/missing_pin.stderr index 3985b4b1..1ebbbdbf 100644 --- a/tests/ui/compile-fail/pin_data/missing_pin.stderr +++ b/tests/ui/compile-fail/pin_data/missing_pin.stderr @@ -1,10 +1,11 @@ error[E0277]: the trait bound `impl PinInit: Init` is not satisfied --> tests/ui/compile-fail/pin_data/missing_pin.rs:12:18 | -12 | a <- a, - | - ^ the trait `Init` is not implemented for `impl PinInit` - | | - | required by a bound introduced by this call +11 | / pin_init!(Self { +12 | | a <- a, + | | ^ the trait `Init` is not implemented for `impl PinInit` +13 | | }) + | |__________- required by a bound introduced by this call | help: the trait `Init` is not implemented for `impl PinInit` but trait `Init, Infallible>` is implemented for it @@ -13,12 +14,8 @@ help: the trait `Init` is not implemented for `impl PinInit` | unsafe impl Init for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `impl PinInit`, found `usize` -note: required by a bound in `__ThePinData::a` - --> tests/ui/compile-fail/pin_data/missing_pin.rs:4:1 +note: required by a bound in `pin_init::__internal::Slot::::init` + --> src/__internal.rs | - 4 | #[pin_data] - | ^^^^^^^^^^^ required by this bound in `__ThePinData::a` - 5 | struct Foo { - 6 | a: usize, - | - required by a bound in this associated function - = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + | pub fn init(self, init: impl Init) -> Result, E> { + | ^^^^^^^^^^ required by this bound in `Slot::::init` diff --git a/tests/ui/expand/many_generics.expanded.rs b/tests/ui/expand/many_generics.expanded.rs index adc83d80..1b0642fb 100644 --- a/tests/ui/expand/many_generics.expanded.rs +++ b/tests/ui/expand/many_generics.expanded.rs @@ -82,69 +82,63 @@ const _: () = { where T: Bar<'a, 1>, { - /// # Safety - /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - unsafe fn array( - self, - slot: *mut [u8; 1024 * 1024], - init: impl ::pin_init::Init<[u8; 1024 * 1024], E>, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::Init::__init(init, slot) } - } - /// # Safety - /// - /// `slot` points at the field `array` inside of `Foo`, which is pinned. - unsafe fn __project_array<'__slot>( - self, - slot: &'__slot mut [u8; 1024 * 1024], - ) -> &'__slot mut [u8; 1024 * 1024] { - slot - } - /// # Safety - /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - unsafe fn r( - self, - slot: *mut &'b mut [&'a mut T; SIZE], - init: impl ::pin_init::Init<&'b mut [&'a mut T; SIZE], E>, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::Init::__init(init, slot) } + /// Type inference helper function. + #[inline(always)] + fn __make_closure<__F, __E>(self, f: __F) -> __F + where + __F: FnOnce( + *mut Foo<'a, 'b, T, SIZE>, + ) -> ::core::result::Result<::pin_init::__internal::InitOk, __E>, + { + f } /// # Safety /// - /// `slot` points at the field `r` inside of `Foo`, which is pinned. - unsafe fn __project_r<'__slot>( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn array( self, - slot: &'__slot mut &'b mut [&'a mut T; SIZE], - ) -> &'__slot mut &'b mut [&'a mut T; SIZE] { - slot + slot: *mut Foo<'a, 'b, T, SIZE>, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Unpinned, + [u8; 1024 * 1024], + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) } } /// # Safety /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - /// - `slot` will not move until it is dropped, i.e. it will be pinned. - unsafe fn _pin( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn r( self, - slot: *mut PhantomPinned, - init: impl ::pin_init::PinInit, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } + slot: *mut Foo<'a, 'b, T, SIZE>, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Unpinned, + &'b mut [&'a mut T; SIZE], + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).r) } } /// # Safety /// - /// `slot` points at the field `_pin` inside of `Foo`, which is pinned. - unsafe fn __project__pin<'__slot>( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn _pin( self, - slot: &'__slot mut PhantomPinned, - ) -> ::core::pin::Pin<&'__slot mut PhantomPinned> { - unsafe { ::core::pin::Pin::new_unchecked(slot) } + slot: *mut Foo<'a, 'b, T, SIZE>, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Pinned, + PhantomPinned, + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) } } } unsafe impl< @@ -163,17 +157,6 @@ const _: () = { } } } - unsafe impl< - 'a, - 'b: 'a, - T: Bar<'b> + ?Sized + 'a, - const SIZE: usize, - > ::pin_init::__internal::PinData for __ThePinData<'a, 'b, T, SIZE> - where - T: Bar<'a, 1>, - { - type Datee = Foo<'a, 'b, T, SIZE>; - } #[allow(dead_code)] struct __Unpin<'__pin, 'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> where diff --git a/tests/ui/expand/pin-data.expanded.rs b/tests/ui/expand/pin-data.expanded.rs index 05c9a119..e79642cd 100644 --- a/tests/ui/expand/pin-data.expanded.rs +++ b/tests/ui/expand/pin-data.expanded.rs @@ -46,48 +46,47 @@ const _: () = { #[allow(dead_code)] #[expect(clippy::missing_safety_doc)] impl __ThePinData { - /// # Safety - /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - unsafe fn array( - self, - slot: *mut [u8; 1024 * 1024], - init: impl ::pin_init::Init<[u8; 1024 * 1024], E>, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::Init::__init(init, slot) } - } - /// # Safety - /// - /// `slot` points at the field `array` inside of `Foo`, which is pinned. - unsafe fn __project_array<'__slot>( - self, - slot: &'__slot mut [u8; 1024 * 1024], - ) -> &'__slot mut [u8; 1024 * 1024] { - slot + /// Type inference helper function. + #[inline(always)] + fn __make_closure<__F, __E>(self, f: __F) -> __F + where + __F: FnOnce( + *mut Foo, + ) -> ::core::result::Result<::pin_init::__internal::InitOk, __E>, + { + f } /// # Safety /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - /// - `slot` will not move until it is dropped, i.e. it will be pinned. - unsafe fn _pin( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn array( self, - slot: *mut PhantomPinned, - init: impl ::pin_init::PinInit, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } + slot: *mut Foo, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Unpinned, + [u8; 1024 * 1024], + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) } } /// # Safety /// - /// `slot` points at the field `_pin` inside of `Foo`, which is pinned. - unsafe fn __project__pin<'__slot>( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn _pin( self, - slot: &'__slot mut PhantomPinned, - ) -> ::core::pin::Pin<&'__slot mut PhantomPinned> { - unsafe { ::core::pin::Pin::new_unchecked(slot) } + slot: *mut Foo, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Pinned, + PhantomPinned, + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) } } } unsafe impl ::pin_init::__internal::HasPinData for Foo { @@ -98,9 +97,6 @@ const _: () = { } } } - unsafe impl ::pin_init::__internal::PinData for __ThePinData { - type Datee = Foo; - } #[allow(dead_code)] struct __Unpin<'__pin> { __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>, diff --git a/tests/ui/expand/pinned_drop.expanded.rs b/tests/ui/expand/pinned_drop.expanded.rs index 14bbd84e..0f1893c2 100644 --- a/tests/ui/expand/pinned_drop.expanded.rs +++ b/tests/ui/expand/pinned_drop.expanded.rs @@ -46,48 +46,47 @@ const _: () = { #[allow(dead_code)] #[expect(clippy::missing_safety_doc)] impl __ThePinData { - /// # Safety - /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - unsafe fn array( - self, - slot: *mut [u8; 1024 * 1024], - init: impl ::pin_init::Init<[u8; 1024 * 1024], E>, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::Init::__init(init, slot) } - } - /// # Safety - /// - /// `slot` points at the field `array` inside of `Foo`, which is pinned. - unsafe fn __project_array<'__slot>( - self, - slot: &'__slot mut [u8; 1024 * 1024], - ) -> &'__slot mut [u8; 1024 * 1024] { - slot + /// Type inference helper function. + #[inline(always)] + fn __make_closure<__F, __E>(self, f: __F) -> __F + where + __F: FnOnce( + *mut Foo, + ) -> ::core::result::Result<::pin_init::__internal::InitOk, __E>, + { + f } /// # Safety /// - /// - `slot` is a valid pointer to uninitialized memory. - /// - the caller does not touch `slot` when `Err` is returned, they are only - /// permitted to deallocate. - /// - `slot` will not move until it is dropped, i.e. it will be pinned. - unsafe fn _pin( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn array( self, - slot: *mut PhantomPinned, - init: impl ::pin_init::PinInit, - ) -> ::core::result::Result<(), E> { - unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } + slot: *mut Foo, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Unpinned, + [u8; 1024 * 1024], + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).array) } } /// # Safety /// - /// `slot` points at the field `_pin` inside of `Foo`, which is pinned. - unsafe fn __project__pin<'__slot>( + /// - `slot` is valid and properly aligned. + /// - `(*slot).#field_name` is properly aligned. + /// - `(*slot).#field_name` points to uninitialized and exclusively accessed + /// memory. + #[inline(always)] + unsafe fn _pin( self, - slot: &'__slot mut PhantomPinned, - ) -> ::core::pin::Pin<&'__slot mut PhantomPinned> { - unsafe { ::core::pin::Pin::new_unchecked(slot) } + slot: *mut Foo, + ) -> ::pin_init::__internal::Slot< + ::pin_init::__internal::Pinned, + PhantomPinned, + > { + unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot)._pin) } } } unsafe impl ::pin_init::__internal::HasPinData for Foo { @@ -98,9 +97,6 @@ const _: () = { } } } - unsafe impl ::pin_init::__internal::PinData for __ThePinData { - type Datee = Foo; - } #[allow(dead_code)] struct __Unpin<'__pin> { __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>, diff --git a/tests/ui/expand/simple-init.expanded.rs b/tests/ui/expand/simple-init.expanded.rs index f3411bc9..ee3d0096 100644 --- a/tests/ui/expand/simple-init.expanded.rs +++ b/tests/ui/expand/simple-init.expanded.rs @@ -6,17 +6,15 @@ fn main() { use ::pin_init::__internal::HasInitData; Foo::__init_data() }; - let init = ::pin_init::__internal::InitData::make_closure::< - _, - ::core::convert::Infallible, - >( - __data, - move |slot| { + let init = __data + .__make_closure::< + _, + ::core::convert::Infallible, + >(move |slot| { #[allow(unreachable_code, clippy::diverging_sub_expression)] let _ = || unsafe { ::core::ptr::write(slot, Foo {}) }; Ok(unsafe { ::pin_init::__internal::InitOk::new() }) - }, - ); + }); let init = move | slot, | -> ::core::result::Result<(), ::core::convert::Infallible> {