[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CABVgOS=f2CdEyrMbQiPc5Jehc0GCzPdv1a790VDFcJ7CtZzYfg@mail.gmail.com>
Date: Mon, 19 Jan 2026 15:09:47 +0800
From: David Gow <davidgow@...gle.com>
To: Gary Guo <gary@...yguo.net>
Cc: Miguel Ojeda <ojeda@...nel.org>, Boqun Feng <boqun.feng@...il.com>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>, Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>,
Danilo Krummrich <dakr@...nel.org>, Brendan Higgins <brendan.higgins@...ux.dev>,
Rae Moar <raemoar63@...il.com>, Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>, Daniel Gomez <da.gomez@...nel.org>,
Sami Tolvanen <samitolvanen@...gle.com>, Aaron Tomlin <atomlin@...mlin.com>,
Tamir Duberstein <tamird@...il.com>, Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
José Expósito <jose.exposito89@...il.com>,
rust-for-linux@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-kselftest@...r.kernel.org, kunit-dev@...glegroups.com,
linux-modules@...r.kernel.org
Subject: Re: [PATCH v3 02/12] rust: macros: use `quote!` from vendored crate
On Tue, 13 Jan 2026 at 01:11, Gary Guo <gary@...nel.org> wrote:
>
> From: Gary Guo <gary@...yguo.net>
>
> With `quote` crate now vendored in the kernel, we can remove our custom
> `quote!` macro implementation and just rely on that crate instead.
>
> The `quote` crate uses types from the `proc-macro2` library so we also
> update to use that, and perform conversion in the top-level lib.rs.
>
> Clippy complains about unnecessary `.to_string()` as `proc-macro2`
> provides additional `PartialEq` impl, so they are removed.
>
> Reviewed-by: Tamir Duberstein <tamird@...il.com>
> Reviewed-by: Benno Lossin <lossin@...nel.org>
> Signed-off-by: Gary Guo <gary@...yguo.net>
> ---
Acked-by: David Gow <davidgow@...gle.com> # for kunit
Cheers,
-- David
-- David
> rust/macros/concat_idents.rs | 2 +-
> rust/macros/export.rs | 4 +-
> rust/macros/fmt.rs | 4 +-
> rust/macros/helpers.rs | 4 +-
> rust/macros/kunit.rs | 5 +-
> rust/macros/lib.rs | 21 ++--
> rust/macros/module.rs | 6 +-
> rust/macros/paste.rs | 2 +-
> rust/macros/quote.rs | 182 -----------------------------------
> rust/macros/vtable.rs | 7 +-
> 10 files changed, 32 insertions(+), 205 deletions(-)
> delete mode 100644 rust/macros/quote.rs
>
> diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
> index 7e4b450f3a507..12cb231c3d715 100644
> --- a/rust/macros/concat_idents.rs
> +++ b/rust/macros/concat_idents.rs
> @@ -1,6 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -use proc_macro::{token_stream, Ident, TokenStream, TokenTree};
> +use proc_macro2::{token_stream, Ident, TokenStream, TokenTree};
>
> use crate::helpers::expect_punct;
>
> diff --git a/rust/macros/export.rs b/rust/macros/export.rs
> index a08f6337d5c8d..92d9b30971929 100644
> --- a/rust/macros/export.rs
> +++ b/rust/macros/export.rs
> @@ -1,7 +1,9 @@
> // SPDX-License-Identifier: GPL-2.0
>
> +use proc_macro2::TokenStream;
> +use quote::quote;
> +
> use crate::helpers::function_name;
> -use proc_macro::TokenStream;
>
> /// Please see [`crate::export`] for documentation.
> pub(crate) fn export(_attr: TokenStream, ts: TokenStream) -> TokenStream {
> diff --git a/rust/macros/fmt.rs b/rust/macros/fmt.rs
> index 2f4b9f6e22110..19f709262552b 100644
> --- a/rust/macros/fmt.rs
> +++ b/rust/macros/fmt.rs
> @@ -1,8 +1,10 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -use proc_macro::{Ident, TokenStream, TokenTree};
> use std::collections::BTreeSet;
>
> +use proc_macro2::{Ident, TokenStream, TokenTree};
> +use quote::quote_spanned;
> +
> /// Please see [`crate::fmt`] for documentation.
> pub(crate) fn fmt(input: TokenStream) -> TokenStream {
> let mut input = input.into_iter();
> diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
> index 365d7eb499c08..13fafaba12261 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, Ident, TokenStream, TokenTree};
> +use proc_macro2::{token_stream, Group, Ident, TokenStream, TokenTree};
>
> pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
> if let Some(TokenTree::Ident(ident)) = it.next() {
> @@ -86,7 +86,7 @@ pub(crate) fn function_name(input: TokenStream) -> Option<Ident> {
> let mut input = input.into_iter();
> while let Some(token) = input.next() {
> match token {
> - TokenTree::Ident(i) if i.to_string() == "fn" => {
> + TokenTree::Ident(i) if i == "fn" => {
> if let Some(TokenTree::Ident(i)) = input.next() {
> return Some(i);
> }
> diff --git a/rust/macros/kunit.rs b/rust/macros/kunit.rs
> index b395bb0536959..5cd6aa5eef07d 100644
> --- a/rust/macros/kunit.rs
> +++ b/rust/macros/kunit.rs
> @@ -4,10 +4,11 @@
> //!
> //! Copyright (c) 2023 José Expósito <jose.exposito89@...il.com>
>
> -use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
> use std::collections::HashMap;
> use std::fmt::Write;
>
> +use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
> +
> pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
> let attr = attr.to_string();
>
> @@ -59,7 +60,7 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
> }
> _ => (),
> },
> - TokenTree::Ident(i) if i.to_string() == "fn" && attributes.contains_key("test") => {
> + TokenTree::Ident(i) if i == "fn" && attributes.contains_key("test") => {
> if let Some(TokenTree::Ident(test_name)) = body_it.next() {
> tests.push((test_name, attributes.remove("cfg").unwrap_or_default()))
> }
> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
> index b38002151871a..945982c21f703 100644
> --- a/rust/macros/lib.rs
> +++ b/rust/macros/lib.rs
> @@ -11,8 +11,6 @@
> // to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0.
> #![cfg_attr(not(CONFIG_RUSTC_HAS_SPAN_FILE), feature(proc_macro_span))]
>
> -#[macro_use]
> -mod quote;
> mod concat_idents;
> mod export;
> mod fmt;
> @@ -132,7 +130,7 @@
> /// the kernel module.
> #[proc_macro]
> pub fn module(ts: TokenStream) -> TokenStream {
> - module::module(ts)
> + module::module(ts.into()).into()
> }
>
> /// Declares or implements a vtable trait.
> @@ -207,7 +205,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
> /// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html
> #[proc_macro_attribute]
> pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
> - vtable::vtable(attr, ts)
> + vtable::vtable(attr.into(), ts.into()).into()
> }
>
> /// Export a function so that C code can call it via a header file.
> @@ -230,7 +228,7 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
> /// automatically exported with `EXPORT_SYMBOL_GPL`.
> #[proc_macro_attribute]
> pub fn export(attr: TokenStream, ts: TokenStream) -> TokenStream {
> - export::export(attr, ts)
> + export::export(attr.into(), ts.into()).into()
> }
>
> /// Like [`core::format_args!`], but automatically wraps arguments in [`kernel::fmt::Adapter`].
> @@ -248,7 +246,7 @@ pub fn export(attr: TokenStream, ts: TokenStream) -> TokenStream {
> /// [`pr_info!`]: ../kernel/macro.pr_info.html
> #[proc_macro]
> pub fn fmt(input: TokenStream) -> TokenStream {
> - fmt::fmt(input)
> + fmt::fmt(input.into()).into()
> }
>
> /// Concatenate two identifiers.
> @@ -306,7 +304,7 @@ pub fn fmt(input: TokenStream) -> TokenStream {
> /// ```
> #[proc_macro]
> pub fn concat_idents(ts: TokenStream) -> TokenStream {
> - concat_idents::concat_idents(ts)
> + concat_idents::concat_idents(ts.into()).into()
> }
>
> /// Paste identifiers together.
> @@ -444,9 +442,12 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
> /// [`paste`]: https://docs.rs/paste/
> #[proc_macro]
> pub fn paste(input: TokenStream) -> TokenStream {
> - let mut tokens = input.into_iter().collect();
> + let mut tokens = proc_macro2::TokenStream::from(input).into_iter().collect();
> paste::expand(&mut tokens);
> - tokens.into_iter().collect()
> + tokens
> + .into_iter()
> + .collect::<proc_macro2::TokenStream>()
> + .into()
> }
>
> /// Registers a KUnit test suite and its test cases using a user-space like syntax.
> @@ -473,5 +474,5 @@ pub fn paste(input: TokenStream) -> TokenStream {
> /// ```
> #[proc_macro_attribute]
> pub fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
> - kunit::kunit_tests(attr, ts)
> + kunit::kunit_tests(attr.into(), ts.into()).into()
> }
> diff --git a/rust/macros/module.rs b/rust/macros/module.rs
> index 80cb9b16f5aaf..b855a2b586e18 100644
> --- a/rust/macros/module.rs
> +++ b/rust/macros/module.rs
> @@ -1,9 +1,11 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -use crate::helpers::*;
> -use proc_macro::{token_stream, Delimiter, Literal, TokenStream, TokenTree};
> use std::fmt::Write;
>
> +use proc_macro2::{token_stream, Delimiter, Literal, TokenStream, TokenTree};
> +
> +use crate::helpers::*;
> +
> fn expect_string_array(it: &mut token_stream::IntoIter) -> Vec<String> {
> let group = expect_group(it);
> assert_eq!(group.delimiter(), Delimiter::Bracket);
> diff --git a/rust/macros/paste.rs b/rust/macros/paste.rs
> index cce712d19855b..2181e312a7d32 100644
> --- a/rust/macros/paste.rs
> +++ b/rust/macros/paste.rs
> @@ -1,6 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
> +use proc_macro2::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
>
> fn concat_helper(tokens: &[TokenTree]) -> Vec<(String, Span)> {
> let mut tokens = tokens.iter();
> diff --git a/rust/macros/quote.rs b/rust/macros/quote.rs
> deleted file mode 100644
> index ddfc21577539c..0000000000000
> --- a/rust/macros/quote.rs
> +++ /dev/null
> @@ -1,182 +0,0 @@
> -// SPDX-License-Identifier: Apache-2.0 OR MIT
> -
> -use proc_macro::{TokenStream, TokenTree};
> -
> -pub(crate) trait ToTokens {
> - fn to_tokens(&self, tokens: &mut TokenStream);
> -}
> -
> -impl<T: ToTokens> ToTokens for Option<T> {
> - fn to_tokens(&self, tokens: &mut TokenStream) {
> - if let Some(v) = self {
> - v.to_tokens(tokens);
> - }
> - }
> -}
> -
> -impl ToTokens for proc_macro::Group {
> - fn to_tokens(&self, tokens: &mut TokenStream) {
> - tokens.extend([TokenTree::from(self.clone())]);
> - }
> -}
> -
> -impl ToTokens for proc_macro::Ident {
> - fn to_tokens(&self, tokens: &mut TokenStream) {
> - tokens.extend([TokenTree::from(self.clone())]);
> - }
> -}
> -
> -impl ToTokens for TokenTree {
> - fn to_tokens(&self, tokens: &mut TokenStream) {
> - tokens.extend([self.clone()]);
> - }
> -}
> -
> -impl ToTokens for TokenStream {
> - fn to_tokens(&self, tokens: &mut TokenStream) {
> - tokens.extend(self.clone());
> - }
> -}
> -
> -/// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
> -/// the given span.
> -///
> -/// This is a similar to the
> -/// [`quote_spanned!`](https://docs.rs/quote/latest/quote/macro.quote_spanned.html) macro from the
> -/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
> -macro_rules! quote_spanned {
> - ($span:expr => $($tt:tt)*) => {{
> - let mut tokens = ::proc_macro::TokenStream::new();
> - {
> - #[allow(unused_variables)]
> - let span = $span;
> - quote_spanned!(@proc tokens span $($tt)*);
> - }
> - tokens
> - }};
> - (@proc $v:ident $span:ident) => {};
> - (@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
> - $crate::quote::ToTokens::to_tokens(&$id, &mut $v);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
> - for token in $id {
> - $crate::quote::ToTokens::to_tokens(&token, &mut $v);
> - }
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
> - #[allow(unused_mut)]
> - let mut tokens = ::proc_macro::TokenStream::new();
> - quote_spanned!(@proc tokens $span $($inner)*);
> - $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
> - ::proc_macro::Delimiter::Parenthesis,
> - tokens,
> - ))]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
> - let mut tokens = ::proc_macro::TokenStream::new();
> - quote_spanned!(@proc tokens $span $($inner)*);
> - $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
> - ::proc_macro::Delimiter::Bracket,
> - tokens,
> - ))]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
> - let mut tokens = ::proc_macro::TokenStream::new();
> - quote_spanned!(@proc tokens $span $($inner)*);
> - $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
> - ::proc_macro::Delimiter::Brace,
> - tokens,
> - ))]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident :: $($tt:tt)*) => {
> - $v.extend([::proc_macro::Spacing::Joint, ::proc_macro::Spacing::Alone].map(|spacing| {
> - ::proc_macro::TokenTree::Punct(::proc_macro::Punct::new(':', spacing))
> - }));
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident : $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident , $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident @ $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident ! $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident ; $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident + $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident = $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident # $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident & $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Punct(
> - ::proc_macro::Punct::new('&', ::proc_macro::Spacing::Alone),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident _ $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Ident(
> - ::proc_macro::Ident::new("_", $span),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> - (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
> - $v.extend([::proc_macro::TokenTree::Ident(
> - ::proc_macro::Ident::new(stringify!($id), $span),
> - )]);
> - quote_spanned!(@proc $v $span $($tt)*);
> - };
> -}
> -
> -/// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
> -/// mixed site span ([`Span::mixed_site()`]).
> -///
> -/// This is a similar to the [`quote!`](https://docs.rs/quote/latest/quote/macro.quote.html) macro
> -/// from the `quote` crate but provides only just enough functionality needed by the current
> -/// `macros` crate.
> -///
> -/// [`Span::mixed_site()`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.mixed_site
> -macro_rules! quote {
> - ($($tt:tt)*) => {
> - quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
> - }
> -}
> diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
> index ee06044fcd4f3..a67d1cc81a2d3 100644
> --- a/rust/macros/vtable.rs
> +++ b/rust/macros/vtable.rs
> @@ -1,9 +1,10 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
> use std::collections::HashSet;
> use std::fmt::Write;
>
> +use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
> +
> pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
> let mut tokens: Vec<_> = ts.into_iter().collect();
>
> @@ -31,7 +32,7 @@ pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
> let mut consts = HashSet::new();
> while let Some(token) = body_it.next() {
> match token {
> - TokenTree::Ident(ident) if ident.to_string() == "fn" => {
> + TokenTree::Ident(ident) if ident == "fn" => {
> let fn_name = match body_it.next() {
> Some(TokenTree::Ident(ident)) => ident.to_string(),
> // Possibly we've encountered a fn pointer type instead.
> @@ -39,7 +40,7 @@ pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
> };
> functions.push(fn_name);
> }
> - TokenTree::Ident(ident) if ident.to_string() == "const" => {
> + TokenTree::Ident(ident) if ident == "const" => {
> let const_name = match body_it.next() {
> Some(TokenTree::Ident(ident)) => ident.to_string(),
> // Possibly we've encountered an inline const block instead.
> --
> 2.51.2
>
Download attachment "smime.p7s" of type "application/pkcs7-signature" (5281 bytes)
Powered by blists - more mailing lists