lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sat, 24 Jun 2023 14:49:05 +0000
From:   Björn Roy Baron <bjorn3_gh@...tonmail.com>
To:     Benno Lossin <benno.lossin@...ton.me>
Cc:     Miguel Ojeda <ojeda@...nel.org>,
        Wedson Almeida Filho <wedsonaf@...il.com>,
        Alex Gaynor <alex.gaynor@...il.com>,
        Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
        Alice Ryhl <aliceryhl@...gle.com>,
        Andreas Hindborg <nmi@...aspace.dk>,
        rust-for-linux@...r.kernel.org, linux-kernel@...r.kernel.org,
        patches@...ts.linux.dev
Subject: Re: [PATCH 1/7] rust: init: consolidate init macros

On Saturday, June 24th, 2023 at 11:24, Benno Lossin <benno.lossin@...ton.me> wrote:

> Merges the implementations of `try_init!` and `try_pin_init!`. These two
> macros are very similar, but use different traits. The new macro
> `__init_internal!` that is now the implementation for both takes these
> traits as parameters.
> 
> This change does not affect any users, as no public API has been
> changed, but it should simplify maintaining the init macros.
> 
> Signed-off-by: Benno Lossin <benno.lossin@...ton.me>

A bit hard to review due to the large blocks of code that were moved, but git show --color-moved didn't show anything weird. Nice to see less code duplication in any case.

Reviewed-by: Björn Roy Baron <bjorn3_gh@...tonmail.com>

> ---
>  rust/kernel/init.rs        | 388 +++----------------------------------
>  rust/kernel/init/macros.rs | 237 +++++++++++++++++++++-
>  2 files changed, 259 insertions(+), 366 deletions(-)
> 
> diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
> index b4332a4ec1f4..d9a91950cba2 100644
> --- a/rust/kernel/init.rs
> +++ b/rust/kernel/init.rs
> @@ -540,11 +540,14 @@ macro_rules! pin_init {
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }) => {
> -        $crate::try_pin_init!(
> +        $crate::__init_internal!(
>              @this($($this)?),
>              @typ($t $(::<$($generics),*>)?),
>              @fields($($fields)*),
>              @error(::core::convert::Infallible),
> +            @data(PinData, use_data),
> +            @has_data(HasPinData, __pin_data),
> +            @construct_closure(pin_init_from_closure),
>          )
>      };
>  }
> @@ -593,205 +596,29 @@ macro_rules! try_pin_init {
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }) => {
> -        $crate::try_pin_init!(
> +        $crate::__init_internal!(
>              @this($($this)?),
>              @typ($t $(::<$($generics),*>)? ),
>              @fields($($fields)*),
>              @error($crate::error::Error),
> +            @data(PinData, use_data),
> +            @has_data(HasPinData, __pin_data),
> +            @construct_closure(pin_init_from_closure),
>          )
>      };
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }? $err:ty) => {
> -        $crate::try_pin_init!(
> +        $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),
>          )
>      };
> -    (
> -        @this($($this:ident)?),
> -        @typ($t:ident $(::<$($generics:ty),*>)?),
> -        @fields($($fields:tt)*),
> -        @error($err:ty),
> -    ) => {{
> -        // We do not want to allow arbitrary returns, so we declare this type 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 pin data from the supplied type.
> -        let data = unsafe {
> -            use $crate::init::__internal::HasPinData;
> -            $t$(::<$($generics),*>)?::__pin_data()
> -        };
> -        // Ensure that `data` really is of type `PinData` and help with type inference:
> -        let init = $crate::init::__internal::PinData::make_closure::<_, __InitOk, $err>(
> -            data,
> -            move |slot| {
> -                {
> -                    // Shadow the structure so it cannot be used to return early.
> -                    struct __InitOk;
> -                    // Create the `this` so it can be referenced by the user inside of the
> -                    // expressions creating the individual fields.
> -                    $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)?
> -                    // Initialize every field.
> -                    $crate::try_pin_init!(init_slot:
> -                        @data(data),
> -                        @slot(slot),
> -                        @munch_fields($($fields)*,),
> -                    );
> -                    // 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)]
> -                    if false {
> -                        $crate::try_pin_init!(make_initializer:
> -                            @slot(slot),
> -                            @type_name($t),
> -                            @munch_fields($($fields)*,),
> -                            @acc(),
> -                        );
> -                    }
> -                    // Forget all guards, since initialization was a success.
> -                    $crate::try_pin_init!(forget_guards:
> -                        @munch_fields($($fields)*,),
> -                    );
> -                }
> -                Ok(__InitOk)
> -            }
> -        );
> -        let init = move |slot| -> ::core::result::Result<(), $err> {
> -            init(slot).map(|__InitOk| ())
> -        };
> -        let init = unsafe { $crate::init::pin_init_from_closure::<_, $err>(init) };
> -        init
> -    }};
> -    (init_slot:
> -        @data($data:ident),
> -        @slot($slot:ident),
> -        @munch_fields($(,)?),
> -    ) => {
> -        // Endpoint of munching, no fields are left.
> -    };
> -    (init_slot:
> -        @data($data:ident),
> -        @slot($slot:ident),
> -        // In-place initialization syntax.
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -    ) => {
> -        let $field = $val;
> -        // Call the initializer.
> -        //
> -        // SAFETY: `slot` is valid, because we are inside of an initializer 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), $field)? };
> -        // Create the drop guard.
> -        //
> -        // We only give access to `&DropGuard`, so it cannot be forgotten via safe code.
> -        //
> -        // SAFETY: We forget the guard later when initialization has succeeded.
> -        let $field = &unsafe {
> -            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> -        };
> -
> -        $crate::try_pin_init!(init_slot:
> -            @data($data),
> -            @slot($slot),
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (init_slot:
> -        @data($data:ident),
> -        @slot($slot:ident),
> -        // Direct value init, this is safe for every field.
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -    ) => {
> -        $(let $field = $val;)?
> -        // Initialize the field.
> -        //
> -        // SAFETY: The memory at `slot` is uninitialized.
> -        unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
> -        // Create the drop guard:
> -        //
> -        // We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
> -        //
> -        // SAFETY: We forget the guard later when initialization has succeeded.
> -        let $field = &unsafe {
> -            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> -        };
> -
> -        $crate::try_pin_init!(init_slot:
> -            @data($data),
> -            @slot($slot),
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields($(,)?),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        // Endpoint, nothing more to munch, create the initializer.
> -        // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to
> -        // get the correct type inference here:
> -        unsafe {
> -            ::core::ptr::write($slot, $t {
> -                $($acc)*
> -            });
> -        }
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        $crate::try_pin_init!(make_initializer:
> -            @slot($slot),
> -            @type_name($t),
> -            @munch_fields($($rest)*),
> -            @acc($($acc)* $field: ::core::panic!(),),
> -        );
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        $crate::try_pin_init!(make_initializer:
> -            @slot($slot),
> -            @type_name($t),
> -            @munch_fields($($rest)*),
> -            @acc($($acc)* $field: ::core::panic!(),),
> -        );
> -    };
> -    (forget_guards:
> -        @munch_fields($(,)?),
> -    ) => {
> -        // Munching finished.
> -    };
> -    (forget_guards:
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -    ) => {
> -        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> -
> -        $crate::try_pin_init!(forget_guards:
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (forget_guards:
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -    ) => {
> -        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> -
> -        $crate::try_pin_init!(forget_guards:
> -            @munch_fields($($rest)*),
> -        );
> -    };
>  }
> 
>  /// Construct an in-place initializer for `struct`s.
> @@ -816,11 +643,14 @@ macro_rules! init {
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }) => {
> -        $crate::try_init!(
> +        $crate::__init_internal!(
>              @this($($this)?),
>              @typ($t $(::<$($generics),*>)?),
>              @fields($($fields)*),
>              @error(::core::convert::Infallible),
> +            @data(InitData, /*no use_data*/),
> +            @has_data(HasInitData, __init_data),
> +            @construct_closure(init_from_closure),
>          )
>      }
>  }
> @@ -863,199 +693,29 @@ macro_rules! try_init {
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }) => {
> -        $crate::try_init!(
> +        $crate::__init_internal!(
>              @this($($this)?),
>              @typ($t $(::<$($generics),*>)?),
>              @fields($($fields)*),
>              @error($crate::error::Error),
> +            @data(InitData, /*no use_data*/),
> +            @has_data(HasInitData, __init_data),
> +            @construct_closure(init_from_closure),
>          )
>      };
>      ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
>          $($fields:tt)*
>      }? $err:ty) => {
> -        $crate::try_init!(
> +        $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),
>          )
>      };
> -    (
> -        @this($($this:ident)?),
> -        @typ($t:ident $(::<$($generics:ty),*>)?),
> -        @fields($($fields:tt)*),
> -        @error($err:ty),
> -    ) => {{
> -        // We do not want to allow arbitrary returns, so we declare this type 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 init data from the supplied type.
> -        let data = unsafe {
> -            use $crate::init::__internal::HasInitData;
> -            $t$(::<$($generics),*>)?::__init_data()
> -        };
> -        // Ensure that `data` really is of type `InitData` and help with type inference:
> -        let init = $crate::init::__internal::InitData::make_closure::<_, __InitOk, $err>(
> -            data,
> -            move |slot| {
> -                {
> -                    // Shadow the structure so it cannot be used to return early.
> -                    struct __InitOk;
> -                    // Create the `this` so it can be referenced by the user inside of the
> -                    // expressions creating the individual fields.
> -                    $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)?
> -                    // Initialize every field.
> -                    $crate::try_init!(init_slot:
> -                        @slot(slot),
> -                        @munch_fields($($fields)*,),
> -                    );
> -                    // 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)]
> -                    if false {
> -                        $crate::try_init!(make_initializer:
> -                            @slot(slot),
> -                            @type_name($t),
> -                            @munch_fields($($fields)*,),
> -                            @acc(),
> -                        );
> -                    }
> -                    // Forget all guards, since initialization was a success.
> -                    $crate::try_init!(forget_guards:
> -                        @munch_fields($($fields)*,),
> -                    );
> -                }
> -                Ok(__InitOk)
> -            }
> -        );
> -        let init = move |slot| -> ::core::result::Result<(), $err> {
> -            init(slot).map(|__InitOk| ())
> -        };
> -        let init = unsafe { $crate::init::init_from_closure::<_, $err>(init) };
> -        init
> -    }};
> -    (init_slot:
> -        @slot($slot:ident),
> -        @munch_fields( $(,)?),
> -    ) => {
> -        // Endpoint of munching, no fields are left.
> -    };
> -    (init_slot:
> -        @slot($slot:ident),
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -    ) => {
> -        let $field = $val;
> -        // Call the initializer.
> -        //
> -        // SAFETY: `slot` is valid, because we are inside of an initializer closure, we
> -        // return when an error/panic occurs.
> -        unsafe {
> -            $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?;
> -        }
> -        // Create the drop guard.
> -        //
> -        // We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
> -        //
> -        // SAFETY: We forget the guard later when initialization has succeeded.
> -        let $field = &unsafe {
> -            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> -        };
> -
> -        $crate::try_init!(init_slot:
> -            @slot($slot),
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (init_slot:
> -        @slot($slot:ident),
> -        // Direct value init.
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -    ) => {
> -        $(let $field = $val;)?
> -        // Call the initializer.
> -        //
> -        // SAFETY: The memory at `slot` is uninitialized.
> -        unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
> -        // Create the drop guard.
> -        //
> -        // We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
> -        //
> -        // SAFETY: We forget the guard later when initialization has succeeded.
> -        let $field = &unsafe {
> -            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> -        };
> -
> -        $crate::try_init!(init_slot:
> -            @slot($slot),
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields( $(,)?),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        // Endpoint, nothing more to munch, create the initializer.
> -        // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to
> -        // get the correct type inference here:
> -        unsafe {
> -            ::core::ptr::write($slot, $t {
> -                $($acc)*
> -            });
> -        }
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        $crate::try_init!(make_initializer:
> -            @slot($slot),
> -            @type_name($t),
> -            @munch_fields($($rest)*),
> -            @acc($($acc)*$field: ::core::panic!(),),
> -        );
> -    };
> -    (make_initializer:
> -        @slot($slot:ident),
> -        @type_name($t:ident),
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -        @acc($($acc:tt)*),
> -    ) => {
> -        $crate::try_init!(make_initializer:
> -            @slot($slot),
> -            @type_name($t),
> -            @munch_fields($($rest)*),
> -            @acc($($acc)*$field: ::core::panic!(),),
> -        );
> -    };
> -    (forget_guards:
> -        @munch_fields($(,)?),
> -    ) => {
> -        // Munching finished.
> -    };
> -    (forget_guards:
> -        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> -    ) => {
> -        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> -
> -        $crate::try_init!(forget_guards:
> -            @munch_fields($($rest)*),
> -        );
> -    };
> -    (forget_guards:
> -        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> -    ) => {
> -        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> -
> -        $crate::try_init!(forget_guards:
> -            @munch_fields($($rest)*),
> -        );
> -    };
>  }
> 
>  /// A pin-initializer for the type `T`.
> diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs
> index 00aa4e956c0a..fbaebd34f218 100644
> --- a/rust/kernel/init/macros.rs
> +++ b/rust/kernel/init/macros.rs
> @@ -1,10 +1,12 @@
>  // SPDX-License-Identifier: Apache-2.0 OR MIT
> 
>  //! This module provides the macros that actually implement the proc-macros `pin_data` and
> -//! `pinned_drop`.
> +//! `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. Use the proc-macros instead.
> +//! in a certain format which is internal. If used incorrectly, these macros 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.
> @@ -980,3 +982,234 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
>          }
>      };
>  }
> +
> +/// 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.
> +/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
> +/// - `make_initializer`: recursively create the struct initializer that guarantees that every
> +///   field has been initialized exactly once.
> +/// - `forget_guards`: recursively forget the drop guards for every field.
> +#[doc(hidden)]
> +#[macro_export]
> +macro_rules! __init_internal {
> +    (
> +        @this($($this:ident)?),
> +        @typ($t:ident $(::<$($generics:ty),*>)?),
> +        @fields($($fields:tt)*),
> +        @error($err:ty),
> +        // Either `PinData` or `InitData`, `$use_data` should only be present 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),
> +    ) => {{
> +        // We do not want to allow arbitrary returns, so we declare this type 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.
> +        let data = unsafe {
> +            use $crate::init::__internal::$has_data;
> +            $t$(::<$($generics),*>)?::$get_data()
> +        };
> +        // Ensure that `data` really is of type `$data` and help with type inference:
> +        let init = $crate::init::__internal::$data::make_closure::<_, __InitOk, $err>(
> +            data,
> +            move |slot| {
> +                {
> +                    // Shadow the structure so it cannot be used to return early.
> +                    struct __InitOk;
> +                    // Create the `this` so it can be referenced by the user inside of the
> +                    // expressions creating the individual fields.
> +                    $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)?
> +                    // Initialize every field.
> +                    $crate::__init_internal!(init_slot($($use_data)?):
> +                        @data(data),
> +                        @slot(slot),
> +                        @munch_fields($($fields)*,),
> +                    );
> +                    // 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)]
> +                    if false {
> +                        $crate::__init_internal!(make_initializer:
> +                            @slot(slot),
> +                            @type_name($t),
> +                            @munch_fields($($fields)*,),
> +                            @acc(),
> +                        );
> +                    }
> +                    // Forget all guards, since initialization was a success.
> +                    $crate::__init_internal!(forget_guards:
> +                        @munch_fields($($fields)*,),
> +                    );
> +                }
> +                Ok(__InitOk)
> +            }
> +        );
> +        let init = move |slot| -> ::core::result::Result<(), $err> {
> +            init(slot).map(|__InitOk| ())
> +        };
> +        let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) };
> +        init
> +    }};
> +    (init_slot($($use_data:ident)?):
> +        @data($data:ident),
> +        @slot($slot:ident),
> +        @munch_fields($(,)?),
> +    ) => {
> +        // Endpoint of munching, no fields are left.
> +    };
> +    (init_slot($use_data:ident): // use_data is present, so we use the `data` to init fields.
> +        @data($data:ident),
> +        @slot($slot:ident),
> +        // In-place initialization syntax.
> +        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> +    ) => {
> +        let $field = $val;
> +        // Call the initializer.
> +        //
> +        // SAFETY: `slot` is valid, because we are inside of an initializer 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), $field)? };
> +        // Create the drop guard.
> +        //
> +        // We only give access to `&DropGuard`, so it cannot be forgotten via safe code.
> +        //
> +        // SAFETY: We forget the guard later when initialization has succeeded.
> +        let $field = &unsafe {
> +            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> +        };
> +
> +        $crate::__init_internal!(init_slot($use_data):
> +            @data($data),
> +            @slot($slot),
> +            @munch_fields($($rest)*),
> +        );
> +    };
> +    (init_slot(): // no use_data, so we use `Init::__init` directly.
> +        @data($data:ident),
> +        @slot($slot:ident),
> +        // In-place initialization syntax.
> +        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> +    ) => {
> +        let $field = $val;
> +        // Call the initializer.
> +        //
> +        // SAFETY: `slot` is valid, because we are inside of an initializer closure, we
> +        // return when an error/panic occurs.
> +        unsafe { $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))? };
> +        // Create the drop guard.
> +        //
> +        // We only give access to `&DropGuard`, so it cannot be forgotten via safe code.
> +        //
> +        // SAFETY: We forget the guard later when initialization has succeeded.
> +        let $field = &unsafe {
> +            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> +        };
> +
> +        $crate::__init_internal!(init_slot():
> +            @data($data),
> +            @slot($slot),
> +            @munch_fields($($rest)*),
> +        );
> +    };
> +    (init_slot($($use_data:ident)?):
> +        @data($data:ident),
> +        @slot($slot:ident),
> +        // Init by-value.
> +        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> +    ) => {
> +        $(let $field = $val;)?
> +        // Initialize the field.
> +        //
> +        // SAFETY: The memory at `slot` is uninitialized.
> +        unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
> +        // Create the drop guard:
> +        //
> +        // We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
> +        //
> +        // SAFETY: We forget the guard later when initialization has succeeded.
> +        let $field = &unsafe {
> +            $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
> +        };
> +
> +        $crate::__init_internal!(init_slot($($use_data)?):
> +            @data($data),
> +            @slot($slot),
> +            @munch_fields($($rest)*),
> +        );
> +    };
> +    (make_initializer:
> +        @slot($slot:ident),
> +        @type_name($t:ident),
> +        @munch_fields($(,)?),
> +        @acc($($acc:tt)*),
> +    ) => {
> +        // Endpoint, nothing more to munch, create the initializer.
> +        // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to
> +        // get the correct type inference here:
> +        unsafe {
> +            ::core::ptr::write($slot, $t {
> +                $($acc)*
> +            });
> +        }
> +    };
> +    (make_initializer:
> +        @slot($slot:ident),
> +        @type_name($t:ident),
> +        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> +        @acc($($acc:tt)*),
> +    ) => {
> +        $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:ident),
> +        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> +        @acc($($acc:tt)*),
> +    ) => {
> +        $crate::__init_internal!(make_initializer:
> +            @slot($slot),
> +            @type_name($t),
> +            @munch_fields($($rest)*),
> +            @acc($($acc)* $field: ::core::panic!(),),
> +        );
> +    };
> +    (forget_guards:
> +        @munch_fields($(,)?),
> +    ) => {
> +        // Munching finished.
> +    };
> +    (forget_guards:
> +        @munch_fields($field:ident <- $val:expr, $($rest:tt)*),
> +    ) => {
> +        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> +
> +        $crate::__init_internal!(forget_guards:
> +            @munch_fields($($rest)*),
> +        );
> +    };
> +    (forget_guards:
> +        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
> +    ) => {
> +        unsafe { $crate::init::__internal::DropGuard::forget($field) };
> +
> +        $crate::__init_internal!(forget_guards:
> +            @munch_fields($($rest)*),
> +        );
> +    };
> +}
> 
> base-commit: d2e3115d717197cb2bc020dd1f06b06538474ac3
> --
> 2.41.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ