From 674b1c7aed6082e1ce329bb3bcb49e7eb9913e79 Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Mon, 14 Aug 2023 08:47:28 +0000 Subject: rust: init: add support for arbitrary paths in init macros 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 Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin Link: https://lore.kernel.org/r/20230814084602.25699-10-benno.lossin@proton.me Signed-off-by: Miguel Ojeda --- 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 9931666293fa..5f0a0bdb9896 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1000,7 +1000,7 @@ macro_rules! __pin_data { 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` @@ -1014,7 +1014,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)?), @@ -1025,7 +1025,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` @@ -1039,7 +1039,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)?), @@ -1050,7 +1050,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` @@ -1064,7 +1064,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!( @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1075,7 +1075,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` @@ -1094,7 +1094,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>( @@ -1253,7 +1257,7 @@ macro_rules! __init_internal { }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields(..Zeroable::zeroed() $(,)?), @acc($($acc:tt)*), ) => { @@ -1270,15 +1274,21 @@ macro_rules! __init_internal { // 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)*), ) => { @@ -1286,14 +1296,20 @@ macro_rules! __init_internal { // 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)*), ) => { @@ -1306,7 +1322,7 @@ macro_rules! __init_internal { }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), @acc($($acc:tt)*), ) => { -- cgit v1.2.3-58-ga151