Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170// SPDX-License-Identifier: GPL-2.0
use std::{ collections::HashSet, iter::Extend, //};
use proc_macro2::{ Ident, TokenStream, //};use quote::{ quote, ToTokens, //};use syn::{ parse_quote, Error, ImplItem, Item, ItemImpl, ItemTrait, Result, TraitItem, //};
fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> { let mut gen_items = Vec::new();
gen_items.push(parse_quote! { /// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable) /// attribute when implementing this trait. const USE_VTABLE_ATTR: (); });
// Add `type OwnerModule: ModuleMetadata` as a required associated type if // the trait does not already define it. if !item .items .iter() .any(|i| matches!(i, TraitItem::Type(t) if t.ident == "OwnerModule")) { gen_items.push(parse_quote! { /// The module implementing this vtable trait. /// /// Automatically set to `crate::LocalModule` by the `#[vtable]` /// impl macro. type OwnerModule: ::kernel::ModuleMetadata; }); }
for item in &mut item.items { if let TraitItem::Fn(fn_item) = item { let name = &fn_item.sig.ident; let gen_const_name = Ident::new( &format!("HAS_{}", name.to_string().to_uppercase()), name.span(), );
if fn_item .attrs .extract_if(.., |attr| attr.path().is_ident("optional")) .count() != 0 { if let Some(default) = &fn_item.default { Err(Error::new_spanned( default, "`#[optional]` methods must not have a default implementation", ))?; }
// Optional methods in Rust need a default implementation. Inject one that fails // the build at compile time if not overridden. fn_item.default = Some(parse_quote!({ ::kernel::build_assert::build_error!( "This function must not be called, see the `#[vtable]` documentation." ); })); // Ensure that the function is never code generated unless used. fn_item.attrs.push(parse_quote!(#[inline])); }
// We don't know on the implementation-site whether a method is required or provided // so we have to generate a const for all methods. // However, hide it for required methods as it will always be true. let doc = if fn_item.default.is_some() { let comment = format!("Indicates if the `{name}` method is overridden by the implementor."); quote!(#[doc = #comment]) } else { quote!(#[doc(hidden)]) }; let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs); gen_items.push(parse_quote! { #(#cfg_attrs)* #doc const #gen_const_name: bool = false; }); } }
item.items.extend(gen_items); Ok(item)}
fn handle_impl(mut item: ItemImpl) -> Result<ItemImpl> { let mut gen_items = Vec::new(); let mut defined_items = HashSet::new();
// Iterate over all user-defined items to gather any possible explicit overrides. for item in &item.items { match item { ImplItem::Const(const_item) => { defined_items.insert(const_item.ident.clone()); } ImplItem::Type(type_item) => { defined_items.insert(type_item.ident.clone()); } _ => {} } }
gen_items.push(parse_quote! { const USE_VTABLE_ATTR: () = (); });
// Auto-insert `type OwnerModule = 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_items.contains(&parse_quote!(OwnerModule)) { gen_items.push(parse_quote! { type OwnerModule = crate::LocalModule; }); }
for item in &item.items { if let ImplItem::Fn(fn_item) = item { let name = &fn_item.sig.ident; let gen_const_name = Ident::new( &format!("HAS_{}", name.to_string().to_uppercase()), name.span(), ); // Skip if it's declared already -- this allows user override. if defined_items.contains(&gen_const_name) { continue; } let cfg_attrs = crate::helpers::gather_cfg_attrs(&fn_item.attrs); gen_items.push(parse_quote! { #(#cfg_attrs)* const #gen_const_name: bool = true; }); } }
item.items.extend(gen_items); Ok(item)}
pub(crate) fn vtable(input: Item) -> Result<TokenStream> { match input { Item::Trait(item) => Ok(handle_trait(item)?.into_token_stream()), Item::Impl(item) => Ok(handle_impl(item)?.into_token_stream()), _ => Err(Error::new_spanned( input, "`#[vtable]` attribute should only be applied to trait or impl block", ))?, }}