From patchwork Wed Jul 19 14:20:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122655 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2483235vqt; Wed, 19 Jul 2023 07:36:17 -0700 (PDT) X-Google-Smtp-Source: APBJJlHX3N84Vcry1XEqgNNwnSq4EZY254Ae7/uxq9KhvudTo+9IVEQO2on/XfEP8RwkO+wSp+Ky X-Received: by 2002:ac2:42c8:0:b0:4f8:680a:68f8 with SMTP id n8-20020ac242c8000000b004f8680a68f8mr43193lfl.41.1689777376893; Wed, 19 Jul 2023 07:36:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777376; cv=none; d=google.com; s=arc-20160816; b=NAOxf/UZ/2h/3mkdx+Lx75B7dyY9qvjobgWEC4+fBY9CnKX/27l76cGR92/RbqLUUr pydpUwzAcPup8whmYzVc2FzRnoKKLk1yUGNrvcU3vw0tob0FHnMH+w9HCJe904zgr8O6 wvfqTOw6SO/01NKAQNycAlWEWcxpoxk5i0HwoYY6vRwjJ7rtk4j9J1uDOcxsoLs2Dgcu +V+7UqYmiJaqI74Rl0WpISMT/n25qdbH9TnbvAPa0aPKlnTRdvE9JiqtsXXBVVmboQEN 1HTRd9nt+3WOi9JNw1LorxUza5bzBNiPJt8udGNbfBWPTl/xOGyQJ7d0hdWB2KylR3zN hNyg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=lXqghVImS0vxXNtqjpZFp5NMfXzv21vyerlAfaphOGQ=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=xYXQrZEj3ZKpslXyE1r08dLVa0AQ+gzQFPeMLjxCooum146G3SM/7at07nJfdibWI3 GB4HyJkfjQnbV+hklRA+InW6g+qUS25Z2ZSw23KXGIEQ0h7LrQ7Rs9sozHwNc03kNxTz kb2JALOZzTQf87po3Xw5tx0CMVmOgAobjYRd8KVZxg4HuoewxcK1W4oG7Q0aJ4XET8XY kLVSWAIEc9PY0CuoHLYyEOkY02Nu6WlB2BRvPBLMiKAUAiFnfJT4eiPvrtD8M8QP4PHX X1YWiHSI5DzrF/r3KznTBd9GKtWrH9WQJFIuH10NJTempItSfCNBJ/lPFr+gC+7hZcnu N30Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=TsG8QUdh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id f22-20020aa7d856000000b005203311fd98si3190281eds.131.2023.07.19.07.35.49; Wed, 19 Jul 2023 07:36:16 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=TsG8QUdh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230376AbjGSOUn (ORCPT + 99 others); Wed, 19 Jul 2023 10:20:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50282 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230436AbjGSOUi (ORCPT ); Wed, 19 Jul 2023 10:20:38 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 516EA1737 for ; Wed, 19 Jul 2023 07:20:32 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776429; x=1690035629; bh=lXqghVImS0vxXNtqjpZFp5NMfXzv21vyerlAfaphOGQ=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=TsG8QUdhtaOgMhbaaVRDhyNO8ocv7bM01uQeYV0N3f2xkCPVpcuSkN0/6Zu72zRIr HtqwCnlVMciJJOnuqmQkdsDrDj9395F55CDD7dvib0kcYYQ1vc82VE2szAPWqqU5T+ Jdd4uxWFTIGjxFJtdTP1ajj9TEJLPlkYGak51qjutEgdmrZIrKZ65iPYIERJ7/d+3L QN1c4WMb8zOIpz5aMRv+RwvXU0XmNus8PcLAKsLQ3Y7NZ0fOTzv+Lfn1nlrdfuimNB mZIVKG/maovc8Vat0cEUhHEGTqPgiZTdnBDbR750lZmYNkVAfoGDyfd97nMY7trE7B E/kJxSoxw++nw== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 01/12] rust: init: consolidate init macros Message-ID: <20230719141918.543938-2-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771860003120783843 X-GMAIL-MSGID: 1771860003120783843 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. Reviewed-by: Björn Roy Baron Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl --- v1 -> v2: * added Reviewed-by from Björn 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 e05563aad2ed..d431d0b153a2 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -548,11 +548,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), ) }; } @@ -601,205 +604,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. @@ -824,11 +651,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), ) } } @@ -871,199 +701,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)*), + ); + }; +} From patchwork Wed Jul 19 14:20:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122646 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2475143vqt; Wed, 19 Jul 2023 07:22:54 -0700 (PDT) X-Google-Smtp-Source: APBJJlH36V/eKQnr83UU1xSkZfR8JqRN69AYTRZz15nxQo30XEssYqQNGmvotbjtkUFeC6++5M3+ X-Received: by 2002:a05:6a20:144c:b0:132:c1fd:aaab with SMTP id a12-20020a056a20144c00b00132c1fdaaabmr2864737pzi.30.1689776573904; Wed, 19 Jul 2023 07:22:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689776573; cv=none; d=google.com; s=arc-20160816; b=PnynvB+fDJqeVCVSkl9WFMVPJm+p2B3TyyLa1tcwWoQLyz7jGt0CHgT8TCEe90c454 hBg5/wi0hjjAO9+bwSaoniXZgsgpQnQfKNeO8Tk+UsYsnqsZSfyYQJKYO/CrmWqKtmYc +slO5zp9X30JgDa+UbRoDDQ7VWcoFp8MNBOH9APDVbM0E6rfKspoSjNqJWqKxfl2GG9Y TgIiED/irjTKL6jBGkzX7/kSaRWYIUWJxZm0K66evdV32SzLVgJvoi0FOiXVecSI7I8f Xe5OUtaq4c6Il8LzWAfFnT6lub7staeH1mI9ztDUKNOJFDU8qGw/P3+SAIR6kQttWNja L/BA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=183b5PAZnhFCxp/oOLo9nlLEFrHHHEv1Gt8/V3juWA8=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=UMfltMgDJL9Pt5NYhtLAyX8Svyd3iN2ngxms0axna9K9XD3rc8kX2gcblrEM1jJkBp RxfGGT2BPr1/z2/f2sYzMmwl0CzSt9J4Hhm2U/UaQWnc6obSf3dpCkhx//odimfFGvfl MMvVRGb2PMj69ljFdivQ5/oTDopIGazh+CRpugfYksW81Gu06kMjr/uvtXOeA6Yho89+ paIgMUhKiCoVoLxyGnimv6feuVMxYMNZTdiXhbuSALVfFt4OqG3aiXYVcaVSr7B5h3FU r8qcDaqZglZ4lYVbo96w2W8tbM2MRzpDz9FNW1pwebpaf2hbM7Gyb9CKqTN3l21btm0Z iKAA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=ZkWznvew; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id cm14-20020a056a00338e00b006686d07f4b6si3406321pfb.327.2023.07.19.07.22.40; Wed, 19 Jul 2023 07:22:53 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=ZkWznvew; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231190AbjGSOUk (ORCPT + 99 others); Wed, 19 Jul 2023 10:20:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50282 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231143AbjGSOUh (ORCPT ); Wed, 19 Jul 2023 10:20:37 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF51A1724 for ; Wed, 19 Jul 2023 07:20:29 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:23 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776427; x=1690035627; bh=183b5PAZnhFCxp/oOLo9nlLEFrHHHEv1Gt8/V3juWA8=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=ZkWznvewtTc2Zfd3W9Yvv2Bupu9uWWK5mPAieCwdpT0tqsvRT3KXVvtCpyLAO7ZR+ 6+UWtIFCcjsAAzWicXpOaGb8xE7Ww6gFXFeiXYLopba2JdIeb3LaAjUwGGb/8835ch 6039ckKVp4EyDHKBC+SEf1q6NqCfQ3YqjbPgWmKiTZ2iVthcxecakVZVYeuROeqMqW NXeKiDd+fYLKUYoVx45rnH8MGjtNkAVI3Q7yU6XYN/r+pRQocdATKzA1rJk11mTsbc v2WAlt0bzKpD3urZQ+ZW/vDPQJpYLYAXZQGOTUxXpvd+2adqcMjSku2ZJwL3zR5VZu yj4vsYo9NjI1A== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 02/12] rust: add derive macro for `Zeroable` Message-ID: <20230719141918.543938-3-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859160421830128 X-GMAIL-MSGID: 1771859160421830128 Add a derive proc-macro for the `Zeroable` trait. The macro supports structs where every field implements the `Zeroable` trait. This way `unsafe` implementations can be avoided. The macro is split into two parts: - a proc-macro to parse generics into impl and ty generics, - a declarative macro that expands to the impl block. Suggested-by: Asahi Lina Reviewed-by: Gary Guo Reviewed-by: Björn Roy Baron Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl --- v1 -> v2: * fix Zeroable path * add Reviewed-by from Gary and Björn rust/kernel/init/macros.rs | 28 ++++++++++++++++++++++++++++ rust/kernel/prelude.rs | 2 +- rust/macros/lib.rs | 20 ++++++++++++++++++++ rust/macros/quote.rs | 6 ++++++ rust/macros/zeroable.rs | 25 +++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 rust/macros/zeroable.rs diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index fbaebd34f218..c50429173fc7 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1213,3 +1213,31 @@ macro_rules! __init_internal { ); }; } + +#[doc(hidden)] +#[macro_export] +macro_rules! __derive_zeroable { + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::init::Zeroable for $name<$($ty_generics)*> + where + $($field_ty: $crate::init::Zeroable,)* + $($($whr)*)? + {} + }; +} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index c28587d68ebc..ae21600970b3 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -18,7 +18,7 @@ pub use alloc::{boxed::Box, vec::Vec}; #[doc(no_inline)] -pub use macros::{module, pin_data, pinned_drop, vtable}; +pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; pub use super::build_assert; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index b4bc44c27bd4..fd7a815e68a8 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -11,6 +11,7 @@ mod pin_data; mod pinned_drop; mod vtable; +mod zeroable; use proc_macro::TokenStream; @@ -343,3 +344,22 @@ pub fn paste(input: TokenStream) -> TokenStream { paste::expand(&mut tokens); tokens.into_iter().collect() } + +/// Derives the [`Zeroable`] trait for the given struct. +/// +/// This can only be used for structs where every field implements the [`Zeroable`] trait. +/// +/// # Examples +/// +/// ```rust +/// #[derive(Zeroable)] +/// pub struct DriverData { +/// id: i64, +/// buf_ptr: *mut u8, +/// len: usize, +/// } +/// ``` +#[proc_macro_derive(Zeroable)] +pub fn derive_zeroable(input: TokenStream) -> TokenStream { + zeroable::derive(input) +} diff --git a/rust/macros/quote.rs b/rust/macros/quote.rs index dddbb4e6f4cb..b76c198a4ed5 100644 --- a/rust/macros/quote.rs +++ b/rust/macros/quote.rs @@ -124,6 +124,12 @@ macro_rules! quote_spanned { )); quote_spanned!(@proc $v $span $($tt)*); }; + (@proc $v:ident $span:ident ; $($tt:tt)*) => { + $v.push(::proc_macro::TokenTree::Punct( + ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone) + )); + quote_spanned!(@proc $v $span $($tt)*); + }; (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => { $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span))); quote_spanned!(@proc $v $span $($tt)*); diff --git a/rust/macros/zeroable.rs b/rust/macros/zeroable.rs new file mode 100644 index 000000000000..cddb866c44ef --- /dev/null +++ b/rust/macros/zeroable.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 + +use crate::helpers::{parse_generics, Generics}; +use proc_macro::TokenStream; + +pub(crate) fn derive(input: TokenStream) -> TokenStream { + let ( + Generics { + impl_generics, + ty_generics, + }, + mut rest, + ) = parse_generics(input); + // This should be the body of the struct `{...}`. + let last = rest.pop(); + quote! { + ::kernel::__derive_zeroable!( + parse_input: + @sig(#(#rest)*), + @impl_generics(#(#impl_generics)*), + @ty_generics(#(#ty_generics)*), + @body(#last), + ); + } +} From patchwork Wed Jul 19 14:20:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122660 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2485160vqt; Wed, 19 Jul 2023 07:39:21 -0700 (PDT) X-Google-Smtp-Source: APBJJlHtnDceaYi4gCNllUszRemkVBRbPLW+7uIUmrPSpGfmcK/biID3PTkyUmoJewrch6ihZvAf X-Received: by 2002:aa7:d659:0:b0:51d:a488:3b3d with SMTP id v25-20020aa7d659000000b0051da4883b3dmr2541458edr.35.1689777560674; Wed, 19 Jul 2023 07:39:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777560; cv=none; d=google.com; s=arc-20160816; b=f9x6asxl+RXfDWiimlwmBhbeSOtsuqqr/l9r+7QdSDG3G+uqyWjio2hRUbo+QPZ1S+ hRky8WhBrWOpl1D8a9sluQ8BFlw7pzXBLcAX3a8RXDH0isCTeySr1sF/lfVluHGxaT8R 7tsAQ/EzR9a344ROaPdOjSlRfVLnZtISSxP8ztSJA9VHuP7RCUIC8xaMGFuAwnKPFW5o 84Okj5WdQvqLeH1tOKg9UdGRGXB5zg3IlbKjnqjuQaPpMHHfDgn86RFlBreje8diOi1Q KYeyYK86fA2uYFoebAFx5CEZuQlttT/G5Hwv+KtffYGVNEhWcORbRqxXdktHtaDZe1t1 59ag== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=SS2q1NjexBrjmn/WRxMHKEqapQDfI+FDXAjjD6I2TmQ=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=s7TZualFv6i6zmYaNuweDO38oe/A7bRPvRJnnnYDNMbl6nBIEDI4LpJv/BD1lFkFqH k8/inM12Qw1IZB1G7/vQ9Cwyg4V0wJ4tKlInhRrKtbrHQCXoy0R4i1p+obmLxJjACRei ZAChpMLrb2j2PRbzm+sdBRxv5301YeNAxXjlOM7j4MrZ3d6yuPOJoWuW/QUQw3jIJnt1 A0afrOuEPKpF0y3DVHTNFzVJvfHCM1PubSqi5/kwmHUiaBXBrBFRdHk5ttBG/weOXFpx Lp0fCoOjoLFWQmQ2/sGcvkkCaH4B/BpllaIiCjOXKNs/tfWnQJTLL9uaewkF7EbXSUgn UrBA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=f2ZPvplH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j1-20020a50ed01000000b00521a8adfdebsi2890447eds.601.2023.07.19.07.38.56; Wed, 19 Jul 2023 07:39:20 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=f2ZPvplH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231524AbjGSOVA (ORCPT + 99 others); Wed, 19 Jul 2023 10:21:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231529AbjGSOUy (ORCPT ); Wed, 19 Jul 2023 10:20:54 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6AECC1723 for ; Wed, 19 Jul 2023 07:20:47 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776445; x=1690035645; bh=SS2q1NjexBrjmn/WRxMHKEqapQDfI+FDXAjjD6I2TmQ=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=f2ZPvplHFjBE4cxEKAJzhCiZ/I6AMsGvCfpV0CraUr/DUOtlkmGHVBMUNVdsG21uN 06Uf3E+t/OWxWPJ39n5iiHmZnwbL3DUZBzq0l2HmpgdsZtoF1jdbHG9vjj/L4+aTn1 gyPQ89zBWcalOz/YnDYGDXAJfcGB9wWQtb+8fXLIxECrwauIAf3tI42HH/dCLnxCen TdnSw83mmoMgYWlDdCtFtCOShyRKMEJVAmjlxjRKdUT9q9JM0+KKhWSHUVnyaPLERR YN8lgxVhQo95K5knFCpwaMRFUo9JAU3eb2LcR2mjGL77HW+qo6QVh/ojTvZSiQP5Xn UR6I7O4dj6Psw== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 03/12] rust: init: make guards in the init macros hygienic Message-ID: <20230719141918.543938-4-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771860195887142034 X-GMAIL-MSGID: 1771860195887142034 Use hygienic identifiers for the guards instead of the field names. This makes the init macros feel more like normal struct initializers, since assigning identifiers with the name of a field does not create conflicts. Also change the internals of the guards, no need to make the `forget` function `unsafe`, since users cannot access the guards anyways. Now the guards are carried directly on the stack and have no extra `Cell` field that marks if they have been forgotten or not, instead they are just forgotten via `mem::forget`. Suggested-by: Asahi Lina Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl --- v1 -> v2: * use Gary's `paste!` macro to create the guard hygiene rust/kernel/init.rs | 1 - rust/kernel/init/__internal.rs | 25 ++----- rust/kernel/init/macros.rs | 116 +++++++++++++++------------------ 3 files changed, 56 insertions(+), 86 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index d431d0b153a2..0120674b451e 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -216,7 +216,6 @@ use alloc::boxed::Box; use core::{ alloc::AllocError, - cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 44751fb62b51..7abd1fb65e41 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -174,7 +174,6 @@ pub fn init(self: Pin<&mut Self>, init: impl PinInit) -> Result { ptr: *mut T, - do_drop: Cell, } impl DropGuard { @@ -190,32 +189,16 @@ impl DropGuard { /// - will not be dropped by any other means. #[inline] pub unsafe fn new(ptr: *mut T) -> Self { - Self { - ptr, - do_drop: Cell::new(true), - } - } - - /// Prevents this guard from dropping the supplied pointer. - /// - /// # Safety - /// - /// This function is unsafe in order to prevent safe code from forgetting this guard. It should - /// only be called by the macros in this module. - #[inline] - pub unsafe fn forget(&self) { - self.do_drop.set(false); + Self { ptr } } } impl Drop for DropGuard { #[inline] fn drop(&mut self) { - if self.do_drop.get() { - // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function - // ensuring that this operation is safe. - unsafe { ptr::drop_in_place(self.ptr) } - } + // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function + // ensuring that this operation is safe. + unsafe { ptr::drop_in_place(self.ptr) } } } diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index c50429173fc7..c5f977f52d0c 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -992,7 +992,6 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> /// - `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 { @@ -1032,6 +1031,7 @@ macro_rules! __init_internal { $crate::__init_internal!(init_slot($($use_data)?): @data(data), @slot(slot), + @guards(), @munch_fields($($fields)*,), ); // We use unreachable code to ensure that all fields have been mentioned exactly @@ -1046,10 +1046,6 @@ macro_rules! __init_internal { @acc(), ); } - // Forget all guards, since initialization was a success. - $crate::__init_internal!(forget_guards: - @munch_fields($($fields)*,), - ); } Ok(__InitOk) } @@ -1063,13 +1059,17 @@ macro_rules! __init_internal { (init_slot($($use_data:ident)?): @data($data:ident), @slot($slot:ident), + @guards($($guards:ident,)*), @munch_fields($(,)?), ) => { - // Endpoint of munching, no fields are left. + // 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): // 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)*), ) => { @@ -1080,24 +1080,28 @@ macro_rules! __init_internal { // 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. + // Create the drop guard: // - // 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)) - }; + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for $field. + ::kernel::macros::paste! { + // 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)*), - ); + $crate::__init_internal!(init_slot($use_data): + @data($data), + @slot($slot), + @guards([<$field>], $($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)*), ) => { @@ -1107,24 +1111,28 @@ macro_rules! __init_internal { // 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. + // Create the drop guard: // - // 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)) - }; + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for $field. + ::kernel::macros::paste! { + // 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)*), - ); + $crate::__init_internal!(init_slot(): + @data($data), + @slot($slot), + @guards([<$field>], $($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)*), ) => { @@ -1135,18 +1143,21 @@ macro_rules! __init_internal { 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)) - }; + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for $field. + ::kernel::macros::paste! { + // 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)*), - ); + $crate::__init_internal!(init_slot($($use_data)?): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } }; (make_initializer: @slot($slot:ident), @@ -1189,29 +1200,6 @@ macro_rules! __init_internal { @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)*), - ); - }; } #[doc(hidden)] From patchwork Wed Jul 19 14:20:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122647 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2476396vqt; Wed, 19 Jul 2023 07:24:54 -0700 (PDT) X-Google-Smtp-Source: APBJJlHXwKC9mgfINfVqQURn19ZMiyt6R3+7GLyG+GEfOUe2p2KTrUw8P8mJBx4R1dZTKESTBHz/ X-Received: by 2002:a19:8c05:0:b0:4f9:6842:afc with SMTP id o5-20020a198c05000000b004f968420afcmr2568lfd.64.1689776694305; Wed, 19 Jul 2023 07:24:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689776694; cv=none; d=google.com; s=arc-20160816; b=zUuAT9aLGmeBgu+u0fBiqq5WjiQTx6BqbM+7duUiWh+CCcairDD77r3p0YYtGVyxeJ MlpSpOo59zxieGjVN2dpoZf8ewJ/gOmaIMdH9eGTP0vHwurAF9vSaW6BWjFwYUogolq6 AVtNJuIXOpJ3StZnNh5zro17XOVZ4jC+7s9h+l3IFX3z1k60yrv17+v6Ohi+jiDCmu5n Xh5aF3zSVpmbZ3IaXSPbYFHoota5bCflOwoZfpoR7IoANiSfClV++D1Pg7ybGlIwV+zk 8G6C4GuPwtAdCKwIAb9LeX8v2cNxZmlCcxWemFjxOLXiPgiNEy6hjDep7PwLUs7lCzbA 4MNw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=DsEfSlKtIhyTB7NkpS5sssxEHNqI+QqAvnsnKYAwLtk=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=SoQ9XxInOOjAcgZnQlnMyYoAxFVQ05lwgPrebFlKGMuLyZ976hH+53Lq87IsZ+30hV l6nZ675jSD53rdELuzJLr3xn5k3Ez30na1p6quYdVBXZKVONmC9u4oDwBab5CPXNBYCY NxkdTMQ4/KM/DXW2ELw1JwMpKUWiYhFQkHz5XH/OsCtpHhCe1eEIFsxkthJD7UcJ3qiF iPfJeeQps/PE15bYuNfPYriHO+XOJzQcK7ujP3RIPH6WvEW4MeA5KCLzzjIci6XvqbyU NMv2JNK5/EHVjJhPbhCSDgkC9vND0Hc9AmQaVPd/BChGjAkCqBV5Q0te7H0v8LUKEh9Y BRkQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=bC5l9XnA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e25-20020a50fb99000000b0051bec40640bsi3035470edq.603.2023.07.19.07.24.30; Wed, 19 Jul 2023 07:24:54 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=bC5l9XnA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231165AbjGSOU5 (ORCPT + 99 others); Wed, 19 Jul 2023 10:20:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231516AbjGSOUx (ORCPT ); Wed, 19 Jul 2023 10:20:53 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0E2651993; Wed, 19 Jul 2023 07:20:44 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:36 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776443; x=1690035643; bh=DsEfSlKtIhyTB7NkpS5sssxEHNqI+QqAvnsnKYAwLtk=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=bC5l9XnAlrfdaq2S5N8x5zKK+FHAetJ5Qoe3fWVLWY0MN12Z6bYFJOnh7qF1QhQ8A 7Y8++xHkylHtv06khzindeO9YELBrZiRYIJwXZ5JgQODdCPOSBuf0A5hYME84tJ/0X uWkzgAF9ipSb5S4EmVjrU/M4Di2j4hoWBmmgMubB1zQrWzquDMRDMhdfkimwq/4dTB paPXsBuQL1rrWJr3ePiYKVTpH3bOH6nptIry5TmBDyQu0iSjSl/sPfB4HYBK2Xiq8d 5yCe/yrjOAtNt21S3EGzfW99kSq+/Jp9s4AJb+XEbiVZyHVrburFMl321d96JmnDXB 4hzuS60K6qpeA== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 04/12] rust: init: wrap type checking struct initializers in a closure Message-ID: <20230719141918.543938-5-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859286731113927 X-GMAIL-MSGID: 1771859286731113927 In the implementation of the init macros there is a `if false` statement that type checks the initializer to ensure every field is initialized. Since the next patch has a stack variable to store the struct, the function might allocate too much memory on debug builds. Putting the struct into a closure that is never executed ensures that even in debug builds no stack overflow error is caused. In release builds this was not a problem since the code was optimized away due to the `if false`. Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl --- v1 -> v2: * do not call the created closure rust/kernel/init/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index c5f977f52d0c..160b95fc03c9 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1038,14 +1038,14 @@ macro_rules! __init_internal { // 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 { + let _ = || { $crate::__init_internal!(make_initializer: @slot(slot), @type_name($t), @munch_fields($($fields)*,), @acc(), ); - } + }; } Ok(__InitOk) } @@ -1166,8 +1166,8 @@ macro_rules! __init_internal { @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: + // Since we are in the closure that is never called, this will never get executed. + // We abuse `slot` to get the correct type inference here: unsafe { ::core::ptr::write($slot, $t { $($acc)* From patchwork Wed Jul 19 14:20:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122651 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2482802vqt; Wed, 19 Jul 2023 07:35:34 -0700 (PDT) X-Google-Smtp-Source: APBJJlHRN72iLulvDw/z1ecRSPlxsC6C/t/OCBGTKmSATaTe0BQN6VWPYDpQyW/VBlKC/sJutZaU X-Received: by 2002:a50:ee0e:0:b0:51e:5ec8:d2f7 with SMTP id g14-20020a50ee0e000000b0051e5ec8d2f7mr2364447eds.30.1689777334166; Wed, 19 Jul 2023 07:35:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777334; cv=none; d=google.com; s=arc-20160816; b=aASIp7VxddVyMGR5c/R2deR/De8OXkygiruJlJPseuH8IXIoIEQljmFNpVT/u3zQ+f b5aEQyk0UQx+fFFUiMcqfy0jYa+Ni47V9Y7VDRkwh4ci48d3xFgG6JyZWYLGDyrUyYLh ZbXH1S3AP2WDY3vRxOp9Z+0WA2j4h9kMaLKbzsqu0fwd/RLIKSVBt1ubHO5G/O/Ja4oe TkzUQzwA8vzHllX0OMBeMvnfvPGcwT0gD03i3YNqlX+BmHHo/FP07T3IUMjbVNd5e4cf T6nNQzkcIwUJ4ITj6OpN96qDGRtW9n2vOPZ2UmXCDcTx6pfBCHgiKHiWDPJCK+Jlp3+v X6cA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=ssgVP+xm/xUxRo5NGKU6FQiwAj0frSX0JCoESMRG9+4=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=wXbV9f7RqKhZS4JkCLAOSl7pk+uhp/exYgnSpNmyj/loSF09eFdc4civ8riXNF4zbE agAnuTR5u4JMPC79jCMjdIYRoS4Otl5daC45m2Qu05bD43WP8jlwrbgzADUlar8wvWtb 0UVcjcc9zBrS2sivrq2J9OiYLQpXncpwQWgvw5oYDm/4jCBLEPwoxay52zpT4lUUhjyn 4nlmPt5lqCGwMR6Ufahq7XG7FR+QfClM02Ffrr2GD3m32VV7AN/qA9mCD37FhfOodZvm whaJCX1JPnB9zwkWu5VZ1LQvjoe3rk74XYNzX/gaQo/kuyKGrxUENFjVhs2HDtY3/ov/ 6I3g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=r5yynngpuvbuthttlghkc7g77y.protonmail header.b=g+vfPcqM; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id o22-20020aa7d3d6000000b0051de4c29577si3010647edr.184.2023.07.19.07.35.08; Wed, 19 Jul 2023 07:35:34 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=r5yynngpuvbuthttlghkc7g77y.protonmail header.b=g+vfPcqM; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231247AbjGSOVb (ORCPT + 99 others); Wed, 19 Jul 2023 10:21:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230375AbjGSOV2 (ORCPT ); Wed, 19 Jul 2023 10:21:28 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1E10F2122; Wed, 19 Jul 2023 07:21:01 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=r5yynngpuvbuthttlghkc7g77y.protonmail; t=1689776458; x=1690035658; bh=ssgVP+xm/xUxRo5NGKU6FQiwAj0frSX0JCoESMRG9+4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=g+vfPcqM0arg3Xzi+IPsZG7G/BF/jKT9SNSx+ctTlu2zdhzxFxxhOAGG0pLGfFEPY 10fLtiyor6Ot2+c+USFvHRwDiNqwalSOlAI+X3jUMXn3uuSbfushJedmjJNmqS1dj/ XuwFeMSa//FBPmn1psngv0glJ9+r2I2lIYYU6aOcpsv7g2T9BlhUzl7tsor77HP5Y2 tVR4tv22Gkc/bnJbkrilMGfm1N5S0l2SufWT2aDkfNesWLsSZNMnDycmknTkeym24l r4OVWO8ejG6ipRs+I54mIwWe17uF7EQg8xMYncAq1oQ1FOyna0jIllEyMfO5fl6e4H ZtO/KzbmaxBwQ== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 05/12] rust: init: make initializer values inaccessible after initializing Message-ID: <20230719141918.543938-6-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859957892632213 X-GMAIL-MSGID: 1771859957892632213 Previously the init macros would create a local variable with the name and hygiene of the field that is being initialized to store the value of the field. This would override any user defined variables. For example: ``` struct Foo { a: usize, b: usize, } let a = 10; let foo = init!(Foo{ a: a + 1, // This creates a local variable named `a`. b: a, // This refers to that variable! }); let foo = Box::init!(foo)?; assert_eq!(foo.a, 11); assert_eq!(foo.b, 11); ``` This patch changes this behavior, so the above code would panic at the last assertion, since `b` would have value 10. Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl --- rust/kernel/init/macros.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 160b95fc03c9..5de939e0801f 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1073,13 +1073,13 @@ macro_rules! __init_internal { // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { - let $field = $val; + let init = $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)? }; + unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), init)? }; // Create the drop guard: // // We rely on macro hygiene to make it impossible for users to access this local variable. @@ -1105,12 +1105,12 @@ macro_rules! __init_internal { // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { - let $field = $val; + let init = $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))? }; + unsafe { $crate::init::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? }; // Create the drop guard: // // We rely on macro hygiene to make it impossible for users to access this local variable. @@ -1136,11 +1136,13 @@ macro_rules! __init_internal { // 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) }; + { + $(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 rely on macro hygiene to make it impossible for users to access this local variable. From patchwork Wed Jul 19 14:20:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122649 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2482519vqt; Wed, 19 Jul 2023 07:35:07 -0700 (PDT) X-Google-Smtp-Source: APBJJlGdpQwnEcy6dVvE0FPr+FSUEF5YRvt6qkWzYMsyAQM63Hh3RmayrCTYwPO3fHkZjF78irlQ X-Received: by 2002:a50:ec97:0:b0:51e:527:3c64 with SMTP id e23-20020a50ec97000000b0051e05273c64mr2781363edr.16.1689777307411; Wed, 19 Jul 2023 07:35:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777307; cv=none; d=google.com; s=arc-20160816; b=xIwbS14tE73023NRn9tSlABo3Aqcf1uRoIbaTlLflgWxrG8tzwfTpe11YiCP+tVAV8 O4aZgnrfFtL9hlzmhv8A5QF2ZEOv8ASM0oL3AREOffg/e6NFNevPI4+VvmFpJrTFRCke 5g7Fl2ceIHFUBixmDD5/MNPpS4HhuOvEnM1Vfy+/a2/aX1o9jBcAllA679BGkEj9Wflt rcrrgV8N2cRTB5PL177dmEjHoVwM4iKERZdNoaPRAWxENor2+d4kno08Bqppg1QNgaH9 2RPkPJRW/iLmDZWVQIw4jmZrGMgwaWkadb9KDakwMlBdkDk0StHr62CRy4I7Ey6km9tl t55Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=0vuOV/QmUmOY88awAOdtxPsMJ6M9quIP7ewNLnDRz8Q=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=T3To0ABhYTqjaTLYE0SElXhr2RYyd/aH+hDJyECRk8HMtqbE2qehtYgz+CmgGpGfzk bNMjr/TEer1yRltdcLsk3NFcJihx2iTU1QrUGGVrdMzXA/JVxMbZCazxN3X8evrMr4Fi Fr3Q+SFf/oKNK1/b+SoRK58BYk8kcw32U9J872GOm+sFDX/5pTPbjCVWeOk6UFChNpDQ eyr2/0sn10K+UwdrIePeWHSgPYgPZ4gWs2KpiTgUxWLcNJ3InGC59s4FbDRngVDoa1yY XVyLwCCIa9diSRavc5t9vmQ2kWvLMPOpF+Igsx7k5najGtayxgq8nkWtl3U7MxnycHb4 9/Rw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=QoXU6WJ3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j11-20020aa7c0cb000000b0051debd504casi3127667edp.160.2023.07.19.07.34.42; Wed, 19 Jul 2023 07:35:07 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=QoXU6WJ3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231488AbjGSOVf (ORCPT + 99 others); Wed, 19 Jul 2023 10:21:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231145AbjGSOVc (ORCPT ); Wed, 19 Jul 2023 10:21:32 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0636E2706; Wed, 19 Jul 2023 07:21:04 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:50 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776461; x=1690035661; bh=0vuOV/QmUmOY88awAOdtxPsMJ6M9quIP7ewNLnDRz8Q=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=QoXU6WJ3mXQgIgYG+lRdE61zAJX6dNOErrJcYdOO5EpjyWrDP69LzaJY8CSfnbjii KvOOdWGUm1M1igFRtL8YKTIHd1TPCoS2/m4qqUlsXmsY7boZ52t7JE6Uf+yFBdyI1E Ty7V/p1wNh0BDeI4o9jNfuqxgTlncwEKvS6lgIXG0zk+uoyx5t7F+SFHT5F1DTF69e SGKMmIR9v/8T8keT9SFg45ze9qJaySjbd6kU6Z7BzvjaTxudFn7W+4z9IzbF1MSHL8 l9YLLYdoZT+NesXhZseWQwFWEfDJg6I975VL3D96ZvpAOesCH3XeUkMEm+SlDv5DWj nffeBRuqAbz3g== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 06/12] rust: init: add `..Zeroable::zeroed()` syntax for zeroing all missing fields Message-ID: <20230719141918.543938-7-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859929611674786 X-GMAIL-MSGID: 1771859929611674786 Add the struct update syntax to the init macros, but only for `..Zeroable::zeroed()`. Adding this at the end of the struct initializer allows one to omit fields from the initializer, these fields will be initialized with 0x00 set to every byte. Only types that implement the `Zeroable` trait can utilize this. Suggested-by: Asahi Lina Signed-off-by: Benno Lossin Reviewed-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- v1 -> v2: * fix doctest imports * fix doctest examples * fix `Zeroable` path in the `__init_internal` macro * rename `is_zeroable` -> `assert_zeroable` * add missing `{}` to the case when `..Zeroable::zeroed()` is present * add `allow(unused_assignments)` in the type-checked struct initializer rust/kernel/init.rs | 16 +++++- rust/kernel/init/macros.rs | 115 ++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 0120674b451e..460f808ebf84 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -517,13 +517,17 @@ macro_rules! stack_try_pin_init { /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. /// - In front of the initializer you can write `&this in` to have access to a [`NonNull`] /// pointer named `this` inside of the initializer. +/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the +/// struct, this initializes every field with 0 and then runs all initializers specified in the +/// body. This can only be done if [`Zeroable`] is implemented for the struct. /// /// For instance: /// /// ```rust -/// # use kernel::{macros::pin_data, pin_init}; +/// # use kernel::{macros::{Zeroable, pin_data}, pin_init}; /// # use core::{ptr::addr_of_mut, marker::PhantomPinned}; /// #[pin_data] +/// #[derive(Zeroable)] /// struct Buf { /// // `ptr` points into `buf`. /// ptr: *mut u8, @@ -536,6 +540,10 @@ macro_rules! stack_try_pin_init { /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, /// pin: PhantomPinned, /// }); +/// pin_init!(Buf { +/// buf: [1; 64], +/// ..Zeroable::zeroed() +/// }); /// ``` /// /// [`try_pin_init!`]: kernel::try_pin_init @@ -555,6 +563,7 @@ macro_rules! pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; } @@ -611,6 +620,7 @@ macro_rules! try_pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { @@ -624,6 +634,7 @@ macro_rules! try_pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; } @@ -658,6 +669,7 @@ macro_rules! init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) } } @@ -708,6 +720,7 @@ macro_rules! try_init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { @@ -721,6 +734,7 @@ macro_rules! try_init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; } diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 5de939e0801f..f5d7f0943f60 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -989,6 +989,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> /// /// 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::zeroed()` syntax has been handled. /// - `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. @@ -1007,6 +1008,82 @@ macro_rules! __init_internal { @has_data($has_data:ident, $get_data:ident), // `pin_init_from_closure` or `init_from_closure`. @construct_closure($construct_closure:ident), + @munch_fields(), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(), // nothing means default behavior. + ) + }; + ( + @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), + @munch_fields(..Zeroable::zeroed()), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(()), // `()` means zero all fields not mentioned. + ) + }; + ( + @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), + @munch_fields($ignore:tt $($rest:tt)*), + ) => { + $crate::__init_internal!( + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @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: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), + @zeroed($($init_zeroed:expr)?), ) => {{ // 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 @@ -1024,6 +1101,17 @@ macro_rules! __init_internal { { // Shadow the structure so it cannot be used to return early. struct __InitOk; + // If `$init_zeroed` is present we should zero the slot now and not emit an + // error when fields are missing (since they will be zeroed). 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 check 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 user inside of the // expressions creating the individual fields. $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? @@ -1060,7 +1148,7 @@ macro_rules! __init_internal { @data($data:ident), @slot($slot:ident), @guards($($guards:ident,)*), - @munch_fields($(,)?), + @munch_fields($(..Zeroable::zeroed())? $(,)?), ) => { // 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. @@ -1161,6 +1249,31 @@ macro_rules! __init_internal { ); } }; + (make_initializer: + @slot($slot:ident), + @type_name($t:ident), + @munch_fields(..Zeroable::zeroed() $(,)?), + @acc($($acc:tt)*), + ) => { + // Endpoint, nothing more to munch, create the initializer. Since the users specified + // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have + // not been overwritten are thus zero and initialized. We still check that all fields are + // actually accessible by using the struct update syntax ourselves. + // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to + // get the correct type inference here: + #[allow(unused_assignments)] + unsafe { + let mut zeroed = ::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 = ::core::mem::zeroed(); + ::core::ptr::write($slot, $t { + $($acc)* + ..zeroed + }); + } + }; (make_initializer: @slot($slot:ident), @type_name($t:ident), From patchwork Wed Jul 19 14:20:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122661 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2486358vqt; Wed, 19 Jul 2023 07:41:27 -0700 (PDT) X-Google-Smtp-Source: APBJJlHzLxW3Jr4kOb4eGTQ78wPbfaSfSIp6Hl6Qmsiz/yDsYJJwmMrl6O0JcS3r1v6Xt9DAdIgQ X-Received: by 2002:a17:902:dac7:b0:1b8:87dc:3371 with SMTP id q7-20020a170902dac700b001b887dc3371mr17234256plx.67.1689777686790; Wed, 19 Jul 2023 07:41:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777686; cv=none; d=google.com; s=arc-20160816; b=ZZYH5JOlGVEYyFNg2gsL5NU2uK+QHa6d1xY0KrTpw7ARVMybYfTma/YN+QKwBte0WV T+f+RryW2KLkDxp2+xVM1aaLwnHVDYN0q6qOaIEweKcT2CW2RcIgp5nH67TxHiFzQPBh jjJEc7RSvf8BaFJGF/7MMIqGa2EmFsQBa29nlR7G2YGzzO9N9JjzI0ncnU0Vi6veVypk mTNrA6/irIDOjEbksQmJMNhz+Vw8HoK1h95iSuO99FnGioI9bm80Ti0+n4GlZgauC6Is u/lANSLbKrAot5JS7eg/q7UuvZl9U0dzW7/1zPBiInlEeT+awagmfPF6MMXlS7LXUxQi a9eQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=ocaw+Jg23eMbqrHzK2iWdBrvi4VvFs/SPBCP4KfLQJI=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=XkS7v54AiP4xxSnUlLMeWF0zh4WyoTA0Bl4Y1QgZ6kSyIat14KoyDxWNxMEaMjc9bt +4ASCNv2kWfyyquynfn8WUWKvPHIod1DlD8ionoLlIPI+NHIivGdxj17LgXq7KE92fqB 08wCcb4r1T3FfKGnjCMeDzvZ+HSpTdhL6M7sTU4QKRaHsDeFjJk6UWqQpCx+YftL5b81 UjYTBO0DaT/nHwN8y2Qnf/MFj+8Sp/t8TO1zRysdcc4I1gu/E9LNFp1hrArROE8/7pcC 7lhxK8s4LNwMcNYToeEtz7mCNZVGAmBtlSvpY2GY/mi0v7iN2g6LEi5Ttdty7LzNDrYV Tzbg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=gK1ISIfe; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l20-20020a170903005400b001b9c34985e1si3516671pla.497.2023.07.19.07.41.12; Wed, 19 Jul 2023 07:41:26 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=gK1ISIfe; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231516AbjGSOVi (ORCPT + 99 others); Wed, 19 Jul 2023 10:21:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230375AbjGSOVe (ORCPT ); Wed, 19 Jul 2023 10:21:34 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D1CBF270F for ; Wed, 19 Jul 2023 07:21:05 -0700 (PDT) Date: Wed, 19 Jul 2023 14:20:57 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776463; x=1690035663; bh=ocaw+Jg23eMbqrHzK2iWdBrvi4VvFs/SPBCP4KfLQJI=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=gK1ISIfeWnjFtMpoaYRH7GnrQ1vT8LMld6UrLQmh9V7bcBAA6Bn2dtmYxpZrTSclX oT7nEDYzQXAJMcvgCJ3c1GPr5LVwaiYcvuZeAPgbWWlXEyZNTQNK1t632sK8JtBm89 AsPMCN4Z3uN/lJR9oDe9RYcluSFZy696clmyjDdgfHZX7AExnKP5pqooI2+zDO9iLY oZG0w0GZ48nKTfoo8BKV/2dvfMsZx7Z3SngYAydmsNQ7Rmzf8woa3OP2f9BwUMxI2q Dt0v5ZK1F11b7pL5nf9sFhV5e61Y7Ub0HeMpTKtPnpY6Lr93AoDDwYBegH2d/MJGJZ IbVZL2LIyggnQ== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 07/12] rust: init: Add functions to create array initializers Message-ID: <20230719141918.543938-8-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771860327634486888 X-GMAIL-MSGID: 1771860327634486888 Add two functions `pin_init_array_from_fn` and `init_array_from_fn` that take a function that generates initializers for `T` from usize, the added functions then return an initializer for `[T; N]` where every element is initialized by an element returned from the generator function. Suggested-by: Asahi Lina Reviewed-by: Björn Roy Baron Signed-off-by: Benno Lossin Reviewed-by: Alice Ryhl --- v1 -> v2: * fix warnings and errors in doctests * replace dropping loop with `drop_in_place` and `slice_from_raw_parts_mut` inside of `{pin_}init_array_from_fn` functions rust/kernel/init.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 460f808ebf84..fa1ebdbf5f4b 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -875,6 +875,92 @@ pub fn uninit() -> impl Init, E> { unsafe { init_from_closure(|_| Ok(())) } } +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{error::Error, init::init_array_from_fn}; +/// let array: Box<[usize; 1_000_000_000]>= Box::init::(init_array_from_fn(|i| i)).unwrap(); +/// pr_info!("{array:?}"); +/// ``` +pub fn init_array_from_fn( + mut make_init: impl FnMut(usize) -> I, +) -> impl Init<[T; N], E> +where + I: Init, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::(); + for i in 0..N { + let init = make_init(i); + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` + // requirements. + match unsafe { init.__init(ptr) } { + Ok(()) => {} + Err(e) => { + // We now free every element that has been initialized before: + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + return Err(e); + } + } + } + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { init_from_closure(init) } +} + +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; +/// let array: Arc<[Mutex; 1_000_000_000]>= +/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap(); +/// pr_info!("{}", array.len()); +/// ``` +pub fn pin_init_array_from_fn( + mut make_init: impl FnMut(usize) -> I, +) -> impl PinInit<[T; N], E> +where + I: PinInit, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::(); + for i in 0..N { + let init = make_init(i); + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__pinned_init` + // requirements. + match unsafe { init.__pinned_init(ptr) } { + Ok(()) => {} + Err(e) => { + // We now have to free every element that has been initialized before, since we + // have to abide by the drop guarantee. + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + return Err(e); + } + } + } + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { pin_init_from_closure(init) } +} + // SAFETY: Every type can be initialized by-value. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { From patchwork Wed Jul 19 14:21:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122653 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2482834vqt; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) X-Google-Smtp-Source: APBJJlEzIwQXEVBRKxDkQz6ai15KrkI0DBFkfepIQtQs7pD/e+5ZvDvi2VEcXQq9p68KtE+cuy6w X-Received: by 2002:a17:906:3150:b0:992:b928:adb3 with SMTP id e16-20020a170906315000b00992b928adb3mr2264430eje.54.1689777336460; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777336; cv=none; d=google.com; s=arc-20160816; b=fZZySq2yBfMmYmCUqD+cEvGszMaYqs6i+WIutE1XwpkCVaYQhaN12XKnMFKFk1TKTC o4xPX3VGCvbWq6j5hjN0mdEgHrUv3jvkrYB34A1DDHpo5ThrFWdKxD13ziPJzTVp3R9A y5Rc8zziKMQWm2JPbwa1DKZ04a8o0BawBGsOfONjeHueZi033g/OWUJJe5EYLePo4Rsq Mq0OvKWlP8QsSBCSb5ZIMVLSsnSzWlh+BebXjvN71T3JLN+c3g/vIjSnTNMlWKC32Gnp CMhIW3iEToAy5yY/cewBJ5Qv0l09horJXZx9hU7XyoKVZbKUheB99mhDXl7baqBxBYWh FasQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=YIuxWzFErHS/G2fc91GDnhwDMG2gDHUgDWefQ2yWmME=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=zGL0DCCGWFkII5W9S3OqkWYXDQvrg9r8/+emRNsVvlHengpGZ1KESMz7us1Ok8YvY5 Xum/IXc1SsOupm0OLvCmmjX72XeDkGqlCN/DzTNkLrtyQEzbZP8S5seb6C9f3rr7BBmh fCRSYmgpfu9IRZL79bWoLV6tXbAPMCgI+ECs5fuxRxroWyGympOwShZ94J9r41sdzkyd YxtZwnlhYZjrfbzSbvM3ZHZ+PmNoeypDnHNUrnyGq2ZDU7+NPdLLlcSDJX8+ga+r8b2i gUOUdhEpK1sHVi4gtoLAzk5Jtr/XGJy6FxFndk1/vNBVt8t020HnSi/Th/3WEuy+Uj97 UiIA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=bfuufCxG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id gq15-20020a170906e24f00b0098886d50308si2914811ejb.490.2023.07.19.07.35.08; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=bfuufCxG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231508AbjGSOWC (ORCPT + 99 others); Wed, 19 Jul 2023 10:22:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230375AbjGSOWA (ORCPT ); Wed, 19 Jul 2023 10:22:00 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E3BC926A2 for ; Wed, 19 Jul 2023 07:21:34 -0700 (PDT) Date: Wed, 19 Jul 2023 14:21:03 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776477; x=1690035677; bh=YIuxWzFErHS/G2fc91GDnhwDMG2gDHUgDWefQ2yWmME=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=bfuufCxGbBZv9CUYoDr0RrvLhYTmm6dmIHOS0Z2bDUwUcxyV6I0hjWszLTaF5Vx5W HrUqFylFnj4WwjhZTlCVCKQvs1YRGQCwXprm5Nr0l/mz1Nb+324CqE2J/mGkCUR2Gv gpE139ybVE5a7d0kjaeMQrhdtjfHDT5JBHlcMsC2vN2/OMhcj3iW8VepYvKzet2/7j cOjROJaG5Rqy8P4ntFLseemzGm9YQwtsnmDBDSfW7lOTWfFosVxG1GsbCnlqPZF4Gn c6YXXZhp5uNYg8W/2TLIjYTI1qdc4wtStblB/YSAdFAeBUjhUpU4PaYgfPR2J7v5Bg /KeRmfHZMiw/A== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 08/12] rust: init: add support for arbitrary paths in init macros Message-ID: <20230719141918.543938-9-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859960500235263 X-GMAIL-MSGID: 1771859960500235263 Previously only `ident` and generic types were supported in the `{try_}{pin_}init!` macros. This patch allows arbitrary path fragments, so for example `Foo::Bar` but also very complex paths such as `::Bar::<0, i32>`. Internally this is accomplished by using `path` fragments. Due to some peculiar declarative macro limitations, we have to "forget" certain additional parsing information in the token trees. This is achieved by using the `paste!` proc macro. It does not actually modify the input, since no `[< >]` will be present in the input, so it just strips the information held by declarative macros. For example, if a declarative macro takes `$t:path` as its input, it cannot sensibly propagate this to a macro that takes `$($p:tt)*` as its input, since the `$t` token will only be considered one `tt` token for the second macro. If we first pipe the tokens through `paste!`, then it parses as expected. Suggested-by: Asahi Lina Signed-off-by: Benno Lossin Reviewed-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- v1 -> v2: * use Gary's `paste!` macro instead of `retokenize` * remove the retokenize macro rust/kernel/init/macros.rs | 54 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index f5d7f0943f60..345cfc0e6d37 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -998,7 +998,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> macro_rules! __init_internal { ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1012,7 +1012,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!(with_update_parsed: @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1023,7 +1023,7 @@ macro_rules! __init_internal { }; ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1037,7 +1037,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!(with_update_parsed: @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1048,7 +1048,7 @@ macro_rules! __init_internal { }; ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1062,7 +1062,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!( @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1073,7 +1073,7 @@ macro_rules! __init_internal { }; (with_update_parsed: @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1092,7 +1092,11 @@ macro_rules! __init_internal { // Get the data about fields from the supplied type. let data = unsafe { use $crate::init::__internal::$has_data; - $t$(::<$($generics),*>)?::$get_data() + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!($t::$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>( @@ -1251,7 +1255,7 @@ fn assert_zeroable(_: *mut T) {} }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields(..Zeroable::zeroed() $(,)?), @acc($($acc:tt)*), ) => { @@ -1268,15 +1272,21 @@ fn assert_zeroable(_: *mut T) {} // not get executed, so it has no effect. ::core::ptr::write($slot, zeroed); zeroed = ::core::mem::zeroed(); - ::core::ptr::write($slot, $t { - $($acc)* - ..zeroed - }); + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + ..zeroed + }); + ); } }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($(,)?), @acc($($acc:tt)*), ) => { @@ -1284,14 +1294,20 @@ fn assert_zeroable(_: *mut T) {} // Since we are in the closure that is never called, this will never get executed. // We abuse `slot` to get the correct type inference here: unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + }); + ); } }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($field:ident <- $val:expr, $($rest:tt)*), @acc($($acc:tt)*), ) => { @@ -1304,7 +1320,7 @@ fn assert_zeroable(_: *mut T) {} }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), @acc($($acc:tt)*), ) => { From patchwork Wed Jul 19 14:21:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122654 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2483213vqt; Wed, 19 Jul 2023 07:36:15 -0700 (PDT) X-Google-Smtp-Source: APBJJlHj5AEeLisrH92du/3qLSbHB7outZXs8U55wWVfe/mW9nXPyolmQYRQ5+pkiBGDmLeY8ptY X-Received: by 2002:a19:4f01:0:b0:4fb:78b1:1cd4 with SMTP id d1-20020a194f01000000b004fb78b11cd4mr27213lfb.49.1689777375588; Wed, 19 Jul 2023 07:36:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777375; cv=none; d=google.com; s=arc-20160816; b=qNk/sKUeBcc5R9wmdGUYP7e4B9gPyGhXzPRqIZ88V+LN/Ux9DUD4YKRBNxEf8xvcdE QMmP8whpxnyZ9fYlinPmz8hXUtYOjNuUF7rM1zX1GHcLz/GQJllXkjBeBk/feY1jbXt5 eTBW9ihfltvFeks8mXETLEdGxPV1DbH6qlD9Ep0Af4u31YzlkUxcWCtidNpddHSQSywp i1M0pibpJ5VHaNoQb0DwaIcXFZbXiVazj7kkwIoaVHYZGRgFH7qcRUf0B6CcbCO2iD+a 4digF81p2IE1S3i+YnEFJMKFQ4Lp8smGpjbXGoN3pQrJL9uyi2p5N8sWNxMte0nGk1I1 spkA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=ycSUa09BWmPYG+p0T3v8MXq1UGIxA3oXkswxIya2goA=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=Ill2Ed5RJfMQLkuz2eygGuZ3/KdBmEJfghjGxz/STGSsZLF6gBSS6ldarI0HJ99Woi 8Dct4wA6so250QJh3epWWyopJIspnNOGkQNbODw0Zkxl6v+9WQaJ4WmZNnsDLYPxQUI9 vso+1LmiMAvdwe+aQrHsTxo4U1Rcjq2RLVM+Hnw1rBQf0E+Iii6pDIxfRQuV4GnJS6t7 Xb0ghZmdIFI0vrPXQJ7z/9C4Er0mSM/h1Wwujp23UkpGHqWVCK3PWP4Iq5Oyrq8JfDjS 7Xckm45L13voQsrKXJX7IQ8jXEFrss7jbQTxRf19vk/zgh1oUQSd4+dyoo+huLXixmXb Uwhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=Hp0gqBpu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id p9-20020a056402074900b005218c27b193si3018838edy.501.2023.07.19.07.35.49; Wed, 19 Jul 2023 07:36:15 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=Hp0gqBpu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230268AbjGSOVx (ORCPT + 99 others); Wed, 19 Jul 2023 10:21:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231536AbjGSOVs (ORCPT ); Wed, 19 Jul 2023 10:21:48 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2CEF519A3; Wed, 19 Jul 2023 07:21:22 -0700 (PDT) Date: Wed, 19 Jul 2023 14:21:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776469; x=1690035669; bh=ycSUa09BWmPYG+p0T3v8MXq1UGIxA3oXkswxIya2goA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=Hp0gqBpu5Kg0lTyFWlOUxr4CFlT3YRUF3s6qV9d9wWK/qCU6Myt8GwZT33ypBSzwr ObLAaGrCb5pyVC4sZP4dDzVQ2xDgRuV8aoiFTfnNYJtdyTpUxUlK092JCDkZaprUCQ SfkSLTY8juIJkd6chETk2t54ejpvmenxydWJKtB+8DWFcUBG7MS1eZ2YV2UzcoehUJ Iwu2LD9ZycYtUouWT6KEvAhhdB8SHfjRQmVJa4rw3qmThKvHfBk4P8zPdPmF/58OJ4 eDQ+7Fv5minHxoZPSKEOohDsQ/sncyXOewAsZ1xjPXw86/64mGl/Fobzesg8qiWvSq ++0ATtS+WotfQ== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 09/12] rust: init: implement Zeroable for Opaque Message-ID: <20230719141918.543938-10-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771860001218102531 X-GMAIL-MSGID: 1771860001218102531 Since `Opaque` contains a `MaybeUninit`, all bytes zero is a valid bit pattern for that type. Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/types.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index d849e1979ac7..f0f540578d0f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,6 +11,7 @@ ops::{Deref, DerefMut}, ptr::NonNull, }; +use macros::Zeroable; /// Used to transfer ownership to and from foreign (non-Rust) languages. /// @@ -251,6 +252,7 @@ fn drop(&mut self) { /// /// This is meant to be used with FFI objects that are never interpreted by Rust code. #[repr(transparent)] +#[derive(Zeroable)] pub struct Opaque { value: UnsafeCell>, _pin: PhantomPinned, From patchwork Wed Jul 19 14:21:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122659 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2484851vqt; Wed, 19 Jul 2023 07:38:50 -0700 (PDT) X-Google-Smtp-Source: APBJJlHKyg+RqTv4L2SnL5BxMRwv/byxn7pW7kHOL52vSLojF8H4l/T2rIaPepk91d9avADtwWp3 X-Received: by 2002:a05:6a00:1908:b0:680:40b2:5424 with SMTP id y8-20020a056a00190800b0068040b25424mr18235653pfi.23.1689777530000; Wed, 19 Jul 2023 07:38:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777529; cv=none; d=google.com; s=arc-20160816; b=mH1dLqeJrwzro9CVOq/Bsffdip3iZVKmOPaI532mJ496CoimJ492UQ+Eb9hRez01iK M5AId6xVsmz0IyUb0vFWwK7Ym1zFppHKwO4FS3Cdfr8egsEQxEM1SMze7gCaotZdhv2y 21ewS1zQh59HKKQfftgfP0H+OBJH6m+UwLS0FjODZG05C4AS62/ReG2vOKZZrymwnmPf JEzcJlhuGhIY9MOBCwaA6f69kqExaRnlizg+jjcRxw6mbvuq0jwxZIU0n5v7HQqfjcxp jljV1Z5dmePNL8TKVywtJDnO4nkjvsa9xCbFcwld04RZYH7AEraPWkBXNiyRmmwLZwkk RaiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=PY3Ej/DIQyjr1nZd2KtYmX46DbaLv5+ISgZDgCfGk58=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=ua55SHYCk4h0cdpB6StudtMaeJvFX4EWQHdMARzM26Cj+QnLyqyTyONw8zyBduiCRY ZbR4l1MVGk4erU+7jZD8jDBVFTJ5IXDlebkB87M8Uoc4Ty6SnpaaX6KUaPjRC2wqU6GD RxffoMElgalFWmnOeanX0ds+57qQgIR4K33+9pfIMk9B8fo+hOwYDqIbdjjNdcK6AOZN xq4Wj03lnSuvtZdhczfKcbC9Mpgz+IOwPiTNsXgu3ktPqGixm/Et3qa1eyBS/8lA46UB g3KYDSTkkGOjyObNkJsLdMZOy7z9uG4/U3NlXwI6I0wq2carJAbc+32kMUKzAqUjJlgj wrIw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=JbZ3uC2P; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q15-20020a056a00150f00b00682acfc5dacsi3680317pfu.53.2023.07.19.07.38.36; Wed, 19 Jul 2023 07:38:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=JbZ3uC2P; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231557AbjGSOWQ (ORCPT + 99 others); Wed, 19 Jul 2023 10:22:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231551AbjGSOWN (ORCPT ); Wed, 19 Jul 2023 10:22:13 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E01B5198D; Wed, 19 Jul 2023 07:21:54 -0700 (PDT) Date: Wed, 19 Jul 2023 14:21:19 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776494; x=1690035694; bh=PY3Ej/DIQyjr1nZd2KtYmX46DbaLv5+ISgZDgCfGk58=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=JbZ3uC2P97beRJVTZB8zzWyQWqTrD2X3DqO614uvYpMuDtjxTr8BcSXwvtmuhFBe6 C7yftw8MTtWqDeWbJA+4c5RRhAxTYBJBRKv8bo8z05YKe/gqdOKV+TKqA4duvrxZIn wcC9LKyrbxSxp8GlSIHztsAgFe51qHjkWNc51k1AS9SUQduqUH4bDCEyqvX0r0qHn3 BpTfDawsATp14Zoz5DH5WH9XkeUOTkkZdyXX59ofNUgelkkhVs9nen57LuxEfgYHx/ 9N0PZbP76v0NSO8drATOMc1SxQnzzngSkeYBtqoEWsV3DZlgaoqkXiEMWEwFgJLER2 6vJwO4xk9yv0A== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 10/12] rust: init: make `PinInit` a supertrait of `Init` Message-ID: <20230719141918.543938-11-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771860163595810979 X-GMAIL-MSGID: 1771860163595810979 Remove the blanket implementation of `PinInit for I where I: Init`. This blanket implementation prevented custom types that implement `PinInit`. Signed-off-by: Benno Lossin Reviewed-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/init.rs | 20 +++++++------------- rust/kernel/init/__internal.rs | 12 ++++++++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index fa1ebdbf5f4b..3c7cd36a424b 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -805,7 +805,7 @@ pub unsafe trait PinInit: Sized { /// /// [`Arc`]: crate::sync::Arc #[must_use = "An initializer must be used in order to create its value."] -pub unsafe trait Init: Sized { +pub unsafe trait Init: PinInit { /// Initializes `slot`. /// /// # Safety @@ -816,18 +816,6 @@ pub unsafe trait Init: Sized { unsafe fn __init(self, slot: *mut T) -> Result<(), E>; } -// SAFETY: Every in-place initializer can also be used as a pin-initializer. -unsafe impl PinInit for I -where - I: Init, -{ - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not - // require `slot` to not move after init. - unsafe { self.__init(slot) } - } -} - /// Creates a new [`PinInit`] from the given closure. /// /// # Safety @@ -968,6 +956,12 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { Ok(()) } } +// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. +unsafe impl PinInit for T { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe { self.__init(slot) } + } +} /// Smart pointer that can initialize memory in-place. pub trait InPlaceInit: Sized { diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 7abd1fb65e41..12e195061525 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -32,6 +32,18 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { } } +// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the +// `__pinned_init` invariants. +unsafe impl PinInit for InitClosure +where + F: FnOnce(*mut T) -> Result<(), E>, +{ + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + (self.0)(slot) + } +} + /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate /// the pin projections within the initializers. /// From patchwork Wed Jul 19 14:21:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122652 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2482833vqt; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) X-Google-Smtp-Source: APBJJlE6p8JMnXFG12KXeIWrD9mnYFKwsWeDK9UYO5P7O3Njpp9mBovtrh4a/OpMxsGXACSialDx X-Received: by 2002:a17:906:14e:b0:993:da40:fbff with SMTP id 14-20020a170906014e00b00993da40fbffmr2571388ejh.0.1689777336306; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777336; cv=none; d=google.com; s=arc-20160816; b=YE2oeeCIm6Et0YmoOcvNDQxVWfKwXyH2olh5+cdWxDICfHrPu5qoGN9gvaKXXzubXC zVa95mH1kblumMKh3PSQMp3al+Hwgz6WDEw/Z78ml5DSaHdQX3bVXljYuSxXmcYKbJR1 mP6oMED+iJcakqN0cHfb/VUS3b8dTDJU7OqOX6sHbqFIIh62QVefvJ94A5ZCpywPAVnE ea26YRXbi7gU7fl8zgZ3YkmFT80RbEOIAFeRBcx9iiJN9OFPEuSje2oRhxT/2psjy9gs DhkpGtJ0V9AMjebBqRMEgc1JoAoiM0EfypLlZAtAeQ7Y6mReXo3/o8+poJjSLxJ+0NrS rTcQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=ROflUBJ/yKtDmmZ5v/yBBaWjNh5JrBS62VSefriDUlI=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=CvOmDsdBOykw/1sZunU4odjPHtVbirxbvliFpnDvCafjEuZwGWwJZ9ewU0qMHRmpoZ 8urIWCWtO0k6nK3Bpygeova8AUOZCYL8kfqLotlmJl5a6Apk5QlFm3QnSfg3Xul8Ae6R 6dWajc7tcnq6Az+dwB5KDjXQQVT5US5i/TXa553RFxtgl3F/E0WKgtSDIgV+9ye59QVs OaeoS2YVbBwExRf6YkkMTdmR2V60autO9EdRVOt9vKk0lDY6DF9HxZHIKUH4O70k/SrC ShQhYMfdw2mZb1d3U7aHtJ8HSjiK6Uh3pBANy1uEw67tX9KsRg3nTJ95fgYb9+Rr++qO 2Xbw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b="XfOf/Qvc"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j22-20020a170906411600b0098cfbd83b9asi2835009ejk.776.2023.07.19.07.35.10; Wed, 19 Jul 2023 07:35:36 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b="XfOf/Qvc"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231341AbjGSOWM (ORCPT + 99 others); Wed, 19 Jul 2023 10:22:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231538AbjGSOWJ (ORCPT ); Wed, 19 Jul 2023 10:22:09 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F92A173B; Wed, 19 Jul 2023 07:21:47 -0700 (PDT) Date: Wed, 19 Jul 2023 14:21:23 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1689776489; x=1690035689; bh=ROflUBJ/yKtDmmZ5v/yBBaWjNh5JrBS62VSefriDUlI=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=XfOf/Qvc4tNpKfp9Ta7VvfL3+x92B6TlWAlOwPOiGBCimGIkakNppevaXnj/7QTaK GVo2UdqRFqVenr9KU4Sa6s2wbFnA801q6Yw4dn33++EjkR1MpTfVqN2hvAAzGHOMdb +egWXh5B/3RNUYknoHkbTV4EbL3pvtYoGPXfOzc/BgCXrnT3AlStm9F53/reZvmk6k dWH2BhWsvw9LAzhFNhIBg7tFGTJEdNALVIam2lZrfZOVJuHAA3BG6iDdtRKhmmcbz3 vyVh9Mo1g4A4E6pI5XceSpWY8qpMXqVfaoJ+nDYv7HxUgYQoFKJMCWAecZrKHpSl8P 4Fgim/gemo7nQ== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Asahi Lina Subject: [PATCH v2 11/12] rust: init: add `{pin_}chain` functions to `{Pin}Init` Message-ID: <20230719141918.543938-12-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859959833089160 X-GMAIL-MSGID: 1771859959833089160 The `{pin_}chain` functions extend an initializer: it not only initializes the value, but also executes a closure taking a reference to the initialized value. This allows to do something with a value directly after initialization. Suggested-by: Asahi Lina Signed-off-by: Benno Lossin --- rust/kernel/init.rs | 138 +++++++++++++++++++++++++++++++++ rust/kernel/init/__internal.rs | 2 +- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 3c7cd36a424b..3b0df839f64c 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -773,6 +773,77 @@ pub unsafe trait PinInit: Sized { /// deallocate. /// - `slot` will not move until it is dropped, i.e. it will be pinned. unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::pin_init_from_closure}; + /// #[repr(C)] + /// struct RawFoo([u8; 16]); + /// extern { + /// fn init_foo(_: *mut RawFoo); + /// } + /// + /// #[pin_data] + /// struct Foo { + /// #[pin] + /// raw: Opaque, + /// } + /// + /// impl Foo { + /// fn setup(self: Pin<&mut Self>) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = pin_init!(Foo { + /// raw <- unsafe { + /// Opaque::ffi_init(|s| { + /// init_foo(s); + /// }) + /// }, + /// }).pin_chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn pin_chain(self, f: F) -> ChainPinInit + where + F: FnOnce(Pin<&mut T>) -> Result<(), E>, + { + ChainPinInit(self, f, PhantomData) + } +} + +/// An initializer returned by [`PinInit::pin_chain`]. +pub struct ChainPinInit(I, F, __internal::Invariant<(E, Box)>); + +// SAFETY: the `__pinned_init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +// - considers `slot` pinned. +unsafe impl PinInit for ChainPinInit +where + I: PinInit, + F: FnOnce(Pin<&mut T>) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: all requirements fulfilled since this function is `__pinned_init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + let val = unsafe { &mut *slot }; + // SAFETY: `slot` is considered pinned + let val = unsafe { Pin::new_unchecked(val) }; + (self.1)(val).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } } /// An initializer for `T`. @@ -814,6 +885,73 @@ pub unsafe trait Init: PinInit { /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. unsafe fn __init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::{self, init_from_closure}}; + /// struct Foo { + /// buf: [u8; 1_000_000], + /// } + /// + /// impl Foo { + /// fn setup(&mut self) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = init!(Foo { + /// buf <- init::zeroed() + /// }).chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn chain(self, f: F) -> ChainInit + where + F: FnOnce(&mut T) -> Result<(), E>, + { + ChainInit(self, f, PhantomData) + } +} + +/// An initializer returned by [`Init::chain`]. +pub struct ChainInit(I, F, __internal::Invariant<(E, Box)>); + +// SAFETY: the `__init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +unsafe impl Init for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: all requirements fulfilled since this function is `__init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + (self.1)(unsafe { &mut *slot }).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } +} + +// SAFETY: `__pinned_init` behaves exactly the same as `__init`. +unsafe impl PinInit for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. + unsafe { self.__init(slot) } + } } /// Creates a new [`PinInit`] from the given closure. diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 12e195061525..db3372619ecd 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -13,7 +13,7 @@ /// /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns -type Invariant = PhantomData *mut T>; +pub(super) type Invariant = PhantomData *mut T>; /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this /// type, since the closure needs to fulfill the same safety requirement as the From patchwork Wed Jul 19 14:21:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 122648 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp2481584vqt; Wed, 19 Jul 2023 07:33:34 -0700 (PDT) X-Google-Smtp-Source: APBJJlGLHmbh775AefVejSycjny9PcsqA651bBYuy84OCf/RHbCh4SaUvMNvZkVKStSV6OW+2Gy6 X-Received: by 2002:a05:6512:2015:b0:4f9:d272:5847 with SMTP id a21-20020a056512201500b004f9d2725847mr8934lfb.68.1689777214069; Wed, 19 Jul 2023 07:33:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689777214; cv=none; d=google.com; s=arc-20160816; b=AufAKPrz9/vyXBsK31RES+7okiliISkT4AyHyQlMDQdjazBf6penwT8AhnVwkP3fSW quUZS/Pn74EACDYEz9UB6k3hrVlm86onIIjzrni2YxEH0G5bUUBFUbZjAdOdP5jP3RHP S5f8XD1jg3lQALxaivYDZ9XoLXVmZDhchBkM+MpgD/Cny5Cey/e/vSXEoZEqkO5A7b01 Cg7VhnApCk8qy7OMkAEgNatvtvJXFUbY2ZYXj46snhgyNG5EVPrBV5YL8cbkNKF/zWxE Ez3DkZuKU1anjMge6XfnvWYX9zLqoMs6aezv9QfBSILcpwaPIVBc6CRrfL8o8sCJEJQa 77VQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=RODYiaZt0FROSzQP92m7gVuExsH92vbxzChBjR19APw=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=fx/QdDK/04oBd/85N0RBq7n8+2JeG3Lt1ZrV9MKbhh3K9JuxBv0yjgJolWnYONYzd+ dBdQMa9VI/yxqbQ8jxkbEb7WhvgZ0BSYx7HZdTzRIDHNC6VAwEKQwbsfUMZtiZxJKnLo bADfltsCircATQUDI18wCNIt4TiTMbWhvyq3ElxZZ8HQxCfLZRyzFvpAsr3dj49aaBwn x9rdzByjPWkwz3UKx4Snf+qMfA9HoDA0FaKxhb82PPauMr3/+8Now5XIjOk/9uoBs0J5 1njaX/zheW8OYb36F5lbCZ9cEtA8ThOI3tcLVGxM9qcHDAgvy0Sw3AC0CsfK3GkKOhgW +OXg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=lg2b3yz7hnghnd5rq75p64wlym.protonmail header.b=MCfNIot2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l1-20020aa7cac1000000b0051fde3f49cdsi3248100edt.531.2023.07.19.07.33.09; Wed, 19 Jul 2023 07:33:34 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=lg2b3yz7hnghnd5rq75p64wlym.protonmail header.b=MCfNIot2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231561AbjGSOWa (ORCPT + 99 others); Wed, 19 Jul 2023 10:22:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231574AbjGSOWZ (ORCPT ); Wed, 19 Jul 2023 10:22:25 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E5D722684 for ; Wed, 19 Jul 2023 07:22:03 -0700 (PDT) Date: Wed, 19 Jul 2023 14:21:26 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=lg2b3yz7hnghnd5rq75p64wlym.protonmail; t=1689776500; x=1690035700; bh=RODYiaZt0FROSzQP92m7gVuExsH92vbxzChBjR19APw=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=MCfNIot27BudyPewXr0xQlqN0C+sNfGNvF/3km10+8ooZ5xsz4QToOz5kBsBwOYNA JRyvoGSIucLm+crjVLhGbjNfsMvKLbUM21abmBksfFPRAbTrdz7Ym3spuqKrilyUOV oJ68p0ZICUiNZl2gfsT5oZ9J+WyXrwtScEkSlpI5aaTrIJEdDR9xzj/vVgmWBpOalv AseTpEdt0D4mtSTxtZVWfoO+/yI7L9ueUnq5CXxMpdSPYCXq80tDKBVzhrf7jT7OaY COj2P9GnuMvotC66RGszZMOHh0l3bzOn9QdoYXhdKI4tQWKe2/Y80C31mI+Sd3fIW4 t7iemh+9zGnng== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 12/12] rust: init: update expanded macro explanation Message-ID: <20230719141918.543938-13-benno.lossin@proton.me> In-Reply-To: <20230719141918.543938-1-benno.lossin@proton.me> References: <20230719141918.543938-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771859832316893354 X-GMAIL-MSGID: 1771859832316893354 The previous patches changed the internals of the macros resulting in the example expanded code being outdated. This patch updates the example and only changes documentation. Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/init/macros.rs | 126 ++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 345cfc0e6d37..1d492c4bab69 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -45,7 +45,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! @@ -170,8 +170,10 @@ //! t: T, //! } //! #[doc(hidden)] -//! impl<'__pin, T> -//! ::core::marker::Unpin for Bar where __Unpin<'__pin, T>: ::core::marker::Unpin {} +//! 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`, since that would give users //! // access to `&mut self` inside of `drop` even if the struct was pinned. This could lead to //! // UB with only safe code, so we disallow this by giving a trait implementation error using @@ -188,8 +190,9 @@ //! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`. //! #[allow(non_camel_case_types)] //! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} -//! impl -//! UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} +//! impl< +//! T: ::kernel::init::PinnedDrop, +//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} //! impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Bar {} //! }; //! ``` @@ -219,7 +222,7 @@ //! // 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 type from the initialized type. +//! // 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 only available in that //! // scope. @@ -227,8 +230,7 @@ //! use ::kernel::init::__internal::HasPinData; //! Self::__pin_data() //! }; -//! // Use `data` to help with type inference, the closure supplied will have the type -//! // `FnOnce(*mut Self) -> Result<__InitOk, Infallible>`. +//! // Ensure that `data` really is of type `PinData` and help with type inference: //! let init = ::kernel::init::__internal::PinData::make_closure::< //! _, //! __InitOk, @@ -236,71 +238,75 @@ //! >(data, move |slot| { //! { //! // Shadow the structure so it cannot be used to return 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. +//! // 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 syntactic sugar for `t: t,`. -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; -//! // Since initialization could fail later (not in this case, since the error -//! // type is `Infallible`) we will need to drop this field if there is an -//! // error later. This `DropGuard` will drop the field when it gets dropped -//! // and has not yet been forgotten. We make a reference to it, so users -//! // cannot `mem::forget` it from the initializer, since the name is the same -//! // as the field (including hygiene). -//! let t = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).t), -//! ) +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; +//! } +//! // Since initialization could fail later (not in this case, since the +//! // error type is `Infallible`) we will need to drop this field if there +//! // is an error later. This `DropGuard` will drop the field when it gets +//! // dropped and has not yet been forgotten. +//! let t = unsafe { +//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t)) //! }; //! // Expansion of `x: 0,`: -//! // Since this can be an arbitrary expression we cannot place it inside of -//! // the `unsafe` block, so we bind it here. -//! let x = 0; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! // Since this can be an arbitrary expression we cannot place it inside +//! // of the `unsafe` block, so we bind it here. +//! { +//! let x = 0; +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! } //! // We again create a `DropGuard`. -//! let x = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).x), -//! ) +//! let x = unsafe { +//! ::kernel::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); +//! ::core::mem::forget(t); //! // Here we use the type checker to ensure that every field has been //! // initialized exactly once, since this is `if false` it will never get //! // executed, but still type-checked. -//! // Additionally we abuse `slot` to automatically infer the correct type for -//! // the struct. This is also another check that every field is accessible -//! // from this scope. +//! // Additionally we abuse `slot` to automatically infer 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_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, //! Self { -//! // We only care about typecheck finding every field here, -//! // the expression does not matter, just conjure one using -//! // `panic!()`: +//! // We only care about typecheck finding every field +//! // here, the expression does not matter, just conjure +//! // one using `panic!()`: //! t: ::core::panic!(), //! x: ::core::panic!(), //! }, //! ); //! }; -//! } -//! // Since initialization has successfully completed, we can now forget the -//! // guards. This is not `mem::forget`, since we only have `&DropGuard`. -//! unsafe { ::kernel::init::__internal::DropGuard::forget(t) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(x) }; +//! }; //! } //! // We leave the scope above and gain access to the previously shadowed //! // `__InitOk` that we need to return. //! Ok(__InitOk) //! }); //! // Change the return type from `__InitOk` to `()`. -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! // Construct the initializer. //! let init = unsafe { -//! ::kernel::init::pin_init_from_closure::<_, ::core::convert::Infallible>(init) +//! ::kernel::init::pin_init_from_closure::< +//! _, +//! ::core::convert::Infallible, +//! >(init) //! }; //! init //! } @@ -374,7 +380,10 @@ //! b: Bar, //! } //! #[doc(hidden)] -//! impl<'__pin> ::core::marker::Unpin for Foo where __Unpin<'__pin>: ::core::marker::Unpin {} +//! 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` implementations like //! // before, instead we implement `Drop` here and delegate to `PinnedDrop`. @@ -403,7 +412,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -414,7 +423,7 @@ //! // `unsafe`, full path and the token parameter are added, everything else stays the same. //! unsafe impl ::kernel::init::PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -449,18 +458,21 @@ //! >(data, move |slot| { //! { //! struct __InitOk; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; -//! let a = &unsafe { +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; +//! } +//! let a = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a)) //! }; -//! let b = Bar::new(36); +//! let init = Bar::new(36); //! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? }; -//! let b = &unsafe { +//! let b = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b)) //! }; -//! +//! ::core::mem::forget(b); +//! ::core::mem::forget(a); //! #[allow(unreachable_code, clippy::diverging_sub_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, @@ -470,13 +482,13 @@ //! }, //! ); //! }; -//! } -//! unsafe { ::kernel::init::__internal::DropGuard::forget(a) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(b) }; +//! }; //! } //! Ok(__InitOk) //! }); -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! let init = unsafe {