diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs index 36678843251c..a3e492c455da 100644 --- a/rust/pin-init/internal/src/pin_data.rs +++ b/rust/pin-init/internal/src/pin_data.rs @@ -433,6 +433,10 @@ fn generate_struct_def(info: &StructInfo) -> TokenStream { ty = quote!(::pin_init::__internal::Erase<#ty>); }; + if field.borrowed.is_some() { + ty = quote!(::pin_init::__internal::Borrowed<#ty>); + } + quote! { #(#attrs)* #vis #ident #colon_token #ty } @@ -468,6 +472,20 @@ fn generate_unpin_impl(info: &StructInfo) -> TokenStream { .map(|x| &x.predicates) .unwrap_or(const { &Punctuated::new() }); + if info.self_referential { + // Self-referential structs must always be pinned. + return quote! { + #[doc(hidden)] + impl #impl_generics ::core::marker::Unpin for #ident #ty_generics + where + // the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds` + // feature . + for<'__dummy> ::core::marker::PhantomPinned: ::core::marker::Unpin, + #predicates + {} + }; + } + let pinned_fields = info.fields.iter().filter(|f| f.pinned).map(|f| { let ident = f.member.as_ident(); let ty = &f.field.ty; @@ -475,6 +493,7 @@ fn generate_unpin_impl(info: &StructInfo) -> TokenStream { #ident: #ty ) }); + quote! { // This struct will be used for the unpin analysis. It is needed, because only structurally // pinned fields are relevant whether the struct should implement `Unpin`. diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs index 0a8247473cbc..74dc23506d97 100644 --- a/rust/pin-init/src/__internal.rs +++ b/rust/pin-init/src/__internal.rs @@ -5,6 +5,9 @@ //! These items must not be used outside of this crate and the pin-init-internal crate located at //! `../internal`. +use core::marker::PhantomPinned; +use core::ops::Deref; + use super::*; /// Zero-sized type used to mark a type as invariant. @@ -462,3 +465,19 @@ unsafe impl Sync for Erase for<'a> Erase<>::Output>: Sync, { } + +/// Wrapper for borrowed fields. +/// +/// This should be switched to `UnsafePinned` when it is stable. +/// NOTE: This type needs to be covariant; Rust's 1.89+'s `UnsafePinned` is invariant. +#[repr(transparent)] +pub struct Borrowed(PhantomPinned, T); + +impl Deref for Borrowed { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.1 + } +}