From nobody Mon Feb 9 07:20:54 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2913D47DD7B; Thu, 8 Jan 2026 13:53:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767880399; cv=none; b=SBtiMmHKKwCsyISLdD+tJ7qd3NutJ6qMhhBAZ1Ngkwzm71JaoMBnmg4U3XXX+/8ZjbT6Pl229sSPi/saKWD6b4kLPJ1eNaWYh+xFM3kqZlcDDFaD47FNykGtFyM9uw2SAAJnKE5wXqpJg2q6tk1BoC8oceGdjmkaWigymV72WNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767880399; c=relaxed/simple; bh=VEpmBENh/rUkcbsYx6ewL93CLZSlTTuasbSN5JtpoVw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MBBWwbdnI2ZCnnsimLbpyBb58w4KIPq0iXaVLdFT1SuWeLLxMWfLrtRhgqxqL0aUCrTY82LQsyNeeLUvp/24wlUy9q7B6fWEbkO7QG0qgorRCLKsGvWdVzAh2amIM6DTvfmGasvJWKleC8L2bXkOqK5fcLIO2P8q1E/9RnEm7Wg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fq/x2AF5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fq/x2AF5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D19EC116C6; Thu, 8 Jan 2026 13:53:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767880398; bh=VEpmBENh/rUkcbsYx6ewL93CLZSlTTuasbSN5JtpoVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fq/x2AF54FjkE97ePXRvz3Cmw1EIMlIgMM7PbJGl6t/mjC1anKpiMPqDIT989cPD6 Kea7ACp0cLKgG1hn8rhMKAG+PC9KQqmrhnu3YfiZavF+fLO48QCIJkqYKK+P/xZz1u wxrLxtfOlezAdAFpJWmeS4Q2745prFDuX/ygWXSU3ncW37mXxiVc9zCBGkQHnH1TyG U71JlSaXSWPD4FYSqsP5X+3o141ZcsY/mq1rS44434y5MB6l1Kzmbmbx7HKimKbRpG Xgwo05of46NX7QjsGpSrt1WMEpivq6k6RvHAU0RwSg0KJxkvnAyFsO3krpoO1Jsqee 2hrNaVEXMBJow== From: Benno Lossin To: Benno Lossin , Gary Guo , Miguel Ojeda , Boqun Feng , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Fiona Behrens , Christian Schrefl , Alban Kurti Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH 08/12] rust: pin-init: rewrite the initializer macros using `syn` Date: Thu, 8 Jan 2026 14:50:46 +0100 Message-ID: <20260108135127.3153925-9-lossin@kernel.org> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260108135127.3153925-1-lossin@kernel.org> References: <20260108135127.3153925-1-lossin@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rewrite the initializer macros `[pin_]init!` using `syn`. No functional changes intended aside from improved error messages on syntactic and semantical errors. For example if one forgets to use `<-` with an initializer (and instead uses `:`): impl Bar { fn new() -> impl PinInit { ... } } impl Foo { fn new() -> impl PinInit { pin_init!(Self { bar: Bar::new() }) } } Then the declarative macro would report: error[E0308]: mismatched types --> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:9 | 14 | fn new() -> impl PinInit { | ------------------ the found opaque type ... 21 | pin_init!(Self { bar: Bar::new() }) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | expected `Bar`, found opaque type | arguments to this function are incorrect | =3D note: expected struct `Bar` found opaque type `impl pin_init::PinInit` note: function defined here --> $RUST/core/src/ptr/mod.rs | | pub const unsafe fn write(dst: *mut T, src: T) { | ^^^^^ =3D note: this error originates in the macro `$crate::__init_interna= l` which comes from the expansion of the macro `pin_init` (in Nightly build= s, run with -Z macro-backtrace for more info) And the new error is: error[E0308]: mismatched types --> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:31 | 14 | fn new() -> impl PinInit { | ------------------ the found opaque type ... 21 | pin_init!(Self { bar: Bar::new() }) | --- ^^^^^^^^^^ expected `Bar`, found opa= que type | | | arguments to this function are incorrect | =3D note: expected struct `Bar` found opaque type `impl pin_init::PinInit` note: function defined here --> $RUST/core/src/ptr/mod.rs | | pub const unsafe fn write(dst: *mut T, src: T) { | ^^^^^ Importantly, this error gives much more accurate span locations, pointing to the offending field, rather than the entire macro invocation. Signed-off-by: Benno Lossin --- rust/pin-init/internal/src/init.rs | 437 +++++++++++++ rust/pin-init/internal/src/lib.rs | 21 + rust/pin-init/src/lib.rs | 56 +- rust/pin-init/src/macros.rs | 951 ----------------------------- 4 files changed, 460 insertions(+), 1005 deletions(-) create mode 100644 rust/pin-init/internal/src/init.rs delete mode 100644 rust/pin-init/src/macros.rs diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/sr= c/init.rs new file mode 100644 index 000000000000..c02a99692980 --- /dev/null +++ b/rust/pin-init/internal/src/init.rs @@ -0,0 +1,437 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{ + braced, + parse::{End, Parse}, + parse_quote, + punctuated::Punctuated, + spanned::Spanned, + token, Block, Expr, ExprCall, ExprPath, Ident, Path, Token, Type, +}; + +pub struct Initializer { + this: Option, + path: Path, + brace_token: token::Brace, + fields: Punctuated, + rest: Option<(Token![..], Expr)>, + error: Option<(Token![?], Type)>, +} + +struct This { + _and_token: Token![&], + ident: Ident, + _in_token: Token![in], +} + +enum InitializerField { + Value { + ident: Ident, + value: Option<(Token![:], Expr)>, + }, + Init { + ident: Ident, + _left_arrow_token: Token![<-], + value: Expr, + }, + Code { + _underscore_token: Token![_], + _colon_token: Token![:], + block: Block, + }, +} + +impl InitializerField { + fn ident(&self) -> Option<&Ident> { + match self { + Self::Value { ident, .. } | Self::Init { ident, .. } =3D> Some= (ident), + Self::Code { .. } =3D> None, + } + } +} + +pub(crate) fn expand( + Initializer { + this, + path, + brace_token, + fields, + rest, + mut error, + }: Initializer, + default_error: Option<&'static str>, + pinned: bool, +) -> TokenStream { + let mut errors =3D TokenStream::new(); + if let Some(default_error) =3D default_error { + error.get_or_insert((Default::default(), syn::parse_str(default_er= ror).unwrap())); + } + let error =3D error.map(|(_, err)| err).unwrap_or_else(|| { + errors.extend(quote_spanned!(brace_token.span.close()=3D> + ::core::compile_error!("expected `? ` after `}`"); + )); + parse_quote!(::core::convert::Infallible) + }); + let slot =3D format_ident!("slot"); + let (has_data_trait, data_trait, get_data, init_from_closure) =3D if p= inned { + ( + 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"), + ) + }; + let init_kind =3D get_init_kind(rest, &mut errors); + let zeroable_check =3D match init_kind { + InitKind::Normal =3D> quote!(), + InitKind::Zeroing =3D> quote! { + // The user specified `..Zeroable::zeroed()` at the end of the= list of fields. + // Therefore we check if the struct implements `Zeroable` and = then zero the memory. + // This allows us to also remove the check that all fields are= present (since we + // already set the memory to zero and that is a valid bit patt= ern). + fn assert_zeroable(_: *mut T) + where T: ::pin_init::Zeroable + {} + // Ensure that the struct is indeed `Zeroable`. + assert_zeroable(#slot); + // SAFETY: The type implements `Zeroable` by the check above. + unsafe { ::core::ptr::write_bytes(#slot, 0, 1) }; + }, + }; + let this =3D match this { + None =3D> quote!(), + Some(This { ident, .. }) =3D> quote! { + // Create the `this` so it can be referenced by the user insid= e of the + // expressions creating the individual fields. + let #ident =3D unsafe { ::core::ptr::NonNull::new_unchecked(sl= ot) }; + }, + }; + // `mixed_site` ensures that the data is not accessible to the user-co= ntrolled code. + let data =3D format_ident!("__data", span =3D Span::mixed_site()); + let init_fields =3D init_fields(&fields, pinned, &data, &slot); + let field_check =3D make_field_check(&fields, init_kind, &path); + quote! {{ + // We do not want to allow arbitrary returns, so we declare this t= ype as the `Ok` return + // type and shadow it later when we insert the arbitrary user code= . That way there will be + // no possibility of returning without `unsafe`. + struct __InitOk; + + // Get the data about fields from the supplied type. + // SAFETY: TODO + let #data =3D unsafe { + use ::pin_init::__internal::#has_data_trait; + // Can't use `<#path as #has_data_trait>::#get_data`, since th= e user is able to omit + // generics (which need to be present with that syntax). + #path::#get_data() + }; + // Ensure that `#data` really is of type `#data` and help with typ= e inference: + let init =3D ::pin_init::__internal::#data_trait::make_closure::<_= , __InitOk, #error>( + #data, + move |slot| { + { + // Shadow the structure so it cannot be used to return= early. + struct __InitOk; + #zeroable_check + #this + #init_fields + #field_check + } + Ok(__InitOk) + } + ); + let init =3D move |slot| -> ::core::result::Result<(), #error> { + init(slot).map(|__InitOk| ()) + }; + // SAFETY: TODO + let init =3D unsafe { ::pin_init::#init_from_closure::<_, #error>(= init) }; + init + }} +} + +enum InitKind { + Normal, + Zeroing, +} + +fn get_init_kind(rest: Option<(Token![..], Expr)>, errors: &mut TokenStrea= m) -> InitKind { + let Some((dotdot, expr)) =3D rest else { + return InitKind::Normal; + }; + match &expr { + Expr::Call(ExprCall { func, args, .. }) if args.is_empty() =3D> ma= tch &**func { + Expr::Path(ExprPath { + attrs, + qself: None, + path: + Path { + leading_colon: None, + segments, + }, + }) if attrs.is_empty() + && segments.len() =3D=3D 2 + && segments[0].ident =3D=3D "Zeroable" + && segments[0].arguments.is_none() + && segments[1].ident =3D=3D "init_zeroed" + && segments[1].arguments.is_none() =3D> + { + return InitKind::Zeroing; + } + _ =3D> {} + }, + _ =3D> {} + } + let span =3D quote!(#dotdot #expr).span(); + errors.extend(quote_spanned!(span=3D> + ::core::compile_error!("expected nothing or `..Zeroable::init_zero= ed()`."); + )); + InitKind::Normal +} + +/// Generate the code that initializes the fields of the struct using the = initializers in `field`. +fn init_fields( + fields: &Punctuated, + pinned: bool, + data: &Ident, + slot: &Ident, +) -> TokenStream { + let mut guards =3D vec![]; + let mut res =3D TokenStream::new(); + for field in fields { + let init =3D match field { + InitializerField::Value { ident, value } =3D> { + let mut value_ident =3D ident.clone(); + let value_prep =3D value.as_ref().map(|value| &value.1).ma= p(|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 =3D #value;) + }); + // Again span for better diagnostics + let write =3D quote_spanned!(ident.span()=3D> ::core::ptr:= :write); + let accessor =3D if pinned { + let project_ident =3D format_ident!("__project_{ident}= "); + quote! { + // SAFETY: TODO + unsafe { #data.#project_ident(&mut (*#slot).#ident= ) } + } + } else { + quote! { + // SAFETY: TODO + unsafe { &mut (*#slot).#ident } + } + }; + quote! { + { + #value_prep + // SAFETY: TODO + unsafe { #write(::core::ptr::addr_of_mut!((*#slot)= .#ident), #value_ident) }; + } + #[allow(unused_variables)] + let #ident =3D #accessor; + } + } + InitializerField::Init { ident, value, .. } =3D> { + // Again span for better diagnostics + let init =3D format_ident!("init", span =3D value.span()); + if pinned { + let project_ident =3D format_ident!("__project_{ident}= "); + quote! { + { + let #init =3D #value; + // 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 correc= t trait (`Init` or `PinInit`) + // for `#ident`. + unsafe { #data.#ident(::core::ptr::addr_of_mut= !((*#slot).#ident), #init)? }; + } + // SAFETY: TODO + #[allow(unused_variables)] + let #ident =3D unsafe { #data.#project_ident(&mut = (*#slot).#ident) }; + } + } else { + quote! { + { + let #init =3D #value; + // SAFETY: `slot` is valid, because we are ins= ide of an initializer + // closure, we return when an error/panic occu= rs. + unsafe { + ::pin_init::Init::__init( + #init, + ::core::ptr::addr_of_mut!((*#slot).#id= ent), + )? + }; + } + // SAFETY: TODO + #[allow(unused_variables)] + let #ident =3D unsafe { &mut (*#slot).#ident }; + } + } + } + InitializerField::Code { block: value, .. } =3D> quote!(#[allo= w(unused_braces)] #value), + }; + res.extend(init); + if let Some(ident) =3D field.ident() { + // `mixed_site` ensures that the guard is not accessible to th= e user-controlled code. + let guard =3D format_ident!("__{ident}_guard", span =3D Span::= mixed_site()); + guards.push(guard.clone()); + res.extend(quote! { + // Create the drop guard: + // + // We rely on macro hygiene to make it impossible for user= s to access this local + // variable. + // SAFETY: We forget the guard later when initialization h= as succeeded. + let #guard =3D unsafe { + ::pin_init::__internal::DropGuard::new( + ::core::ptr::addr_of_mut!((*slot).#ident) + ) + }; + }); + } + } + quote! { + #res + // If execution reaches this point, all fields have been initializ= ed. Therefore we can now + // dismiss the guards by forgetting them. + #(::core::mem::forget(#guards);)* + } +} + +/// Generate the check for ensuring that every field has been initialized. +fn make_field_check( + fields: &Punctuated, + init_kind: InitKind, + path: &Path, +) -> TokenStream { + let fields =3D fields.iter().filter_map(|f| f.ident()); + match init_kind { + InitKind::Normal =3D> quote! { + // We use unreachable code to ensure that all fields have been= mentioned exactly once, + // this struct initializer will still be type-checked and comp= lain with a very natural + // error message if a field is forgotten/mentioned more than o= nce. + #[allow(unreachable_code, clippy::diverging_sub_expression)] + // SAFETY: this code is never executed. + let _ =3D || unsafe { + ::core::ptr::write(slot, #path { + #( + #fields: ::core::panic!(), + )* + }) + }; + }, + InitKind::Zeroing =3D> 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-check= ed and complain with a + // very natural error message if a field is mentioned more tha= n once, or doesn't exist. + #[allow(unreachable_code, clippy::diverging_sub_expression, un= used_assignments)] + // SAFETY: this code is never executed. + let _ =3D || unsafe { + let mut zeroed =3D ::core::mem::zeroed(); + ::core::ptr::write(slot, zeroed); + zeroed =3D ::core::mem::zeroed(); + ::core::ptr::write(slot, #path { + #( + #fields: ::core::panic!(), + )* + ..zeroed + }) + }; + }, + } +} + +impl Parse for Initializer { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let this =3D input.peek(Token![&]).then(|| input.parse()).transpos= e()?; + let path =3D input.parse()?; + let content; + let brace_token =3D braced!(content in input); + let mut fields =3D Punctuated::new(); + loop { + let lh =3D content.lookahead1(); + if lh.peek(End) || lh.peek(Token![..]) { + break; + } else if lh.peek(Ident) || lh.peek(Token![_]) { + fields.push_value(content.parse()?); + let lh =3D content.lookahead1(); + if lh.peek(End) { + break; + } else if lh.peek(Token![,]) { + fields.push_punct(content.parse()?); + } else { + return Err(lh.error()); + } + } else { + return Err(lh.error()); + } + } + let rest =3D content + .peek(Token![..]) + .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse(= )?))) + .transpose()?; + let error =3D input + .peek(Token![?]) + .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?))) + .transpose()?; + Ok(Self { + this, + path, + brace_token, + fields, + rest, + error, + }) + } +} + +impl Parse for This { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self { + _and_token: input.parse()?, + ident: input.parse()?, + _in_token: input.parse()?, + }) + } +} + +impl Parse for InitializerField { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lh =3D input.lookahead1(); + if lh.peek(Token![_]) { + Ok(Self::Code { + _underscore_token: input.parse()?, + _colon_token: input.parse()?, + block: input.parse()?, + }) + } else if lh.peek(Ident) { + let ident =3D input.parse()?; + let lh =3D input.lookahead1(); + if lh.peek(Token![<-]) { + Ok(Self::Init { + ident, + _left_arrow_token: input.parse()?, + value: input.parse()?, + }) + } else if lh.peek(Token![:]) { + Ok(Self::Value { + ident, + value: Some((input.parse()?, input.parse()?)), + }) + } else if lh.peek(Token![,]) || lh.peek(End) { + Ok(Self::Value { ident, value: None }) + } else { + Err(lh.error()) + } + } else { + Err(lh.error()) + } + } +} diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src= /lib.rs index 243684a1eedc..c7c59ae77eda 100644 --- a/rust/pin-init/internal/src/lib.rs +++ b/rust/pin-init/internal/src/lib.rs @@ -13,6 +13,7 @@ use proc_macro::TokenStream; use syn::parse_macro_input; =20 +mod init; mod pin_data; mod pinned_drop; mod zeroable; @@ -47,3 +48,23 @@ pub fn derive_zeroable(input: TokenStream) -> TokenStrea= m { pub fn maybe_derive_zeroable(input: TokenStream) -> TokenStream { zeroable::maybe_derive(parse_macro_input!(input as _)).into() } + +#[proc_macro] +pub fn init(input: TokenStream) -> TokenStream { + init::expand( + parse_macro_input!(input as _), + Some("::core::convert::Infallible"), + false, + ) + .into() +} + +#[proc_macro] +pub fn pin_init(input: TokenStream) -> TokenStream { + init::expand( + parse_macro_input!(input as _), + Some("::core::convert::Infallible"), + true, + ) + .into() +} diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 0e707f00061f..780b4fead22d 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -297,8 +297,6 @@ =20 #[doc(hidden)] pub mod __internal; -#[doc(hidden)] -pub mod macros; =20 #[cfg(any(feature =3D "std", feature =3D "alloc"))] mod alloc; @@ -781,32 +779,7 @@ macro_rules! stack_try_pin_init { /// ``` /// /// [`NonNull`]: core::ptr::NonNull -// For a detailed example of how this macro works, see the module document= ation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! pin_init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }) =3D> { - $crate::pin_init!($(&$this in)? $t $(::<$($generics),*>)? { - $($fields)* - }? ::core::convert::Infallible) - }; - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }? $err:ty) =3D> { - $crate::__init_internal!( - @this($($this)?), - @typ($t $(::<$($generics),*>)? ), - @fields($($fields)*), - @error($err), - @data(PinData, use_data), - @has_data(HasPinData, __pin_data), - @construct_closure(pin_init_from_closure), - @munch_fields($($fields)*), - ) - } -} +pub use pin_init_internal::pin_init; =20 /// Construct an in-place, fallible initializer for `struct`s. /// @@ -844,32 +817,7 @@ macro_rules! pin_init { /// } /// # let _ =3D Box::init(BigBuf::new()); /// ``` -// For a detailed example of how this macro works, see the module document= ation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }) =3D> { - $crate::init!($(&$this in)? $t $(::<$($generics),*>)? { - $($fields)* - }? ::core::convert::Infallible) - }; - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }? $err:ty) =3D> { - $crate::__init_internal!( - @this($($this)?), - @typ($t $(::<$($generics),*>)?), - @fields($($fields)*), - @error($err), - @data(InitData, /*no use_data*/), - @has_data(HasInitData, __init_data), - @construct_closure(init_from_closure), - @munch_fields($($fields)*), - ) - } -} +pub use pin_init_internal::init; =20 /// Asserts that a field on a struct using `#[pin_data]` is marked with `#= [pin]` ie. that it is /// structurally pinned. diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs deleted file mode 100644 index eea8adc5c7ad..000000000000 --- a/rust/pin-init/src/macros.rs +++ /dev/null @@ -1,951 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! This module provides the macros that actually implement the proc-macro= s `pin_data` and -//! `pinned_drop`. It also contains `__init_internal`, the implementation = of the -//! `{try_}{pin_}init!` macros. -//! -//! These macros should never be called directly, since they expect their = input to be -//! in a certain format which is internal. If used incorrectly, these macr= os can lead to UB even in -//! safe code! Use the public facing macros instead. -//! -//! This architecture has been chosen because the kernel does not yet have= access to `syn` which -//! would make matters a lot easier for implementing these as proc-macros. -//! -//! Since this library and the kernel implementation should diverge as lit= tle as possible, the same -//! approach has been taken here. -//! -//! # Macro expansion example -//! -//! This section is intended for readers trying to understand the macros i= n this module and the -//! `[try_][pin_]init!` macros from `lib.rs`. -//! -//! We will look at the following example: -//! -//! ```rust,ignore -//! #[pin_data] -//! #[repr(C)] -//! struct Bar { -//! #[pin] -//! t: T, -//! pub x: usize, -//! } -//! -//! impl Bar { -//! fn new(t: T) -> impl PinInit { -//! pin_init!(Self { t, x: 0 }) -//! } -//! } -//! -//! #[pin_data(PinnedDrop)] -//! struct Foo { -//! a: usize, -//! #[pin] -//! b: Bar, -//! } -//! -//! #[pinned_drop] -//! impl PinnedDrop for Foo { -//! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); -//! } -//! } -//! -//! let a =3D 42; -//! let initializer =3D pin_init!(Foo { -//! a, -//! b <- Bar::new(36), -//! }); -//! ``` -//! -//! This example includes the most common and important features of the pi= n-init API. -//! -//! Below you can find individual section about the different macro invoca= tions. Here are some -//! general things we need to take into account when designing macros: -//! - use global paths, similarly to file paths, these start with the sepa= rator: `::core::panic!()` -//! this ensures that the correct item is used, since users could define= their own `mod core {}` -//! and then their own `panic!` inside to execute arbitrary code inside = of our macro. -//! - macro `unsafe` hygiene: we need to ensure that we do not expand arbi= trary, user-supplied -//! expressions inside of an `unsafe` block in the macro, because this w= ould allow users to do -//! `unsafe` operations without an associated `unsafe` block. -//! -//! ## `#[pin_data]` on `Bar` -//! -//! This macro is used to specify which fields are structurally pinned and= which fields are not. It -//! is placed on the struct definition and allows `#[pin]` to be placed on= the fields. -//! -//! Here is the definition of `Bar` from our example: -//! -//! ```rust,ignore -//! #[pin_data] -//! #[repr(C)] -//! struct Bar { -//! #[pin] -//! t: T, -//! pub x: usize, -//! } -//! ``` -//! -//! This expands to the following code: -//! -//! ```rust,ignore -//! // Firstly the normal definition of the struct, attributes are preserv= ed: -//! #[repr(C)] -//! struct Bar { -//! t: T, -//! pub x: usize, -//! } -//! // Then an anonymous constant is defined, this is because we do not wa= nt any code to access the -//! // types that we define inside: -//! const _: () =3D { -//! // We define the pin-data carrying struct, it is a ZST and needs t= o have the same generics, -//! // since we need to implement access functions for each field and = thus need to know its -//! // type. -//! struct __ThePinData { -//! __phantom: ::core::marker::PhantomData) -> Bar>, -//! } -//! // We implement `Copy` for the pin-data struct, since all function= s it defines will take -//! // `self` by value. -//! impl ::core::clone::Clone for __ThePinData { -//! fn clone(&self) -> Self { -//! *self -//! } -//! } -//! impl ::core::marker::Copy for __ThePinData {} -//! // For every field of `Bar`, the pin-data struct will define a fun= ction with the same name -//! // and accessor (`pub` or `pub(crate)` etc.). This function will t= ake a pointer to the -//! // field (`slot`) and a `PinInit` or `Init` depending on the proje= ction kind of the field -//! // (if pinning is structural for the field, then `PinInit` otherwi= se `Init`). -//! #[allow(dead_code)] -//! impl __ThePinData { -//! unsafe fn t( -//! self, -//! slot: *mut T, -//! // Since `t` is `#[pin]`, this is `PinInit`. -//! init: impl ::pin_init::PinInit, -//! ) -> ::core::result::Result<(), E> { -//! unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } -//! } -//! pub unsafe fn x( -//! self, -//! slot: *mut usize, -//! // Since `x` is not `#[pin]`, this is `Init`. -//! init: impl ::pin_init::Init, -//! ) -> ::core::result::Result<(), E> { -//! unsafe { ::pin_init::Init::__init(init, slot) } -//! } -//! } -//! // Implement the internal `HasPinData` trait that associates `Bar`= with the pin-data struct -//! // that we constructed above. -//! unsafe impl ::pin_init::__internal::HasPinData for Bar { -//! type PinData =3D __ThePinData; -//! unsafe fn __pin_data() -> Self::PinData { -//! __ThePinData { -//! __phantom: ::core::marker::PhantomData, -//! } -//! } -//! } -//! // Implement the internal `PinData` trait that marks the pin-data = struct as a pin-data -//! // struct. This is important to ensure that no user can implement = a rogue `__pin_data` -//! // function without using `unsafe`. -//! unsafe impl ::pin_init::__internal::PinData for __ThePinData= { -//! type Datee =3D Bar; -//! } -//! // Now we only want to implement `Unpin` for `Bar` when every stru= cturally pinned field is -//! // `Unpin`. In other words, whether `Bar` is `Unpin` only depends = on structurally pinned -//! // fields (those marked with `#[pin]`). These fields will be liste= d in this struct, in our -//! // case no such fields exist, hence this is almost empty. The two = phantomdata fields exist -//! // for two reasons: -//! // - `__phantom`: every generic must be used, since we cannot real= ly know which generics -//! // are used, we declare all and then use everything here once. -//! // - `__phantom_pin`: uses the `'__pin` lifetime and ensures that = this struct is invariant -//! // over it. The lifetime is needed to work around the limitation= that trait bounds must -//! // not be trivial, e.g. the user has a `#[pin] PhantomPinned` fi= eld -- this is -//! // unconditionally `!Unpin` and results in an error. The lifetim= e tricks the compiler -//! // into accepting these bounds regardless. -//! #[allow(dead_code)] -//! struct __Unpin<'__pin, T> { -//! __phantom_pin: ::core::marker::PhantomData &= '__pin ()>, -//! __phantom: ::core::marker::PhantomData) -> Bar>, -//! // Our only `#[pin]` field is `t`. -//! t: T, -//! } -//! #[doc(hidden)] -//! impl<'__pin, T> ::core::marker::Unpin for Bar -//! where -//! __Unpin<'__pin, T>: ::core::marker::Unpin, -//! {} -//! // Now we need to ensure that `Bar` does not implement `Drop`, sin= ce that would give users -//! // access to `&mut self` inside of `drop` even if the struct was p= inned. This could lead to -//! // UB with only safe code, so we disallow this by giving a trait i= mplementation error using -//! // a direct impl and a blanket implementation. -//! trait MustNotImplDrop {} -//! // Normally `Drop` bounds do not have the correct semantics, but f= or this purpose they do -//! // (normally people want to know if a type has any kind of drop gl= ue at all, here we want -//! // to know if it has any kind of custom drop glue, which is exactl= y what this bound does). -//! #[expect(drop_bounds)] -//! impl MustNotImplDrop for T {} -//! impl MustNotImplDrop for Bar {} -//! // Here comes a convenience check, if one implemented `PinnedDrop`= , but forgot to add it to -//! // `#[pin_data]`, then this will error with the same mechanic as a= bove, this is not needed -//! // for safety, but a good sanity check, since no normal code calls= `PinnedDrop::drop`. -//! #[expect(non_camel_case_types)] -//! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} -//! impl< -//! T: ::pin_init::PinnedDrop, -//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} -//! impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for B= ar {} -//! }; -//! ``` -//! -//! ## `pin_init!` in `impl Bar` -//! -//! This macro creates an pin-initializer for the given struct. It require= s that the struct is -//! annotated by `#[pin_data]`. -//! -//! Here is the impl on `Bar` defining the new function: -//! -//! ```rust,ignore -//! impl Bar { -//! fn new(t: T) -> impl PinInit { -//! pin_init!(Self { t, x: 0 }) -//! } -//! } -//! ``` -//! -//! This expands to the following code: -//! -//! ```rust,ignore -//! impl Bar { -//! fn new(t: T) -> impl PinInit { -//! { -//! // We do not want to allow arbitrary returns, so we declar= e this type as the `Ok` -//! // return type and shadow it later when we insert the arbi= trary user code. That way -//! // there will be no possibility of returning without `unsa= fe`. -//! struct __InitOk; -//! // Get the data about fields from the supplied type. -//! // - the function is unsafe, hence the unsafe block -//! // - we `use` the `HasPinData` trait in the block, it is o= nly available in that -//! // scope. -//! let data =3D unsafe { -//! use ::pin_init::__internal::HasPinData; -//! Self::__pin_data() -//! }; -//! // Ensure that `data` really is of type `PinData` and help= with type inference: -//! let init =3D ::pin_init::__internal::PinData::make_closure= ::< -//! _, -//! __InitOk, -//! ::core::convert::Infallible, -//! >(data, move |slot| { -//! { -//! // Shadow the structure so it cannot be used to re= turn early. If a user -//! // tries to write `return Ok(__InitOk)`, then they= get a type error, -//! // since that will refer to this struct instead of= the one defined -//! // above. -//! struct __InitOk; -//! // This is the expansion of `t,`, which is syntact= ic sugar for `t: t,`. -//! { -//! unsafe { ::core::ptr::write(::core::addr_of_mu= t!((*slot).t), t) }; -//! } -//! // Since initialization could fail later (not in t= his case, since the -//! // error type is `Infallible`) we will need to dro= p this field if there -//! // is an error later. This `DropGuard` will drop t= he field when it gets -//! // dropped and has not yet been forgotten. -//! let __t_guard =3D unsafe { -//! ::pin_init::__internal::DropGuard::new(::core:= :addr_of_mut!((*slot).t)) -//! }; -//! // Expansion of `x: 0,`: -//! // Since this can be an arbitrary expression we ca= nnot place it inside -//! // of the `unsafe` block, so we bind it here. -//! { -//! let x =3D 0; -//! unsafe { ::core::ptr::write(::core::addr_of_mu= t!((*slot).x), x) }; -//! } -//! // We again create a `DropGuard`. -//! let __x_guard =3D unsafe { -//! ::pin_init::__internal::DropGuard::new(::core:= :addr_of_mut!((*slot).x)) -//! }; -//! // Since initialization has successfully completed= , we can now forget -//! // the guards. This is not `mem::forget`, since we= only have -//! // `&DropGuard`. -//! ::core::mem::forget(__x_guard); -//! ::core::mem::forget(__t_guard); -//! // Here we use the type checker to ensure that eve= ry field has been -//! // initialized exactly once, since this is `if fal= se` it will never get -//! // executed, but still type-checked. -//! // Additionally we abuse `slot` to automatically i= nfer the correct type -//! // for the struct. This is also another check that= every field is -//! // accessible from this scope. -//! #[allow(unreachable_code, clippy::diverging_sub_ex= pression)] -//! let _ =3D || { -//! unsafe { -//! ::core::ptr::write( -//! slot, -//! Self { -//! // We only care about typecheck fi= nding every field -//! // here, the expression does not m= atter, just conjure -//! // one using `panic!()`: -//! t: ::core::panic!(), -//! x: ::core::panic!(), -//! }, -//! ); -//! }; -//! }; -//! } -//! // We leave the scope above and gain access to the pre= viously shadowed -//! // `__InitOk` that we need to return. -//! Ok(__InitOk) -//! }); -//! // Change the return type from `__InitOk` to `()`. -//! let init =3D move | -//! slot, -//! | -> ::core::result::Result<(), ::core::convert::Infallibl= e> { -//! init(slot).map(|__InitOk| ()) -//! }; -//! // Construct the initializer. -//! let init =3D unsafe { -//! ::pin_init::pin_init_from_closure::< -//! _, -//! ::core::convert::Infallible, -//! >(init) -//! }; -//! init -//! } -//! } -//! } -//! ``` -//! -//! ## `#[pin_data]` on `Foo` -//! -//! Since we already took a look at `#[pin_data]` on `Bar`, this section w= ill only explain the -//! differences/new things in the expansion of the `Foo` definition: -//! -//! ```rust,ignore -//! #[pin_data(PinnedDrop)] -//! struct Foo { -//! a: usize, -//! #[pin] -//! b: Bar, -//! } -//! ``` -//! -//! This expands to the following code: -//! -//! ```rust,ignore -//! struct Foo { -//! a: usize, -//! b: Bar, -//! } -//! const _: () =3D { -//! struct __ThePinData { -//! __phantom: ::core::marker::PhantomData Foo>, -//! } -//! impl ::core::clone::Clone for __ThePinData { -//! fn clone(&self) -> Self { -//! *self -//! } -//! } -//! impl ::core::marker::Copy for __ThePinData {} -//! #[allow(dead_code)] -//! impl __ThePinData { -//! unsafe fn b( -//! self, -//! slot: *mut Bar, -//! init: impl ::pin_init::PinInit, E>, -//! ) -> ::core::result::Result<(), E> { -//! unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } -//! } -//! unsafe fn a( -//! self, -//! slot: *mut usize, -//! init: impl ::pin_init::Init, -//! ) -> ::core::result::Result<(), E> { -//! unsafe { ::pin_init::Init::__init(init, slot) } -//! } -//! } -//! unsafe impl ::pin_init::__internal::HasPinData for Foo { -//! type PinData =3D __ThePinData; -//! unsafe fn __pin_data() -> Self::PinData { -//! __ThePinData { -//! __phantom: ::core::marker::PhantomData, -//! } -//! } -//! } -//! unsafe impl ::pin_init::__internal::PinData for __ThePinData { -//! type Datee =3D Foo; -//! } -//! #[allow(dead_code)] -//! struct __Unpin<'__pin> { -//! __phantom_pin: ::core::marker::PhantomData &= '__pin ()>, -//! __phantom: ::core::marker::PhantomData Foo>, -//! b: Bar, -//! } -//! #[doc(hidden)] -//! impl<'__pin> ::core::marker::Unpin for Foo -//! where -//! __Unpin<'__pin>: ::core::marker::Unpin, -//! {} -//! // Since we specified `PinnedDrop` as the argument to `#[pin_data]= `, we expect `Foo` to -//! // implement `PinnedDrop`. Thus we do not need to prevent `Drop` i= mplementations like -//! // before, instead we implement `Drop` here and delegate to `Pinne= dDrop`. -//! impl ::core::ops::Drop for Foo { -//! fn drop(&mut self) { -//! // Since we are getting dropped, no one else has a referen= ce to `self` and thus we -//! // can assume that we never move. -//! let pinned =3D unsafe { ::core::pin::Pin::new_unchecked(se= lf) }; -//! // Create the unsafe token that proves that we are inside = of a destructor, this -//! // type is only allowed to be created in a destructor. -//! let token =3D unsafe { ::pin_init::__internal::OnlyCallFro= mDrop::new() }; -//! ::pin_init::PinnedDrop::drop(pinned, token); -//! } -//! } -//! }; -//! ``` -//! -//! ## `#[pinned_drop]` on `impl PinnedDrop for Foo` -//! -//! This macro is used to implement the `PinnedDrop` trait, since that tra= it is `unsafe` and has an -//! extra parameter that should not be used at all. The macro hides that p= arameter. -//! -//! Here is the `PinnedDrop` impl for `Foo`: -//! -//! ```rust,ignore -//! #[pinned_drop] -//! impl PinnedDrop for Foo { -//! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); -//! } -//! } -//! ``` -//! -//! This expands to the following code: -//! -//! ```rust,ignore -//! // `unsafe`, full path and the token parameter are added, everything e= lse stays the same. -//! unsafe impl ::pin_init::PinnedDrop for Foo { -//! fn drop(self: Pin<&mut Self>, _: ::pin_init::__internal::OnlyCallF= romDrop) { -//! println!("{self:p} is getting dropped."); -//! } -//! } -//! ``` -//! -//! ## `pin_init!` on `Foo` -//! -//! Since we already took a look at `pin_init!` on `Bar`, this section wil= l only show the expansion -//! of `pin_init!` on `Foo`: -//! -//! ```rust,ignore -//! let a =3D 42; -//! let initializer =3D pin_init!(Foo { -//! a, -//! b <- Bar::new(36), -//! }); -//! ``` -//! -//! This expands to the following code: -//! -//! ```rust,ignore -//! let a =3D 42; -//! let initializer =3D { -//! struct __InitOk; -//! let data =3D unsafe { -//! use ::pin_init::__internal::HasPinData; -//! Foo::__pin_data() -//! }; -//! let init =3D ::pin_init::__internal::PinData::make_closure::< -//! _, -//! __InitOk, -//! ::core::convert::Infallible, -//! >(data, move |slot| { -//! { -//! struct __InitOk; -//! { -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slo= t).a), a) }; -//! } -//! let __a_guard =3D unsafe { -//! ::pin_init::__internal::DropGuard::new(::core::addr_of= _mut!((*slot).a)) -//! }; -//! let init =3D Bar::new(36); -//! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? }; -//! let __b_guard =3D unsafe { -//! ::pin_init::__internal::DropGuard::new(::core::addr_of= _mut!((*slot).b)) -//! }; -//! ::core::mem::forget(__b_guard); -//! ::core::mem::forget(__a_guard); -//! #[allow(unreachable_code, clippy::diverging_sub_expression= )] -//! let _ =3D || { -//! unsafe { -//! ::core::ptr::write( -//! slot, -//! Foo { -//! a: ::core::panic!(), -//! b: ::core::panic!(), -//! }, -//! ); -//! }; -//! }; -//! } -//! Ok(__InitOk) -//! }); -//! let init =3D move | -//! slot, -//! | -> ::core::result::Result<(), ::core::convert::Infallible> { -//! init(slot).map(|__InitOk| ()) -//! }; -//! let init =3D unsafe { -//! ::pin_init::pin_init_from_closure::<_, ::core::convert::Infall= ible>(init) -//! }; -//! init -//! }; -//! ``` - -#[cfg(kernel)] -pub use ::macros::paste; -#[cfg(not(kernel))] -pub use ::paste::paste; - -/// The internal init macro. Do not call manually! -/// -/// This is called by the `{try_}{pin_}init!` macros with various inputs. -/// -/// This macro has multiple internal call configurations, these are always= the very first ident: -/// - nothing: this is the base case and called by the `{try_}{pin_}init!`= macros. -/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax ha= s been handled. -/// - `init_slot`: recursively creates the code that initializes all field= s in `slot`. -/// - `make_initializer`: recursively create the struct initializer that g= uarantees that every -/// field has been initialized exactly once. -#[doc(hidden)] -#[macro_export] -macro_rules! __init_internal { - ( - @this($($this:ident)?), - @typ($t:path), - @fields($($fields:tt)*), - @error($err:ty), - // Either `PinData` or `InitData`, `$use_data` should only be pres= ent in the `PinData` - // case. - @data($data:ident, $($use_data:ident)?), - // `HasPinData` or `HasInitData`. - @has_data($has_data:ident, $get_data:ident), - // `pin_init_from_closure` or `init_from_closure`. - @construct_closure($construct_closure:ident), - @munch_fields(), - ) =3D> { - $crate::__init_internal!(with_update_parsed: - @this($($this)?), - @typ($t), - @fields($($fields)*), - @error($err), - @data($data, $($use_data)?), - @has_data($has_data, $get_data), - @construct_closure($construct_closure), - @init_zeroed(), // Nothing means default behavior. - ) - }; - ( - @this($($this:ident)?), - @typ($t:path), - @fields($($fields:tt)*), - @error($err:ty), - // Either `PinData` or `InitData`, `$use_data` should only be pres= ent in the `PinData` - // case. - @data($data:ident, $($use_data:ident)?), - // `HasPinData` or `HasInitData`. - @has_data($has_data:ident, $get_data:ident), - // `pin_init_from_closure` or `init_from_closure`. - @construct_closure($construct_closure:ident), - @munch_fields(..Zeroable::init_zeroed()), - ) =3D> { - $crate::__init_internal!(with_update_parsed: - @this($($this)?), - @typ($t), - @fields($($fields)*), - @error($err), - @data($data, $($use_data)?), - @has_data($has_data, $get_data), - @construct_closure($construct_closure), - @init_zeroed(()), // `()` means zero all fields not mentioned. - ) - }; - ( - @this($($this:ident)?), - @typ($t:path), - @fields($($fields:tt)*), - @error($err:ty), - // Either `PinData` or `InitData`, `$use_data` should only be pres= ent in the `PinData` - // case. - @data($data:ident, $($use_data:ident)?), - // `HasPinData` or `HasInitData`. - @has_data($has_data:ident, $get_data:ident), - // `pin_init_from_closure` or `init_from_closure`. - @construct_closure($construct_closure:ident), - @munch_fields($ignore:tt $($rest:tt)*), - ) =3D> { - $crate::__init_internal!( - @this($($this)?), - @typ($t), - @fields($($fields)*), - @error($err), - @data($data, $($use_data)?), - @has_data($has_data, $get_data), - @construct_closure($construct_closure), - @munch_fields($($rest)*), - ) - }; - (with_update_parsed: - @this($($this:ident)?), - @typ($t:path), - @fields($($fields:tt)*), - @error($err:ty), - // Either `PinData` or `InitData`, `$use_data` should only be pres= ent in the `PinData` - // case. - @data($data:ident, $($use_data:ident)?), - // `HasPinData` or `HasInitData`. - @has_data($has_data:ident, $get_data:ident), - // `pin_init_from_closure` or `init_from_closure`. - @construct_closure($construct_closure:ident), - @init_zeroed($($init_zeroed:expr)?), - ) =3D> {{ - // We do not want to allow arbitrary returns, so we declare this t= ype as the `Ok` return - // type and shadow it later when we insert the arbitrary user code= . That way there will be - // no possibility of returning without `unsafe`. - struct __InitOk; - // Get the data about fields from the supplied type. - // - // SAFETY: TODO. - let data =3D unsafe { - use $crate::__internal::$has_data; - // Here we abuse `paste!` to retokenize `$t`. Declarative macr= os have some internal - // information that is associated to already parsed fragments,= so a path fragment - // cannot be used in this position. Doing the retokenization r= esults in valid rust - // code. - $crate::macros::paste!($t::$get_data()) - }; - // Ensure that `data` really is of type `$data` and help with type= inference: - let init =3D $crate::__internal::$data::make_closure::<_, __InitOk= , $err>( - data, - move |slot| { - { - // Shadow the structure so it cannot be used to return= early. - struct __InitOk; - // If `$init_zeroed` is present we should zero the slo= t now and not emit an - // error when fields are missing (since they will be z= eroed). We also have to - // check that the type actually implements `Zeroable`. - $({ - fn assert_zeroable(_: *mut T)= {} - // Ensure that the struct is indeed `Zeroable`. - assert_zeroable(slot); - // SAFETY: The type implements `Zeroable` by the c= heck above. - unsafe { ::core::ptr::write_bytes(slot, 0, 1) }; - $init_zeroed // This will be `()` if set. - })? - // Create the `this` so it can be referenced by the us= er inside of the - // expressions creating the individual fields. - $(let $this =3D unsafe { ::core::ptr::NonNull::new_unc= hecked(slot) };)? - // Initialize every field. - $crate::__init_internal!(init_slot($($use_data)?): - @data(data), - @slot(slot), - @guards(), - @munch_fields($($fields)*,), - ); - // We use unreachable code to ensure that all fields h= ave been mentioned exactly - // once, this struct initializer will still be type-ch= ecked and complain with a - // very natural error message if a field is forgotten/= mentioned more than once. - #[allow(unreachable_code, clippy::diverging_sub_expres= sion)] - let _ =3D || { - $crate::__init_internal!(make_initializer: - @slot(slot), - @type_name($t), - @munch_fields($($fields)*,), - @acc(), - ); - }; - } - Ok(__InitOk) - } - ); - let init =3D move |slot| -> ::core::result::Result<(), $err> { - init(slot).map(|__InitOk| ()) - }; - // SAFETY: TODO. - let init =3D unsafe { $crate::$construct_closure::<_, $err>(init) = }; - init - }}; - (init_slot($($use_data:ident)?): - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - @munch_fields($(..Zeroable::init_zeroed())? $(,)?), - ) =3D> { - // Endpoint of munching, no fields are left. If execution reaches = this point, all fields - // have been initialized. Therefore we can now dismiss the guards = by forgetting them. - $(::core::mem::forget($guards);)* - }; - (init_slot($($use_data:ident)?): - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - // arbitrary code block - @munch_fields(_: { $($code:tt)* }, $($rest:tt)*), - ) =3D> { - { $($code)* } - $crate::__init_internal!(init_slot($($use_data)?): - @data($data), - @slot($slot), - @guards($($guards,)*), - @munch_fields($($rest)*), - ); - }; - (init_slot($use_data:ident): // `use_data` is present, so we use the `= data` to init fields. - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - // In-place initialization syntax. - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) =3D> { - let init =3D $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initialize= r closure, we - // return when an error/panic occurs. - // We also use the `data` to require the correct trait (`Init` or = `PinInit`) for `$field`. - unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), = init)? }; - // SAFETY: - // - the project function does the correct field projection, - // - the field has been initialized, - // - the reference is only valid until the end of the initializer. - #[allow(unused_variables)] - let $field =3D $crate::macros::paste!(unsafe { $data.[< __project_= $field >](&mut (*$slot).$field) }); - - // Create the drop guard: - // - // We rely on macro hygiene to make it impossible for users to acc= ess this local variable. - // We use `paste!` to create new hygiene for `$field`. - $crate::macros::paste! { - // SAFETY: We forget the guard later when initialization has s= ucceeded. - let [< __ $field _guard >] =3D unsafe { - $crate::__internal::DropGuard::new(::core::ptr::addr_of_mu= t!((*$slot).$field)) - }; - - $crate::__init_internal!(init_slot($use_data): - @data($data), - @slot($slot), - @guards([< __ $field _guard >], $($guards,)*), - @munch_fields($($rest)*), - ); - } - }; - (init_slot(): // No `use_data`, so we use `Init::__init` directly. - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - // In-place initialization syntax. - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) =3D> { - let init =3D $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initialize= r closure, we - // return when an error/panic occurs. - unsafe { $crate::Init::__init(init, ::core::ptr::addr_of_mut!((*$s= lot).$field))? }; - - // SAFETY: - // - the field is not structurally pinned, since the line above mu= st compile, - // - the field has been initialized, - // - the reference is only valid until the end of the initializer. - #[allow(unused_variables)] - let $field =3D unsafe { &mut (*$slot).$field }; - - // Create the drop guard: - // - // We rely on macro hygiene to make it impossible for users to acc= ess this local variable. - // We use `paste!` to create new hygiene for `$field`. - $crate::macros::paste! { - // SAFETY: We forget the guard later when initialization has s= ucceeded. - let [< __ $field _guard >] =3D unsafe { - $crate::__internal::DropGuard::new(::core::ptr::addr_of_mu= t!((*$slot).$field)) - }; - - $crate::__init_internal!(init_slot(): - @data($data), - @slot($slot), - @guards([< __ $field _guard >], $($guards,)*), - @munch_fields($($rest)*), - ); - } - }; - (init_slot(): // No `use_data`, so all fields are not structurally pin= ned - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - // Init by-value. - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) =3D> { - { - $(let $field =3D $val;)? - // Initialize the field. - // - // SAFETY: The memory at `slot` is uninitialized. - unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot)= .$field), $field) }; - } - - #[allow(unused_variables)] - // SAFETY: - // - the field is not structurally pinned, since no `use_data` was= required to create this - // initializer, - // - the field has been initialized, - // - the reference is only valid until the end of the initializer. - let $field =3D unsafe { &mut (*$slot).$field }; - - // Create the drop guard: - // - // We rely on macro hygiene to make it impossible for users to acc= ess this local variable. - // We use `paste!` to create new hygiene for `$field`. - $crate::macros::paste! { - // SAFETY: We forget the guard later when initialization has s= ucceeded. - let [< __ $field _guard >] =3D unsafe { - $crate::__internal::DropGuard::new(::core::ptr::addr_of_mu= t!((*$slot).$field)) - }; - - $crate::__init_internal!(init_slot(): - @data($data), - @slot($slot), - @guards([< __ $field _guard >], $($guards,)*), - @munch_fields($($rest)*), - ); - } - }; - (init_slot($use_data:ident): - @data($data:ident), - @slot($slot:ident), - @guards($($guards:ident,)*), - // Init by-value. - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) =3D> { - { - $(let $field =3D $val;)? - // Initialize the field. - // - // SAFETY: The memory at `slot` is uninitialized. - unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot)= .$field), $field) }; - } - // SAFETY: - // - the project function does the correct field projection, - // - the field has been initialized, - // - the reference is only valid until the end of the initializer. - #[allow(unused_variables)] - let $field =3D $crate::macros::paste!(unsafe { $data.[< __project_= $field >](&mut (*$slot).$field) }); - - // Create the drop guard: - // - // We rely on macro hygiene to make it impossible for users to acc= ess this local variable. - // We use `paste!` to create new hygiene for `$field`. - $crate::macros::paste! { - // SAFETY: We forget the guard later when initialization has s= ucceeded. - let [< __ $field _guard >] =3D unsafe { - $crate::__internal::DropGuard::new(::core::ptr::addr_of_mu= t!((*$slot).$field)) - }; - - $crate::__init_internal!(init_slot($use_data): - @data($data), - @slot($slot), - @guards([< __ $field _guard >], $($guards,)*), - @munch_fields($($rest)*), - ); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:path), - @munch_fields(_: { $($code:tt)* }, $($rest:tt)*), - @acc($($acc:tt)*), - ) =3D> { - // code blocks are ignored for the initializer check - $crate::__init_internal!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)*), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:path), - @munch_fields(..Zeroable::init_zeroed() $(,)?), - @acc($($acc:tt)*), - ) =3D> { - // Endpoint, nothing more to munch, create the initializer. Since = the users specified - // `..Zeroable::init_zeroed()`, the slot will already have been ze= roed and all field that have - // not been overwritten are thus zero and initialized. We still ch= eck that all fields are - // actually accessible by using the struct update syntax ourselves. - // We are inside of a closure that is never executed and thus we c= an abuse `slot` to - // get the correct type inference here: - #[allow(unused_assignments)] - unsafe { - let mut zeroed =3D ::core::mem::zeroed(); - // We have to use type inference here to make zeroed have the = correct type. This does - // not get executed, so it has no effect. - ::core::ptr::write($slot, zeroed); - zeroed =3D ::core::mem::zeroed(); - // Here we abuse `paste!` to retokenize `$t`. Declarative macr= os have some internal - // information that is associated to already parsed fragments,= so a path fragment - // cannot be used in this position. Doing the retokenization r= esults in valid rust - // code. - $crate::macros::paste!( - ::core::ptr::write($slot, $t { - $($acc)* - ..zeroed - }); - ); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:path), - @munch_fields($(,)?), - @acc($($acc:tt)*), - ) =3D> { - // Endpoint, nothing more to munch, create the initializer. - // Since we are in the closure that is never called, this will nev= er get executed. - // We abuse `slot` to get the correct type inference here: - // - // SAFETY: TODO. - unsafe { - // Here we abuse `paste!` to retokenize `$t`. Declarative macr= os have some internal - // information that is associated to already parsed fragments,= so a path fragment - // cannot be used in this position. Doing the retokenization r= esults in valid rust - // code. - $crate::macros::paste!( - ::core::ptr::write($slot, $t { - $($acc)* - }); - ); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:path), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - @acc($($acc:tt)*), - ) =3D> { - $crate::__init_internal!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:path), - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - @acc($($acc:tt)*), - ) =3D> { - $crate::__init_internal!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; -} --=20 2.51.2