* [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` @ 2023-12-13 22:08 Benno Lossin 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin ` (4 more replies) 0 siblings, 5 replies; 14+ messages in thread From: Benno Lossin @ 2023-12-13 22:08 UTC (permalink / raw) To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Sumera Priyadarsini, Vincenzo Palazzo, Asahi Lina, Martin Rodriguez Reboredo Cc: rust-for-linux, linux-kernel The generic parameters on a type definition can specify default values. Currently `parse_generics()` cannot handle this though. For example when parsing the following generics: <T: Clone, const N: usize = 0> The `impl_generics` will be set to `T: Clone, const N: usize = 0` and `ty_generics` will be set to `T, N`. Now using the `impl_generics` on an impl block: impl<$($impl_generics)*> Foo {} will result in invalid Rust code, because default values are only available on type definitions. Therefore add parsing support for generic parameter default values using a new kind of generics called `decl_generics` and change the old behavior of `impl_generics` to not contain the generic parameter default values. Now `Generics` has three fields: - `impl_generics`: the generics with bounds (e.g. `T: Clone, const N: usize`) - `decl_generics`: the generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`) - `ty_generics`: contains the generics without bounds and without default values (e.g. `T, N`) `impl_generics` is designed to be used on `impl<$impl_generics>`, `decl_generics` for the type definition, so `struct Foo<$decl_generics>` and `ty_generics` whenever you use the type, so `Foo<$ty_generics>`. Here is an example that uses all three different types of generics: let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); quote! { struct Foo<$($decl_generics)*> { // ... } impl<$impl_generics> Foo<$ty_generics> { fn foo() { // ... } } } The next commit contains a fix to the `#[pin_data]` macro making it compatible with generic parameter default values by relying on this new behavior. Signed-off-by: Benno Lossin <benno.lossin@proton.me> --- v1 -> v2: - improve documentation and commit message explanation - add motivation to commit message rust/macros/helpers.rs | 122 ++++++++++++++++++++++++++++++---------- rust/macros/pin_data.rs | 1 + rust/macros/zeroable.rs | 1 + 3 files changed, 94 insertions(+), 30 deletions(-) diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index afb0f2e3a36a..3f50a5c847c8 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -use proc_macro::{token_stream, Group, Punct, Spacing, TokenStream, TokenTree}; +use proc_macro::{token_stream, Group, TokenStream, TokenTree}; pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> { if let Some(TokenTree::Ident(ident)) = it.next() { @@ -70,8 +70,40 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) { } } +/// Parsed generics. +/// +/// See the field documentation for an explanation what each of the fields represents. +/// +/// # Examples +/// +/// ```rust,ignore +/// # let input = todo!(); +/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); +/// quote! { +/// struct Foo<$($decl_generics)*> { +/// // ... +/// } +/// +/// impl<$impl_generics> Foo<$ty_generics> { +/// fn foo() { +/// // ... +/// } +/// } +/// } +/// ``` pub(crate) struct Generics { + /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`). + /// + /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`). + pub(crate) decl_generics: Vec<TokenTree>, + /// The generics with bounds (e.g. `T: Clone, const N: usize`). + /// + /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`. pub(crate) impl_generics: Vec<TokenTree>, + /// The generics without bounds and without default values (e.g. `T, N`). + /// + /// Use this when you use the type that is declared with these generics e.g. + /// `Foo<$ty_generics>`. pub(crate) ty_generics: Vec<TokenTree>, } @@ -81,6 +113,8 @@ pub(crate) struct Generics { pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { // `impl_generics`, the declared generics with their bounds. let mut impl_generics = vec![]; + // The generics with bounds and default values. + let mut decl_generics = vec![]; // Only the names of the generics, without any bounds. let mut ty_generics = vec![]; // Tokens not related to the generics e.g. the `where` token and definition. @@ -90,10 +124,17 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { let mut toks = input.into_iter(); // If we are at the beginning of a generic parameter. let mut at_start = true; - for tt in &mut toks { + let mut skip_until_comma = false; + while let Some(tt) = toks.next() { + if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') { + // Found the end of the generics. + break; + } else if nesting >= 1 { + decl_generics.push(tt.clone()); + } match tt.clone() { TokenTree::Punct(p) if p.as_char() == '<' => { - if nesting >= 1 { + if nesting >= 1 && !skip_until_comma { // This is inside of the generics and part of some bound. impl_generics.push(tt); } @@ -105,49 +146,70 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { break; } else { nesting -= 1; - if nesting >= 1 { + if nesting >= 1 && !skip_until_comma { // We are still inside of the generics and part of some bound. impl_generics.push(tt); } - if nesting == 0 { - break; - } } } - tt => { + TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => { if nesting == 1 { - // Here depending on the token, it might be a generic variable name. - match &tt { - // Ignore const. - TokenTree::Ident(i) if i.to_string() == "const" => {} - TokenTree::Ident(_) if at_start => { - ty_generics.push(tt.clone()); - // We also already push the `,` token, this makes it easier to append - // generics. - ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); - at_start = false; - } - TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, - // Lifetimes begin with `'`. - TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { - ty_generics.push(tt.clone()); - } - _ => {} - } + impl_generics.push(TokenTree::Punct(p.clone())); + ty_generics.push(TokenTree::Punct(p)); + skip_until_comma = false; } - if nesting >= 1 { - impl_generics.push(tt); - } else if nesting == 0 { + } + tt if !skip_until_comma => { + match nesting { // If we haven't entered the generics yet, we still want to keep these tokens. - rest.push(tt); + 0 => rest.push(tt), + 1 => { + // Here depending on the token, it might be a generic variable name. + match tt { + TokenTree::Ident(i) if at_start && i.to_string() == "const" => { + let Some(name) = toks.next() else { + // Parsing error. + break; + }; + impl_generics.push(TokenTree::Ident(i)); + impl_generics.push(name.clone()); + ty_generics.push(name.clone()); + decl_generics.push(name); + at_start = false; + } + tt @ TokenTree::Ident(_) if at_start => { + impl_generics.push(tt.clone()); + ty_generics.push(tt); + at_start = false; + } + TokenTree::Punct(p) if p.as_char() == ',' => { + impl_generics.push(TokenTree::Punct(p.clone())); + ty_generics.push(TokenTree::Punct(p)); + at_start = true; + } + // Lifetimes begin with `'`. + TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { + ty_generics.push(TokenTree::Punct(p.clone())); + impl_generics.push(TokenTree::Punct(p)); + } + // Generics can have default values, we skip these. + TokenTree::Punct(p) if p.as_char() == '=' => { + skip_until_comma = true; + } + tt => impl_generics.push(tt), + } + } + _ => impl_generics.push(tt), } } + _ => {} } } rest.extend(toks); ( Generics { impl_generics, + decl_generics, ty_generics, }, rest, diff --git a/rust/macros/pin_data.rs b/rust/macros/pin_data.rs index 6d58cfda9872..022e68e9720d 100644 --- a/rust/macros/pin_data.rs +++ b/rust/macros/pin_data.rs @@ -10,6 +10,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { let ( Generics { impl_generics, + decl_generics: _, ty_generics, }, rest, diff --git a/rust/macros/zeroable.rs b/rust/macros/zeroable.rs index 0d605c46ab3b..cfee2cec18d5 100644 --- a/rust/macros/zeroable.rs +++ b/rust/macros/zeroable.rs @@ -7,6 +7,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { let ( Generics { impl_generics, + decl_generics: _, ty_generics, }, mut rest, base-commit: d9857c16cfc6bce7764e1b79956c6a028f97f4d0 -- 2.42.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin @ 2023-12-13 22:08 ` Benno Lossin 2023-12-14 3:11 ` Martin Rodriguez Reboredo ` (2 more replies) 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin ` (3 subsequent siblings) 4 siblings, 3 replies; 14+ messages in thread From: Benno Lossin @ 2023-12-13 22:08 UTC (permalink / raw) To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Martin Rodriguez Reboredo Cc: rust-for-linux, linux-kernel Add support for generic parameters defaults in `#[pin_data]` by using the newly introduced `decl_generics` instead of the `impl_generics`. Before this would not compile: #[pin_data] struct Foo<const N: usize = 0> { // ... } because it would be expanded to this: struct Foo<const N: usize = 0> { // ... } const _: () = { struct __ThePinData<const N: usize = 0> { __phantom: ::core::marker::PhantomData<fn(Foo<N>) -> Foo<N>>, } impl<const N: usize = 0> ::core::clone::Clone for __ThePinData<N> { fn clone(&self) -> Self { *self } } // [...] rest of expansion omitted }; The problem is with the `impl<const N: usize = 0>`, since that is invalid Rust syntax. It should not mention the default value at all, since default values only make sense on type definitions. The new `impl_generics` do not contain the default values, thus generating correct Rust code. This is used by the next commit that puts `#[pin_data]` on `kernel::workqueue::Work`. Signed-off-by: Benno Lossin <benno.lossin@proton.me> --- v1 -> v2: - clarify the change in the commit message - add motivation to the commit message rust/kernel/init/macros.rs | 19 ++++++++++++++++++- rust/macros/pin_data.rs | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index cb6e61b6c50b..624e9108e3b4 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -538,6 +538,7 @@ macro_rules! __pin_data { ), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @body({ $($fields:tt)* }), ) => { // We now use token munching to iterate through all of the fields. While doing this we @@ -560,6 +561,9 @@ macro_rules! __pin_data { @impl_generics($($impl_generics)*), // The 'ty generics', the generics that will need to be specified on the impl blocks. @ty_generics($($ty_generics)*), + // The 'decl generics', the generics that need to be specified on the struct + // definition. + @decl_generics($($decl_generics)*), // The where clause of any impl block and the declaration. @where($($($whr)*)?), // The remaining fields tokens that need to be processed. @@ -585,6 +589,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We found a PhantomPinned field, this should generally be pinned! @fields_munch($field:ident : $($($(::)?core::)?marker::)?PhantomPinned, $($rest:tt)*), @@ -607,6 +612,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($($rest)*), @pinned($($pinned)* $($accum)* $field: ::core::marker::PhantomPinned,), @@ -623,6 +629,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We reached the field declaration. @fields_munch($field:ident : $type:ty, $($rest:tt)*), @@ -640,6 +647,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($($rest)*), @pinned($($pinned)* $($accum)* $field: $type,), @@ -656,6 +664,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We reached the field declaration. @fields_munch($field:ident : $type:ty, $($rest:tt)*), @@ -673,6 +682,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($($rest)*), @pinned($($pinned)*), @@ -689,6 +699,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We found the `#[pin]` attr. @fields_munch(#[pin] $($rest:tt)*), @@ -705,6 +716,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($($rest)*), // We do not include `#[pin]` in the list of attributes, since it is not actually an @@ -724,6 +736,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We reached the field declaration with visibility, for simplicity we only munch the // visibility and put it into `$accum`. @@ -741,6 +754,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($field $($rest)*), @pinned($($pinned)*), @@ -757,6 +771,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // Some other attribute, just put it into `$accum`. @fields_munch(#[$($attr:tt)*] $($rest:tt)*), @@ -773,6 +788,7 @@ macro_rules! __pin_data { @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), + @decl_generics($($decl_generics)*), @where($($whr)*), @fields_munch($($rest)*), @pinned($($pinned)*), @@ -789,6 +805,7 @@ macro_rules! __pin_data { @name($name:ident), @impl_generics($($impl_generics:tt)*), @ty_generics($($ty_generics:tt)*), + @decl_generics($($decl_generics:tt)*), @where($($whr:tt)*), // We reached the end of the fields, plus an optional additional comma, since we added one // before and the user is also allowed to put a trailing comma. @@ -802,7 +819,7 @@ macro_rules! __pin_data { ) => { // Declare the struct with all fields in the correct order. $($struct_attrs)* - $vis struct $name <$($impl_generics)*> + $vis struct $name <$($decl_generics)*> where $($whr)* { $($fields)* diff --git a/rust/macros/pin_data.rs b/rust/macros/pin_data.rs index 022e68e9720d..1d4a3547c684 100644 --- a/rust/macros/pin_data.rs +++ b/rust/macros/pin_data.rs @@ -10,7 +10,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { let ( Generics { impl_generics, - decl_generics: _, + decl_generics, ty_generics, }, rest, @@ -77,6 +77,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { @sig(#(#rest)*), @impl_generics(#(#impl_generics)*), @ty_generics(#(#ty_generics)*), + @decl_generics(#(#decl_generics)*), @body(#last), }); quoted.extend(errs); -- 2.42.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin @ 2023-12-14 3:11 ` Martin Rodriguez Reboredo 2023-12-23 14:42 ` Gary Guo 2024-01-04 15:18 ` Alice Ryhl 2 siblings, 0 replies; 14+ messages in thread From: Martin Rodriguez Reboredo @ 2023-12-14 3:11 UTC (permalink / raw) To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Alice Ryhl Cc: rust-for-linux, linux-kernel On 12/13/23 19:08, Benno Lossin wrote: > Add support for generic parameters defaults in `#[pin_data]` by using > the newly introduced `decl_generics` instead of the `impl_generics`. > > Before this would not compile: > > #[pin_data] > struct Foo<const N: usize = 0> { > // ... > } > > because it would be expanded to this: > > struct Foo<const N: usize = 0> { > // ... > } > > const _: () = { > struct __ThePinData<const N: usize = 0> { > __phantom: ::core::marker::PhantomData<fn(Foo<N>) -> Foo<N>>, > } > impl<const N: usize = 0> ::core::clone::Clone for __ThePinData<N> { > fn clone(&self) -> Self { > *self > } > } > > // [...] rest of expansion omitted > }; > > The problem is with the `impl<const N: usize = 0>`, since that is > invalid Rust syntax. It should not mention the default value at all, > since default values only make sense on type definitions. > > The new `impl_generics` do not contain the default values, thus > generating correct Rust code. > > This is used by the next commit that puts `#[pin_data]` on > `kernel::workqueue::Work`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > [...] Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin 2023-12-14 3:11 ` Martin Rodriguez Reboredo @ 2023-12-23 14:42 ` Gary Guo 2024-01-04 15:18 ` Alice Ryhl 2 siblings, 0 replies; 14+ messages in thread From: Gary Guo @ 2023-12-23 14:42 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Martin Rodriguez Reboredo, rust-for-linux, linux-kernel On Wed, 13 Dec 2023 22:08:53 +0000 Benno Lossin <benno.lossin@proton.me> wrote: > Add support for generic parameters defaults in `#[pin_data]` by using > the newly introduced `decl_generics` instead of the `impl_generics`. > > Before this would not compile: > > #[pin_data] > struct Foo<const N: usize = 0> { > // ... > } > > because it would be expanded to this: > > struct Foo<const N: usize = 0> { > // ... > } > > const _: () = { > struct __ThePinData<const N: usize = 0> { > __phantom: ::core::marker::PhantomData<fn(Foo<N>) -> Foo<N>>, > } > impl<const N: usize = 0> ::core::clone::Clone for __ThePinData<N> { > fn clone(&self) -> Self { > *self > } > } > > // [...] rest of expansion omitted > }; > > The problem is with the `impl<const N: usize = 0>`, since that is > invalid Rust syntax. It should not mention the default value at all, > since default values only make sense on type definitions. > > The new `impl_generics` do not contain the default values, thus > generating correct Rust code. > > This is used by the next commit that puts `#[pin_data]` on > `kernel::workqueue::Work`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Gary Guo <gary@garyguo.net> > --- > v1 -> v2: > - clarify the change in the commit message > - add motivation to the commit message > > rust/kernel/init/macros.rs | 19 ++++++++++++++++++- > rust/macros/pin_data.rs | 3 ++- > 2 files changed, 20 insertions(+), 2 deletions(-) ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin 2023-12-14 3:11 ` Martin Rodriguez Reboredo 2023-12-23 14:42 ` Gary Guo @ 2024-01-04 15:18 ` Alice Ryhl 2 siblings, 0 replies; 14+ messages in thread From: Alice Ryhl @ 2024-01-04 15:18 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Martin Rodriguez Reboredo, rust-for-linux, linux-kernel On Wed, Dec 13, 2023 at 11:09 PM Benno Lossin <benno.lossin@proton.me> wrote: > > Add support for generic parameters defaults in `#[pin_data]` by using > the newly introduced `decl_generics` instead of the `impl_generics`. > > Before this would not compile: > > #[pin_data] > struct Foo<const N: usize = 0> { > // ... > } > > because it would be expanded to this: > > struct Foo<const N: usize = 0> { > // ... > } > > const _: () = { > struct __ThePinData<const N: usize = 0> { > __phantom: ::core::marker::PhantomData<fn(Foo<N>) -> Foo<N>>, > } > impl<const N: usize = 0> ::core::clone::Clone for __ThePinData<N> { > fn clone(&self) -> Self { > *self > } > } > > // [...] rest of expansion omitted > }; > > The problem is with the `impl<const N: usize = 0>`, since that is > invalid Rust syntax. It should not mention the default value at all, > since default values only make sense on type definitions. > > The new `impl_generics` do not contain the default values, thus > generating correct Rust code. > > This is used by the next commit that puts `#[pin_data]` on > `kernel::workqueue::Work`. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Tested-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin @ 2023-12-13 22:09 ` Benno Lossin 2023-12-14 3:13 ` Martin Rodriguez Reboredo ` (2 more replies) 2023-12-14 2:57 ` [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Martin Rodriguez Reboredo ` (2 subsequent siblings) 4 siblings, 3 replies; 14+ messages in thread From: Benno Lossin @ 2023-12-13 22:09 UTC (permalink / raw) To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Martin Rodriguez Reboredo, Tejun Heo Cc: Wedson Almeida Filho, rust-for-linux, linux-kernel The previous two patches made it possible to add `#[pin_data]` on structs with default generic parameter values. This patch makes `Work` use `#[pin_data]` and removes an invocation of `pin_init_from_closure`. This function is intended as a low level manual escape hatch, so it is better to rely on the safe `pin_init!` macro. Signed-off-by: Benno Lossin <benno.lossin@proton.me> --- v1 -> v2: - improve commit message wording - change `:` to `<-` in `pin_init!` invocation rust/kernel/workqueue.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index b67fb1ba168e..4a9fb7d06d20 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -334,8 +334,10 @@ pub trait WorkItem<const ID: u64 = 0> { /// Wraps the kernel's C `struct work_struct`. /// /// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it. +#[pin_data] #[repr(transparent)] pub struct Work<T: ?Sized, const ID: u64 = 0> { + #[pin] work: Opaque<bindings::work_struct>, _inner: PhantomData<T>, } @@ -357,21 +359,22 @@ pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self where T: WorkItem<ID>, { - // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as the work - // item function. - unsafe { - kernel::init::pin_init_from_closure(move |slot| { - let slot = Self::raw_get(slot); - bindings::init_work_with_key( - slot, - Some(T::Pointer::run), - false, - name.as_char_ptr(), - key.as_ptr(), - ); - Ok(()) - }) - } + pin_init!(Self { + work <- Opaque::ffi_init(|slot| { + // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as + // the work item function. + unsafe { + bindings::init_work_with_key( + slot, + Some(T::Pointer::run), + false, + name.as_char_ptr(), + key.as_ptr(), + ) + } + }), + _inner: PhantomData, + }) } /// Get a pointer to the inner `work_struct`. -- 2.42.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin @ 2023-12-14 3:13 ` Martin Rodriguez Reboredo 2023-12-18 17:47 ` Benno Lossin 2023-12-23 14:43 ` Gary Guo 2024-01-04 15:19 ` Alice Ryhl 2 siblings, 1 reply; 14+ messages in thread From: Martin Rodriguez Reboredo @ 2023-12-14 3:13 UTC (permalink / raw) To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Tejun Heo Cc: Wedson Almeida Filho, rust-for-linux, linux-kernel On 12/13/23 19:09, Benno Lossin wrote: > The previous two patches made it possible to add `#[pin_data]` on > structs with default generic parameter values. > This patch makes `Work` use `#[pin_data]` and removes an invocation of > `pin_init_from_closure`. This function is intended as a low level manual > escape hatch, so it is better to rely on the safe `pin_init!` macro. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > [...] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-14 3:13 ` Martin Rodriguez Reboredo @ 2023-12-18 17:47 ` Benno Lossin 2023-12-18 20:49 ` Martin Rodriguez Reboredo 0 siblings, 1 reply; 14+ messages in thread From: Benno Lossin @ 2023-12-18 17:47 UTC (permalink / raw) To: Martin Rodriguez Reboredo, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Tejun Heo Cc: Wedson Almeida Filho, rust-for-linux, linux-kernel On 12/14/23 04:13, Martin Rodriguez Reboredo wrote: > On 12/13/23 19:09, Benno Lossin wrote: >> The previous two patches made it possible to add `#[pin_data]` on >> structs with default generic parameter values. >> This patch makes `Work` use `#[pin_data]` and removes an invocation of >> `pin_init_from_closure`. This function is intended as a low level manual >> escape hatch, so it is better to rely on the safe `pin_init!` macro. >> >> Signed-off-by: Benno Lossin <benno.lossin@proton.me> >> --- >> [...] Did you mean to add your reviewed by? Because I received only the quote. -- Cheers, Benno ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-18 17:47 ` Benno Lossin @ 2023-12-18 20:49 ` Martin Rodriguez Reboredo 0 siblings, 0 replies; 14+ messages in thread From: Martin Rodriguez Reboredo @ 2023-12-18 20:49 UTC (permalink / raw) To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Tejun Heo Cc: Wedson Almeida Filho, rust-for-linux, linux-kernel On 12/18/23 14:47, Benno Lossin wrote: > On 12/14/23 04:13, Martin Rodriguez Reboredo wrote: >> On 12/13/23 19:09, Benno Lossin wrote: >>> The previous two patches made it possible to add `#[pin_data]` on >>> structs with default generic parameter values. >>> This patch makes `Work` use `#[pin_data]` and removes an invocation of >>> `pin_init_from_closure`. This function is intended as a low level manual >>> escape hatch, so it is better to rely on the safe `pin_init!` macro. >>> >>> Signed-off-by: Benno Lossin <benno.lossin@proton.me> >>> --- >>> [...] > > Did you mean to add your reviewed by? Because I received only > the quote. > Thunderbird is a disaster for plain-text emails. Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin 2023-12-14 3:13 ` Martin Rodriguez Reboredo @ 2023-12-23 14:43 ` Gary Guo 2024-01-04 15:19 ` Alice Ryhl 2 siblings, 0 replies; 14+ messages in thread From: Gary Guo @ 2023-12-23 14:43 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Martin Rodriguez Reboredo, Tejun Heo, Wedson Almeida Filho, rust-for-linux, linux-kernel On Wed, 13 Dec 2023 22:09:04 +0000 Benno Lossin <benno.lossin@proton.me> wrote: > The previous two patches made it possible to add `#[pin_data]` on > structs with default generic parameter values. > This patch makes `Work` use `#[pin_data]` and removes an invocation of > `pin_init_from_closure`. This function is intended as a low level manual > escape hatch, so it is better to rely on the safe `pin_init!` macro. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Gary Guo <gary@garyguo.net> > --- > v1 -> v2: > - improve commit message wording > - change `:` to `<-` in `pin_init!` invocation > > rust/kernel/workqueue.rs | 33 ++++++++++++++++++--------------- > 1 file changed, 18 insertions(+), 15 deletions(-) ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin 2023-12-14 3:13 ` Martin Rodriguez Reboredo 2023-12-23 14:43 ` Gary Guo @ 2024-01-04 15:19 ` Alice Ryhl 2 siblings, 0 replies; 14+ messages in thread From: Alice Ryhl @ 2024-01-04 15:19 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Martin Rodriguez Reboredo, Tejun Heo, Wedson Almeida Filho, rust-for-linux, linux-kernel On Wed, Dec 13, 2023 at 11:09 PM Benno Lossin <benno.lossin@proton.me> wrote: > > The previous two patches made it possible to add `#[pin_data]` on > structs with default generic parameter values. > This patch makes `Work` use `#[pin_data]` and removes an invocation of > `pin_init_from_closure`. This function is intended as a low level manual > escape hatch, so it is better to rely on the safe `pin_init!` macro. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Tested-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin @ 2023-12-14 2:57 ` Martin Rodriguez Reboredo 2023-12-23 14:41 ` Gary Guo 2024-01-04 15:17 ` Alice Ryhl 4 siblings, 0 replies; 14+ messages in thread From: Martin Rodriguez Reboredo @ 2023-12-14 2:57 UTC (permalink / raw) To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Sumera Priyadarsini, Vincenzo Palazzo, Asahi Lina Cc: rust-for-linux, linux-kernel On 12/13/23 19:08, Benno Lossin wrote: > The generic parameters on a type definition can specify default values. > Currently `parse_generics()` cannot handle this though. For example when > parsing the following generics: > > <T: Clone, const N: usize = 0> > > The `impl_generics` will be set to `T: Clone, const N: usize = 0` and > `ty_generics` will be set to `T, N`. Now using the `impl_generics` on an > impl block: > > impl<$($impl_generics)*> Foo {} > > will result in invalid Rust code, because default values are only > available on type definitions. > > Therefore add parsing support for generic parameter default values using > a new kind of generics called `decl_generics` and change the old > behavior of `impl_generics` to not contain the generic parameter default > values. > > Now `Generics` has three fields: > - `impl_generics`: the generics with bounds > (e.g. `T: Clone, const N: usize`) > - `decl_generics`: the generics with bounds and default values > (e.g. `T: Clone, const N: usize = 0`) > - `ty_generics`: contains the generics without bounds and without > default values (e.g. `T, N`) > > `impl_generics` is designed to be used on `impl<$impl_generics>`, > `decl_generics` for the type definition, so `struct Foo<$decl_generics>` > and `ty_generics` whenever you use the type, so `Foo<$ty_generics>`. > > Here is an example that uses all three different types of generics: > > let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); > quote! { > struct Foo<$($decl_generics)*> { > // ... > } > > impl<$impl_generics> Foo<$ty_generics> { > fn foo() { > // ... > } > } > } > > The next commit contains a fix to the `#[pin_data]` macro making it > compatible with generic parameter default values by relying on this new > behavior. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> > --- > [...] Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin ` (2 preceding siblings ...) 2023-12-14 2:57 ` [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Martin Rodriguez Reboredo @ 2023-12-23 14:41 ` Gary Guo 2024-01-04 15:17 ` Alice Ryhl 4 siblings, 0 replies; 14+ messages in thread From: Gary Guo @ 2023-12-23 14:41 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Sumera Priyadarsini, Vincenzo Palazzo, Asahi Lina, Martin Rodriguez Reboredo, rust-for-linux, linux-kernel The logic looks good to me, some nits: > +/// Parsed generics. > +/// > +/// See the field documentation for an explanation what each of the fields represents. > +/// > +/// # Examples > +/// > +/// ```rust,ignore > +/// # let input = todo!(); > +/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); > +/// quote! { > +/// struct Foo<$($decl_generics)*> { > +/// // ... > +/// } > +/// > +/// impl<$impl_generics> Foo<$ty_generics> { > +/// fn foo() { > +/// // ... > +/// } > +/// } > +/// } > +/// ``` > pub(crate) struct Generics { > + /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`). > + /// > + /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`). > + pub(crate) decl_generics: Vec<TokenTree>, > + /// The generics with bounds (e.g. `T: Clone, const N: usize`). > + /// > + /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`. > pub(crate) impl_generics: Vec<TokenTree>, > + /// The generics without bounds and without default values (e.g. `T, N`). > + /// > + /// Use this when you use the type that is declared with these generics e.g. > + /// `Foo<$ty_generics>`. > pub(crate) ty_generics: Vec<TokenTree>, > } > > @@ -81,6 +113,8 @@ pub(crate) struct Generics { > pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { > // `impl_generics`, the declared generics with their bounds. > let mut impl_generics = vec![]; > + // The generics with bounds and default values. > + let mut decl_generics = vec![]; It'll be great if the order if the same as the declaration in struct above. > // Only the names of the generics, without any bounds. > let mut ty_generics = vec![]; > // Tokens not related to the generics e.g. the `where` token and definition. > @@ -90,10 +124,17 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { > let mut toks = input.into_iter(); > // If we are at the beginning of a generic parameter. > let mut at_start = true; > - for tt in &mut toks { > + let mut skip_until_comma = false; > + while let Some(tt) = toks.next() { > + if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') { > + // Found the end of the generics. > + break; > + } else if nesting >= 1 { > + decl_generics.push(tt.clone()); > + } > match tt.clone() { > TokenTree::Punct(p) if p.as_char() == '<' => { > - if nesting >= 1 { > + if nesting >= 1 && !skip_until_comma { > // This is inside of the generics and part of some bound. > impl_generics.push(tt); > } > @@ -105,49 +146,70 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { > break; > } else { > nesting -= 1; > - if nesting >= 1 { > + if nesting >= 1 && !skip_until_comma { > // We are still inside of the generics and part of some bound. > impl_generics.push(tt); > } > - if nesting == 0 { > - break; > - } > } > } > - tt => { > + TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => { > if nesting == 1 { > - // Here depending on the token, it might be a generic variable name. > - match &tt { > - // Ignore const. > - TokenTree::Ident(i) if i.to_string() == "const" => {} > - TokenTree::Ident(_) if at_start => { > - ty_generics.push(tt.clone()); > - // We also already push the `,` token, this makes it easier to append > - // generics. > - ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); > - at_start = false; > - } > - TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, > - // Lifetimes begin with `'`. > - TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { > - ty_generics.push(tt.clone()); > - } > - _ => {} > - } > + impl_generics.push(TokenTree::Punct(p.clone())); > + ty_generics.push(TokenTree::Punct(p)); This could just be impl_generics.push(tt.clone()); ty_generics.push(tt); ? > + skip_until_comma = false; > } > - if nesting >= 1 { > - impl_generics.push(tt); > - } else if nesting == 0 { > + } > + tt if !skip_until_comma => { > + match nesting { > // If we haven't entered the generics yet, we still want to keep these tokens. > - rest.push(tt); > + 0 => rest.push(tt), > + 1 => { > + // Here depending on the token, it might be a generic variable name. > + match tt { > + TokenTree::Ident(i) if at_start && i.to_string() == "const" => { > + let Some(name) = toks.next() else { > + // Parsing error. > + break; > + }; > + impl_generics.push(TokenTree::Ident(i)); Similar, this could just be push tt. > + impl_generics.push(name.clone()); > + ty_generics.push(name.clone()); > + decl_generics.push(name); > + at_start = false; > + } > + tt @ TokenTree::Ident(_) if at_start => { > + impl_generics.push(tt.clone()); > + ty_generics.push(tt); > + at_start = false; > + } > + TokenTree::Punct(p) if p.as_char() == ',' => { > + impl_generics.push(TokenTree::Punct(p.clone())); > + ty_generics.push(TokenTree::Punct(p)); > + at_start = true; > + } I am not sure why the ident above uses tt, but this spells thing all out. > + // Lifetimes begin with `'`. > + TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { > + ty_generics.push(TokenTree::Punct(p.clone())); > + impl_generics.push(TokenTree::Punct(p)); > + } ditto > + // Generics can have default values, we skip these. > + TokenTree::Punct(p) if p.as_char() == '=' => { > + skip_until_comma = true; > + } > + tt => impl_generics.push(tt), > + } > + } > + _ => impl_generics.push(tt), > } > } > + _ => {} > } > } > rest.extend(toks); > ( > Generics { > impl_generics, > + decl_generics, > ty_generics, > }, > rest, > diff --git a/rust/macros/pin_data.rs b/rust/macros/pin_data.rs > index 6d58cfda9872..022e68e9720d 100644 > --- a/rust/macros/pin_data.rs > +++ b/rust/macros/pin_data.rs > @@ -10,6 +10,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { > let ( > Generics { > impl_generics, > + decl_generics: _, > ty_generics, > }, > rest, > diff --git a/rust/macros/zeroable.rs b/rust/macros/zeroable.rs > index 0d605c46ab3b..cfee2cec18d5 100644 > --- a/rust/macros/zeroable.rs > +++ b/rust/macros/zeroable.rs > @@ -7,6 +7,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream { > let ( > Generics { > impl_generics, > + decl_generics: _, > ty_generics, > }, > mut rest, > > base-commit: d9857c16cfc6bce7764e1b79956c6a028f97f4d0 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin ` (3 preceding siblings ...) 2023-12-23 14:41 ` Gary Guo @ 2024-01-04 15:17 ` Alice Ryhl 4 siblings, 0 replies; 14+ messages in thread From: Alice Ryhl @ 2024-01-04 15:17 UTC (permalink / raw) To: Benno Lossin Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg, Sumera Priyadarsini, Vincenzo Palazzo, Asahi Lina, Martin Rodriguez Reboredo, rust-for-linux, linux-kernel On Wed, Dec 13, 2023 at 11:08 PM Benno Lossin <benno.lossin@proton.me> wrote: > > The generic parameters on a type definition can specify default values. > Currently `parse_generics()` cannot handle this though. For example when > parsing the following generics: > > <T: Clone, const N: usize = 0> > > The `impl_generics` will be set to `T: Clone, const N: usize = 0` and > `ty_generics` will be set to `T, N`. Now using the `impl_generics` on an > impl block: > > impl<$($impl_generics)*> Foo {} > > will result in invalid Rust code, because default values are only > available on type definitions. > > Therefore add parsing support for generic parameter default values using > a new kind of generics called `decl_generics` and change the old > behavior of `impl_generics` to not contain the generic parameter default > values. > > Now `Generics` has three fields: > - `impl_generics`: the generics with bounds > (e.g. `T: Clone, const N: usize`) > - `decl_generics`: the generics with bounds and default values > (e.g. `T: Clone, const N: usize = 0`) > - `ty_generics`: contains the generics without bounds and without > default values (e.g. `T, N`) > > `impl_generics` is designed to be used on `impl<$impl_generics>`, > `decl_generics` for the type definition, so `struct Foo<$decl_generics>` > and `ty_generics` whenever you use the type, so `Foo<$ty_generics>`. > > Here is an example that uses all three different types of generics: > > let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); > quote! { > struct Foo<$($decl_generics)*> { > // ... > } > > impl<$impl_generics> Foo<$ty_generics> { > fn foo() { > // ... > } > } > } > > The next commit contains a fix to the `#[pin_data]` macro making it > compatible with generic parameter default values by relying on this new > behavior. > > Signed-off-by: Benno Lossin <benno.lossin@proton.me> Tested-by: Alice Ryhl <aliceryhl@google.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-01-04 15:19 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-12-13 22:08 [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Benno Lossin 2023-12-13 22:08 ` [PATCH v2 2/3] rust: macros: allow generic parameter default values in `#[pin_data]` Benno Lossin 2023-12-14 3:11 ` Martin Rodriguez Reboredo 2023-12-23 14:42 ` Gary Guo 2024-01-04 15:18 ` Alice Ryhl 2023-12-13 22:09 ` [PATCH v2 3/3] rust: workqueue: add `#[pin_data]` to `Work` Benno Lossin 2023-12-14 3:13 ` Martin Rodriguez Reboredo 2023-12-18 17:47 ` Benno Lossin 2023-12-18 20:49 ` Martin Rodriguez Reboredo 2023-12-23 14:43 ` Gary Guo 2024-01-04 15:19 ` Alice Ryhl 2023-12-14 2:57 ` [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()` Martin Rodriguez Reboredo 2023-12-23 14:41 ` Gary Guo 2024-01-04 15:17 ` Alice Ryhl
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).