Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aa935a1
Merge branch 'net-next-20231228' into rust-dev
fbq Dec 28, 2023
e562737
rust: upgrade to Rust 1.75.0
ojeda Dec 24, 2023
39f11a3
rust: file: add Rust abstraction for `struct file`
wedsonaf Dec 6, 2023
1d0fab6
rust: cred: add Rust abstraction for `struct cred`
wedsonaf Dec 6, 2023
dab0fe4
rust: security: add abstraction for secctx
Darksonn Dec 6, 2023
5a5888c
rust: file: add `FileDescriptorReservation`
wedsonaf Dec 6, 2023
e98a9c7
rust: file: add `Kuid` wrapper
Darksonn Dec 6, 2023
befd131
rust: file: add `DeferredFdCloser`
Darksonn Dec 6, 2023
0d01533
rust: file: add abstraction for `poll_table`
Darksonn Dec 6, 2023
ba17aad
rust: macros: add `decl_generics` to `parse_generics()`
BennoLossin Dec 13, 2023
884a0c6
rust: add improved version of `ForeignOwnable::borrow_mut`
Darksonn Jul 10, 2023
1fd25cc
rust: macros: allow generic parameter default values in `#[pin_data]`
BennoLossin Dec 13, 2023
7ca8daf
rust: Refactor the build target to allow the use of builtin targets
JamieCunliffe Oct 20, 2023
8f7e376
rust: workqueue: add `#[pin_data]` to `Work`
BennoLossin Dec 13, 2023
df91439
arm64: rust: Enable Rust support for AArch64
JamieCunliffe Oct 20, 2023
f3bc6f9
rust: task: add `as_raw()` to `Task`
antonio-hickey Jan 2, 2024
b54bde5
rust: task: use safe `current!` macro
antonio-hickey Jan 4, 2024
0e52e55
rust: macros: add `decl_generics` to `parse_generics()`
BennoLossin Dec 13, 2023
9a1d84e
rust: macros: allow generic parameter default values in `#[pin_data]`
BennoLossin Dec 13, 2023
b01a973
rust: workqueue: add `#[pin_data]` to `Work`
BennoLossin Dec 13, 2023
d02944d
rust: sync: add `CondVar::notify_sync`
Darksonn Jan 8, 2024
b13bfeb
rust: time: add msecs to jiffies conversion
Darksonn Jan 8, 2024
af3c12d
rust: sync: add `CondVar::wait_timeout`
Darksonn Jan 8, 2024
80a1985
rust: sync: update integer types in CondVar
Darksonn Jan 8, 2024
5f46355
rust: file: add Rust abstraction for `struct file`
wedsonaf Dec 6, 2023
87c2ee2
rust: cred: add Rust abstraction for `struct cred`
wedsonaf Dec 6, 2023
31608a9
rust: security: add abstraction for secctx
Darksonn Dec 6, 2023
fd6acd6
rust: file: add `FileDescriptorReservation`
wedsonaf Dec 6, 2023
8257138
rust: file: add `Kuid` wrapper
Darksonn Dec 6, 2023
a49b634
rust: file: add `DeferredFdCloser`
Darksonn Dec 6, 2023
779be36
rust: file: add abstraction for `poll_table`
Darksonn Dec 6, 2023
7822673
Merge branch 'rust-dev' into rust-dev
antonio-hickey Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rust: macros: add decl_generics to parse_generics()
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 <[email protected]>
Reviewed-by: Martin Rodriguez Reboredo <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
BennoLossin authored and fbq committed Jan 8, 2024
commit 0e52e55e67fc543a3cca30c8ab9ee98aae419436
122 changes: 92 additions & 30 deletions rust/macros/helpers.rs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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>,
}

Expand All @@ -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.
Expand All @@ -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);
}
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions rust/macros/pin_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
let (
Generics {
impl_generics,
decl_generics: _,
ty_generics,
},
rest,
Expand Down
1 change: 1 addition & 0 deletions rust/macros/zeroable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {
let (
Generics {
impl_generics,
decl_generics: _,
ty_generics,
},
mut rest,
Expand Down