[PATCH v2 2/7] rust: macros: auto-insert ThisModule in #[vtable]

0 views
Skip to first unread message

Alvin Sun

unread,
May 21, 2026, 3:53:00 AM (4 days ago) May 21
to Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman, Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida, Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao, Jens Axboe, rust-fo...@vger.kernel.org, linux-...@vger.kernel.org, drive...@lists.linux.dev, dri-...@lists.freedesktop.org, nova...@lists.linux.dev, linux-k...@vger.kernel.org, kuni...@googlegroups.com, linux...@vger.kernel.org, Alvin Sun
Auto-add `type ThisModule: ::kernel::ModuleMetadata;` as a required
associated type on the trait side if not already defined, and
auto-insert `type ThisModule = crate::LocalModule;` on the impl side
if not explicitly provided, eliminating the need to manually declare
and implement `ThisModule` in every vtable trait and impl.

Signed-off-by: Alvin Sun <alvi...@linux.dev>
---
rust/macros/lib.rs | 6 ++++++
rust/macros/vtable.rs | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2cfd59e0f9e7c..d35e45ea745c0 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -176,6 +176,12 @@ pub fn module(input: TokenStream) -> TokenStream {
///
/// This macro should not be used when all functions are required.
///
+/// Additionally, this macro automatically handles the `ThisModule`
+/// associated type: on the trait side, `type ThisModule: ModuleMetadata;`
+/// is added as a required associated type if not already defined; on the
+/// impl side, `type ThisModule = LocalModule;` is automatically inserted
+/// if not explicitly defined.
+///
/// # Examples
///
/// ```
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
index c6510b0c4ea1d..d3d0e9cbd7172 100644
--- a/rust/macros/vtable.rs
+++ b/rust/macros/vtable.rs
@@ -23,6 +23,7 @@

fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
let mut gen_items = Vec::new();
+ let mut has_this_module = false;

gen_items.push(parse_quote! {
/// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable)
@@ -30,6 +31,28 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
const USE_VTABLE_ATTR: ();
});

+ // Detect existing type ThisModule so we don't add a duplicate.
+ for i in &item.items {
+ if let TraitItem::Type(type_item) = i {
+ if type_item.ident == "ThisModule" {
+ has_this_module = true;
+ }
+ }
+ }
+
+ // Add `type ThisModule: ModuleMetadata` as a required associated type if
+ // the trait does not already define it. No default is used because
+ // `associated_type_defaults` is unstable (issue #29661).
+ if !has_this_module {
+ gen_items.push(parse_quote! {
+ /// The module implementing this vtable trait.
+ ///
+ /// Automatically set to `crate::LocalModule` by the `#[vtable]`
+ /// impl macro.
+ type ThisModule: ::kernel::ModuleMetadata;
+ });
+ }
+
for item in &item.items {
if let TraitItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;
@@ -58,18 +81,31 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> {
let mut gen_items = Vec::new();
let mut defined_consts = HashSet::new();
+ let mut defined_types = HashSet::new();

- // Iterate over all user-defined constants to gather any possible explicit overrides.
+ // Iterate over all user-defined constants and types to gather any possible explicit overrides.
for item in &item.items {
if let ImplItem::Const(const_item) = item {
defined_consts.insert(const_item.ident.clone());
}
+ if let ImplItem::Type(type_item) = item {
+ defined_types.insert(type_item.ident.clone());
+ }
}

gen_items.push(parse_quote! {
const USE_VTABLE_ATTR: () = ();
});

+ // Auto-insert `type ThisModule = crate::LocalModule` if not explicitly defined.
+ // `crate::LocalModule` resolves to the real module type (via `module!`) or a
+ // dummy fallback in non-module contexts (e.g., doctests).
+ if !defined_types.contains(&parse_quote!(ThisModule)) {
+ gen_items.push(parse_quote! {
+ type ThisModule = crate::LocalModule;
+ });
+ }
+
for item in &item.items {
if let ImplItem::Fn(fn_item) = item {
let name = &fn_item.sig.ident;

--
2.43.0


Reply all
Reply to author
Forward
0 new messages