summaryrefslogtreecommitdiff
path: root/rust/pin-init/internal/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/pin-init/internal/src')
-rw-r--r--rust/pin-init/internal/src/diagnostics.rs14
-rw-r--r--rust/pin-init/internal/src/init.rs263
-rw-r--r--rust/pin-init/internal/src/lib.rs1
-rw-r--r--rust/pin-init/internal/src/pin_data.rs268
-rw-r--r--rust/pin-init/internal/src/zeroable.rs2
5 files changed, 243 insertions, 305 deletions
diff --git a/rust/pin-init/internal/src/diagnostics.rs b/rust/pin-init/internal/src/diagnostics.rs
index 3bdb477c2f2b..c7d9b3e624fc 100644
--- a/rust/pin-init/internal/src/diagnostics.rs
+++ b/rust/pin-init/internal/src/diagnostics.rs
@@ -3,6 +3,7 @@
use std::fmt::Display;
use proc_macro2::TokenStream;
+use quote::quote_spanned;
use syn::{spanned::Spanned, Error};
pub(crate) struct DiagCtxt(TokenStream);
@@ -15,6 +16,19 @@ impl DiagCtxt {
ErrorGuaranteed(())
}
+ pub(crate) fn warn(&mut self, span: impl Spanned, msg: impl Display) {
+ // Have the message start on a new line for visual clarity.
+ let msg = format!("\n{}", msg);
+ self.0.extend(quote_spanned!(span.span() =>
+ // Approximate using deprecated warning while `proc_macro_diagnostic` is unstable.
+ const _: () = {
+ #[deprecated = #msg]
+ const fn warn() {}
+ warn();
+ };
+ ));
+ }
+
pub(crate) fn with(
fun: impl FnOnce(&mut DiagCtxt) -> Result<TokenStream, ErrorGuaranteed>,
) -> TokenStream {
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index daa3f1c6466e..28d30805d06b 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/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
@@ -172,14 +169,7 @@ pub(crate) fn expand(
init(slot).map(|__InitOk| ())
};
// SAFETY: TODO
- let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
- // FIXME: this let binding is required to avoid a compiler error (cycle when computing the
- // opaque type returned by this function) before Rust 1.81. Remove after MSRV bump.
- #[allow(
- clippy::let_and_return,
- reason = "some clippy versions warn about the let binding"
- )]
- init
+ unsafe { ::pin_init::#init_from_closure::<_, #error>(init) }
}})
}
@@ -238,123 +228,82 @@ 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);
- // NOTE: the field accessor ensures that the initialized field is properly aligned.
- // Unaligned fields will cause the compiler to emit E0793. We do not support
- // unaligned fields since `Init::__init` requires an aligned pointer; the call to
- // `ptr::write` below has the same requirement.
- let accessor = if pinned {
- let project_ident = format_ident!("__project_{ident}");
- quote! {
- // SAFETY: TODO
- unsafe { #data.#project_ident(&mut (*#slot).#ident) }
- }
- } else {
- quote! {
- // SAFETY: TODO
- unsafe { &mut (*#slot).#ident }
- }
- };
+ 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) };
- }
- #(#cfgs)*
- #[allow(unused_variables)]
- let #ident = #accessor;
+ let mut #guard = #slot.write(#value);
+
}
}
- InitializerKind::Init { ident, value, .. } => {
- // Again span for better diagnostics
- let init = format_ident!("init", span = value.span());
- // NOTE: the field accessor ensures that the initialized field is properly aligned.
- // Unaligned fields will cause the compiler to emit E0793. We do not support
- // unaligned fields since `Init::__init` requires an aligned pointer; the call to
- // `ptr::write` below has the same requirement.
- let (value_init, accessor) = if pinned {
- let project_ident = format_ident!("__project_{ident}");
- (
- 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)? };
- },
- quote! {
- // SAFETY: TODO
- unsafe { #data.#project_ident(&mut (*#slot).#ident) }
- },
- )
- } 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,
- )?
- };
- },
- quote! {
- // SAFETY: TODO
- unsafe { &mut (*#slot).#ident }
- },
- )
- };
+ InitializerKind::Init { value, .. } => {
quote! {
#(#attrs)*
- {
- let #init = #value;
- #value_init
- }
- #(#cfgs)*
- #[allow(unused_variables)]
- let #ident = #accessor;
+ 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());
- res.extend(quote! {
- #(#cfgs)*
- // Create the drop guard:
- //
- // We rely on macro hygiene to make it impossible for users to access this local
- // variable.
- // SAFETY: We forget the guard later when initialization has succeeded.
- let #guard = unsafe {
- ::pin_init::__internal::DropGuard::new(
- &raw mut (*slot).#ident
- )
- };
- });
- guards.push(guard);
- guard_attrs.push(cfgs);
- }
+
+ res.extend(quote! {
+ #init
+
+ #(#cfgs)*
+ // Allow `non_snake_case` since the same warning is going to be reported for the struct
+ // field.
+ #[allow(unused_variables, non_snake_case)]
+ let #ident = #guard.let_binding();
+ });
+
+ guards.push(guard);
+ guard_attrs.push(cfgs);
}
quote! {
#res
@@ -367,49 +316,49 @@ fn init_fields(
}
}
-/// Generate the check for ensuring that every field has been initialized.
+/// Generate the check for ensuring that every field has been initialized and aligned.
fn make_field_check(
fields: &Punctuated<InitializerField, Token![,]>,
init_kind: InitKind,
path: &Path,
) -> TokenStream {
- let field_attrs = fields
+ let field_attrs: Vec<_> = fields
.iter()
- .filter_map(|f| f.kind.ident().map(|_| &f.attrs));
- let field_name = fields.iter().filter_map(|f| f.kind.ident());
- match init_kind {
- InitKind::Normal => quote! {
- // We use unreachable code to ensure that all fields have been mentioned exactly once,
- // this struct initializer will still be type-checked and complain with a very natural
- // error message if a field is forgotten/mentioned more than once.
- #[allow(unreachable_code, clippy::diverging_sub_expression)]
- // SAFETY: this code is never executed.
- let _ = || unsafe {
- ::core::ptr::write(slot, #path {
- #(
- #(#field_attrs)*
- #field_name: ::core::panic!(),
- )*
- })
- };
- },
- InitKind::Zeroing => quote! {
- // We use unreachable code to ensure that all fields have been mentioned at most once.
- // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
- // be zeroed. This struct initializer will still be type-checked and complain with a
- // very natural error message if a field is mentioned more than once, or doesn't exist.
- #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
- // SAFETY: this code is never executed.
- let _ = || unsafe {
- ::core::ptr::write(slot, #path {
- #(
- #(#field_attrs)*
- #field_name: ::core::panic!(),
- )*
- ..::core::mem::zeroed()
- })
- };
- },
+ .filter_map(|f| f.kind.ident().map(|_| &f.attrs))
+ .collect();
+ let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.ident()).collect();
+ let zeroing_trailer = match init_kind {
+ InitKind::Normal => None,
+ InitKind::Zeroing => Some(quote! {
+ ..::core::mem::zeroed()
+ }),
+ };
+ quote! {
+ #[allow(unreachable_code, clippy::diverging_sub_expression)]
+ // We use unreachable code to perform field checks. They're still checked by the compiler.
+ // SAFETY: this code is never executed.
+ let _ = || unsafe {
+ // Create references to ensure that the initialized field is properly aligned.
+ // Unaligned fields will cause the compiler to emit E0793. We do not support
+ // unaligned fields since `Init::__init` requires an aligned pointer; the call to
+ // `ptr::write` for value-initialization case has the same requirement.
+ #(
+ #(#field_attrs)*
+ let _ = &(*slot).#field_name;
+ )*
+
+ // If the zeroing trailer is not present, this checks that all fields have been
+ // mentioned exactly once. If the zeroing trailer is present, all missing fields will be
+ // zeroed, so this checks that all fields have been mentioned at most once. The use of
+ // struct initializer will still generate very natural error messages for any misuse.
+ ::core::ptr::write(slot, #path {
+ #(
+ #(#field_attrs)*
+ #field_name: loop {},
+ )*
+ #zeroing_trailer
+ })
+ };
}
}
diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs
index b08dfe003031..60d5093f3128 100644
--- a/rust/pin-init/internal/src/lib.rs
+++ b/rust/pin-init/internal/src/lib.rs
@@ -6,7 +6,6 @@
//! `pin-init` proc macros.
-#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
// Documentation is done in the pin-init crate instead.
#![allow(missing_docs)]
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
index 7d871236b49c..9fbbd25bcaac 100644
--- a/rust/pin-init/internal/src/pin_data.rs
+++ b/rust/pin-init/internal/src/pin_data.rs
@@ -7,7 +7,7 @@ use syn::{
parse_quote, parse_quote_spanned,
spanned::Spanned,
visit_mut::VisitMut,
- Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,
+ Attribute, Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,
};
use crate::diagnostics::{DiagCtxt, ErrorGuaranteed};
@@ -35,6 +35,12 @@ impl Parse for Args {
}
}
+struct FieldInfo<'a> {
+ field: &'a Field,
+ pinned: bool,
+ cfg_attrs: Vec<&'a Attribute>,
+}
+
pub(crate) fn pin_data(
args: Args,
input: Item,
@@ -73,24 +79,37 @@ pub(crate) fn pin_data(
replacer.visit_generics_mut(&mut struct_.generics);
replacer.visit_fields_mut(&mut struct_.fields);
- let fields: Vec<(bool, &Field)> = struct_
+ let fields: Vec<FieldInfo<'_>> = struct_
.fields
.iter_mut()
.map(|field| {
let len = field.attrs.len();
field.attrs.retain(|a| !a.path().is_ident("pin"));
- (len != field.attrs.len(), &*field)
+ let pinned = len != field.attrs.len();
+
+ let cfg_attrs = field
+ .attrs
+ .iter()
+ .filter(|a| a.path().is_ident("cfg"))
+ .collect();
+
+ FieldInfo {
+ field: &*field,
+ pinned,
+ cfg_attrs,
+ }
})
.collect();
- for (pinned, field) in &fields {
- if !pinned && is_phantom_pinned(&field.ty) {
- dcx.error(
- field,
+ for field in &fields {
+ let ident = field.field.ident.as_ref().unwrap();
+
+ if !field.pinned && is_phantom_pinned(&field.field.ty) {
+ dcx.warn(
+ field.field,
format!(
- "The field `{}` of type `PhantomPinned` only has an effect \
+ "The field `{ident}` of type `PhantomPinned` only has an effect \
if it has the `#[pin]` attribute",
- field.ident.as_ref().unwrap(),
),
);
}
@@ -143,7 +162,7 @@ fn is_phantom_pinned(ty: &Type) -> bool {
fn generate_unpin_impl(
ident: &Ident,
generics: &Generics,
- fields: &[(bool, &Field)],
+ fields: &[FieldInfo<'_>],
) -> TokenStream {
let (_, ty_generics, _) = generics.split_for_impl();
let mut generics_with_pin_lt = generics.clone();
@@ -160,19 +179,28 @@ fn generate_unpin_impl(
else {
unreachable!()
};
- let pinned_fields = fields.iter().filter_map(|(b, f)| b.then_some(f));
+ let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| {
+ let ident = f.field.ident.as_ref().unwrap();
+ let ty = &f.field.ty;
+ let cfg_attrs = &f.cfg_attrs;
+ quote!(
+ #(#cfg_attrs)*
+ #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`.
- #[allow(dead_code)] // The fields below are never used.
+ #[allow(
+ dead_code, // The fields below are never used.
+ non_snake_case // The warning will be emitted on the struct definition.
+ )]
struct __Unpin #generics_with_pin_lt
#where_token
#predicates
{
- __phantom_pin: ::core::marker::PhantomData<fn(&'__pin ()) -> &'__pin ()>,
- __phantom: ::core::marker::PhantomData<
- fn(#ident #ty_generics) -> #ident #ty_generics
- >,
+ __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>,
+ __phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>,
#(#pinned_fields),*
}
@@ -238,7 +266,7 @@ fn generate_projections(
vis: &Visibility,
ident: &Ident,
generics: &Generics,
- fields: &[(bool, &Field)],
+ fields: &[FieldInfo<'_>],
) -> TokenStream {
let (impl_generics, ty_generics, _) = generics.split_for_impl();
let mut generics_with_pin_lt = generics.clone();
@@ -247,32 +275,23 @@ fn generate_projections(
let projection = format_ident!("{ident}Projection");
let this = format_ident!("this");
- let (fields_decl, fields_proj) = collect_tuple(fields.iter().map(
- |(
- pinned,
- Field {
- vis,
- ident,
- ty,
- attrs,
- ..
- },
- )| {
- let mut attrs = attrs.clone();
- attrs.retain(|a| !a.path().is_ident("pin"));
- let mut no_doc_attrs = attrs.clone();
- no_doc_attrs.retain(|a| !a.path().is_ident("doc"));
+ let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields
+ .iter()
+ .map(|field| {
+ let Field { vis, ident, ty, .. } = &field.field;
+ let cfg_attrs = &field.cfg_attrs;
+
let ident = ident
.as_ref()
.expect("only structs with named fields are supported");
- if *pinned {
+ if field.pinned {
(
quote!(
- #(#attrs)*
+ #(#cfg_attrs)*
#vis #ident: ::core::pin::Pin<&'__pin mut #ty>,
),
quote!(
- #(#no_doc_attrs)*
+ #(#cfg_attrs)*
// SAFETY: this field is structurally pinned.
#ident: unsafe { ::core::pin::Pin::new_unchecked(&mut #this.#ident) },
),
@@ -280,31 +299,35 @@ fn generate_projections(
} else {
(
quote!(
- #(#attrs)*
+ #(#cfg_attrs)*
#vis #ident: &'__pin mut #ty,
),
quote!(
- #(#no_doc_attrs)*
+ #(#cfg_attrs)*
#ident: &mut #this.#ident,
),
)
}
- },
- ));
+ })
+ .collect();
let structurally_pinned_fields_docs = fields
.iter()
- .filter_map(|(pinned, field)| pinned.then_some(field))
- .map(|Field { ident, .. }| format!(" - `{}`", ident.as_ref().unwrap()));
+ .filter(|f| f.pinned)
+ .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
let not_structurally_pinned_fields_docs = fields
.iter()
- .filter_map(|(pinned, field)| (!pinned).then_some(field))
- .map(|Field { ident, .. }| format!(" - `{}`", ident.as_ref().unwrap()));
+ .filter(|f| !f.pinned)
+ .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
let docs = format!(" Pin-projections of [`{ident}`]");
quote! {
#[doc = #docs]
- #[allow(dead_code)]
+ // Allow `non_snake_case` since the same warning will be emitted on
+ // the struct definition.
+ #[allow(dead_code, non_snake_case)]
#[doc(hidden)]
- #vis struct #projection #generics_with_pin_lt {
+ #vis struct #projection #generics_with_pin_lt
+ #whr
+ {
#(#fields_decl)*
___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>,
}
@@ -336,91 +359,54 @@ fn generate_projections(
fn generate_the_pin_data(
vis: &Visibility,
- ident: &Ident,
+ struct_name: &Ident,
generics: &Generics,
- fields: &[(bool, &Field)],
+ fields: &[FieldInfo<'_>],
) -> TokenStream {
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.
- fn handle_field(
- Field {
- vis,
- ident,
- ty,
- attrs,
- ..
- }: &Field,
- struct_ident: &Ident,
- pinned: bool,
- ) -> TokenStream {
- let mut attrs = attrs.clone();
- attrs.retain(|a| !a.path().is_ident("pin"));
- let ident = ident
- .as_ref()
- .expect("only structs with named fields are supported");
- let project_ident = format_ident!("__project_{ident}");
- let (init_ty, init_fn, project_ty, project_body, pin_safety) = if 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.
- ),
- )
- } else {
- (
- quote!(Init),
- quote!(__init),
- quote!(&'__slot mut #ty),
- quote!(slot),
- quote!(),
- )
- };
- let slot_safety = format!(
- " `slot` points at the field `{ident}` inside of `{struct_ident}`, 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 #ident<E>(
- 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]
- #(#attrs)*
- #vis unsafe fn #project_ident<'__slot>(
- self,
- slot: &'__slot mut #ty,
- ) -> #project_ty {
- #project_body
- }
- }
- }
-
+ // 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(|(pinned, field)| handle_field(field, ident, *pinned))
+ .map(|f| {
+ let Field { vis, ident, ty, .. } = f.field;
+ let cfg_attrs = &f.cfg_attrs;
+
+ let field_name = ident
+ .as_ref()
+ .expect("only structs with named fields are supported");
+ let pin_marker = if f.pinned {
+ quote!(Pinned)
+ } else {
+ quote!(Unpinned)
+ };
+ quote! {
+ /// # Safety
+ ///
+ /// - `slot` is valid and properly aligned.
+ /// - `(*slot).#field_name` is properly aligned.
+ /// - `(*slot).#field_name` points to uninitialized and exclusively accessed
+ /// memory.
+ #(#cfg_attrs)*
+ // Allow `non_snake_case` since the same warning will be emitted on
+ // the struct definition.
+ #[allow(non_snake_case)]
+ #[inline(always)]
+ #vis unsafe fn #field_name(
+ self,
+ 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) }
+ }
+ }
+ })
.collect::<TokenStream>();
quote! {
// We declare this struct which will host all of the projection function for our type. It
@@ -429,9 +415,7 @@ fn generate_the_pin_data(
#vis struct __ThePinData #generics
#whr
{
- __phantom: ::core::marker::PhantomData<
- fn(#ident #ty_generics) -> #ident #ty_generics
- >,
+ __phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>,
}
impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics
@@ -449,27 +433,30 @@ 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
}
// SAFETY: We have added the correct projection functions above to `__ThePinData` and
// we also use the least restrictive generics possible.
- unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #ident #ty_generics
+ unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics
#whr
{
type PinData = __ThePinData #ty_generics;
unsafe fn __pin_data() -> Self::PinData {
- __ThePinData { __phantom: ::core::marker::PhantomData }
+ __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() }
}
}
-
- // SAFETY: TODO
- unsafe impl #impl_generics ::pin_init::__internal::PinData for __ThePinData #ty_generics
- #whr
- {
- type Datee = #ident #ty_generics;
- }
}
}
@@ -500,14 +487,3 @@ impl VisitMut for SelfReplacer {
// Do not descend into items, since items reset/change what `Self` refers to.
}
}
-
-// replace with `.collect()` once MSRV is above 1.79
-fn collect_tuple<A, B>(iter: impl Iterator<Item = (A, B)>) -> (Vec<A>, Vec<B>) {
- let mut res_a = vec![];
- let mut res_b = vec![];
- for (a, b) in iter {
- res_a.push(a);
- res_b.push(b);
- }
- (res_a, res_b)
-}
diff --git a/rust/pin-init/internal/src/zeroable.rs b/rust/pin-init/internal/src/zeroable.rs
index 05683319b0f7..b11feaeb1ca6 100644
--- a/rust/pin-init/internal/src/zeroable.rs
+++ b/rust/pin-init/internal/src/zeroable.rs
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: Apache-2.0 OR MIT
use proc_macro2::TokenStream;
use quote::quote;