* [PATCH 1/3] rust: macros: vtable: hide generated `HAS_` constants for required methods
2026-08-11 13:55 [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
@ 2026-08-11 13:55 ` Gary Guo
2026-08-11 13:55 ` [PATCH 2/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Gary Guo @ 2026-08-11 13:55 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Arnd Bergmann, Greg Kroah-Hartman
Cc: rust-for-linux, linux-kernel, Gary Guo
These constants have to be generated as the implementation-site `#[vtable]`
invocation has no way of knowing whether the methods are required or
provided-but-overriden. However, these constants will have a fixed value so
shouldn't be used. Thus, hide them.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/macros/vtable.rs | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
index c6510b0c4ea1..e28976a5919f 100644
--- a/rust/macros/vtable.rs
+++ b/rust/macros/vtable.rs
@@ -9,7 +9,10 @@
Ident,
TokenStream, //
};
-use quote::ToTokens;
+use quote::{
+ quote,
+ ToTokens, //
+};
use syn::{
parse_quote,
Error,
@@ -40,12 +43,18 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
// 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);
- let comment =
- format!("Indicates if the `{name}` method is overridden by the implementor.");
gen_items.push(parse_quote! {
#(#cfg_attrs)*
- #[doc = #comment]
+ #doc
const #gen_const_name: bool = false;
});
}
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 2/3] rust: macros: vtable: add `#[optional]` attribute
2026-08-11 13:55 [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
2026-08-11 13:55 ` [PATCH 1/3] rust: macros: vtable: hide generated `HAS_` constants for required methods Gary Guo
@ 2026-08-11 13:55 ` Gary Guo
2026-08-11 13:55 ` [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro Gary Guo
2026-10-02 19:10 ` [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Miguel Ojeda
3 siblings, 0 replies; 8+ messages in thread
From: Gary Guo @ 2026-08-11 13:55 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Arnd Bergmann, Greg Kroah-Hartman
Cc: rust-for-linux, linux-kernel, Gary Guo
For most users of the `#[vtable]` macro, the optional methods do not have a
Rust-side default implementation; a `NULL` pointer is inserted to the
vtable and the C subsystem does thing differently when it sees `NULL`.
Streamline this use case by providing a `#[optional]` attribute that does
what the `build_error!(VTABLE_DEFAULT_ERROR)` boilerplate does.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/macros/lib.rs | 39 +++++++++++----------------------------
rust/macros/vtable.rs | 26 +++++++++++++++++++++++++-
2 files changed, 36 insertions(+), 29 deletions(-)
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 0514fc7c0a55..de55dee4d866 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -156,44 +156,29 @@ pub fn module(input: TokenStream) -> TokenStream {
/// associated constant bool for each method in the trait that is set to true if
/// the implementer has overridden the associated method.
///
-/// For a trait method to be optional, it must have a default implementation.
-/// This is also the case for traits annotated with `#[vtable]`, but in this
-/// case the default implementation will never be executed. The reason for this
-/// is that the functions will be called through function pointers installed in
-/// C side vtables. When an optional method is not implemented on a `#[vtable]`
-/// trait, a `NULL` entry is installed in the vtable. Thus the default
-/// implementation is never called. Since these traits are not designed to be
-/// used on the Rust side, it should not be possible to call the default
-/// implementation. This is done to ensure that we call the vtable methods
-/// through the C vtable, and not through the Rust vtable. Therefore, the
-/// default implementation should call `build_error!`, which prevents
-/// calls to this function at compile time:
-///
-/// ```compile_fail
-/// # // Intentionally missing `use`s to simplify `rusttest`.
-/// build_error!(VTABLE_DEFAULT_ERROR)
-/// ```
-///
-/// Note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`].
+/// For a trait method to be optional for normal traits, it must have a default implementation.
+/// However, for many users of `#[vtable]`, the functions will be called through function pointers
+/// installed in C side vtables. When an optional method is not implemented on a `#[vtable]` trait,
+/// a `NULL` entry is installed in the vtable; thus the default implementation is never called. If
+/// this is the case, `#[optional]` can be applied on the optional method. Methods annotated as such
+/// do not need to be implemented nor need a default implementation. Calling these methods on types
+/// that do not implement them will fail to build using the `build_error!` mechanism.
///
/// This macro should not be used when all functions are required.
///
/// # Examples
///
/// ```
-/// use kernel::error::VTABLE_DEFAULT_ERROR;
/// use kernel::prelude::*;
///
/// // Declares a `#[vtable]` trait
/// #[vtable]
/// pub trait Operations: Send + Sync + Sized {
-/// fn foo(&self) -> Result<()> {
-/// build_error!(VTABLE_DEFAULT_ERROR)
-/// }
+/// #[optional]
+/// fn foo(&self) -> Result<()>;
///
-/// fn bar(&self) -> Result<()> {
-/// build_error!(VTABLE_DEFAULT_ERROR)
-/// }
+/// #[optional]
+/// fn bar(&self) -> Result<()>;
/// }
///
/// struct Foo;
@@ -210,8 +195,6 @@ pub fn module(input: TokenStream) -> TokenStream {
/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
/// ```
-///
-/// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html
#[proc_macro_attribute]
pub fn vtable(attr: TokenStream, input: TokenStream) -> TokenStream {
parse_macro_input!(attr as syn::parse::Nothing);
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
index e28976a5919f..54bd32e82a9c 100644
--- a/rust/macros/vtable.rs
+++ b/rust/macros/vtable.rs
@@ -33,7 +33,7 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
const USE_VTABLE_ATTR: ();
});
- for item in &item.items {
+ 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(
@@ -41,6 +41,30 @@ fn handle_trait(mut item: ItemTrait) -> Result<ItemTrait> {
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 default implementation",
+ ))?;
+ }
+
+ // Optional methods in Rust need a default implementation. Inject one that fails
+ // the build in 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.
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro
2026-08-11 13:55 [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
2026-08-11 13:55 ` [PATCH 1/3] rust: macros: vtable: hide generated `HAS_` constants for required methods Gary Guo
2026-08-11 13:55 ` [PATCH 2/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
@ 2026-08-11 13:55 ` Gary Guo
2026-10-02 13:17 ` Miguel Ojeda
2026-10-02 19:10 ` [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Miguel Ojeda
3 siblings, 1 reply; 8+ messages in thread
From: Gary Guo @ 2026-08-11 13:55 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Arnd Bergmann, Greg Kroah-Hartman
Cc: rust-for-linux, linux-kernel, Gary Guo
Replace the `build_error!(VTABLE_DEFAULT_ERROR)` boilerplate with the
`#[optional]` attribute.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/miscdevice.rs | 35 +++++++++++++----------------------
1 file changed, 13 insertions(+), 22 deletions(-)
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index 3abef1b8543d..76cb45e2a5ee 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -11,10 +11,7 @@
use crate::{
bindings,
device::Device,
- error::{
- to_result,
- VTABLE_DEFAULT_ERROR, //
- },
+ error::to_result,
fs::{
File,
Kiocb, //
@@ -144,37 +141,33 @@ fn release(device: Self::Ptr, _file: &File) {
/// the VMA initialization by calling methods of `vma`. If the function does not return an
/// error, the kernel will complete initialization of the VMA according to the properties of
/// `vma`.
+ #[optional]
fn mmap(
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_vma: &VmaNew,
- ) -> Result {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ ) -> Result;
/// Read from this miscdevice.
- fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterDest<'_>) -> Result<usize> {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ #[optional]
+ fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterDest<'_>) -> Result<usize>;
/// Write to this miscdevice.
- fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterSource<'_>) -> Result<usize> {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ #[optional]
+ fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterSource<'_>) -> Result<usize>;
/// Handler for ioctls.
///
/// The `cmd` argument is usually manipulated using the utilities in [`kernel::ioctl`].
///
/// [`kernel::ioctl`]: mod@crate::ioctl
+ #[optional]
fn ioctl(
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_cmd: u32,
_arg: usize,
- ) -> Result<isize> {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ ) -> Result<isize>;
/// Handler for ioctls.
///
@@ -184,23 +177,21 @@ fn ioctl(
/// that have different layout on 32-bit and 64-bit userspace. If no implementation is
/// provided, then `compat_ptr_ioctl` will be used instead.
#[cfg(CONFIG_COMPAT)]
+ #[optional]
fn compat_ioctl(
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_cmd: u32,
_arg: usize,
- ) -> Result<isize> {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ ) -> Result<isize>;
/// Show info for this fd.
+ #[optional]
fn show_fdinfo(
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
_m: &SeqFile,
_file: &File,
- ) {
- build_error!(VTABLE_DEFAULT_ERROR)
- }
+ );
}
/// A vtable for the file operations of a Rust miscdevice.
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro
2026-08-11 13:55 ` [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro Gary Guo
@ 2026-10-02 13:17 ` Miguel Ojeda
2026-10-02 13:55 ` Greg Kroah-Hartman
0 siblings, 1 reply; 8+ messages in thread
From: Miguel Ojeda @ 2026-10-02 13:17 UTC (permalink / raw)
To: Gary Guo, Arnd Bergmann, Greg Kroah-Hartman
Cc: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, rust-for-linux, linux-kernel
On Tue, Aug 11, 2026 at 3:56 PM Gary Guo <gary@garyguo.net> wrote:
>
> Replace the `build_error!(VTABLE_DEFAULT_ERROR)` boilerplate with the
> `#[optional]` attribute.
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
Arnd, Greg: may I get a quick Acked-by on this patch?
It is a change that simplifies boilerplate -- no "real" change for
you; miscdevice is just the example for the series.
Thanks!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro
2026-10-02 13:17 ` Miguel Ojeda
@ 2026-10-02 13:55 ` Greg Kroah-Hartman
0 siblings, 0 replies; 8+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-02 13:55 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Gary Guo, Arnd Bergmann, Miguel Ojeda, Boqun Feng,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel
On Fri, Oct 02, 2026 at 03:17:13PM +0200, Miguel Ojeda wrote:
> On Tue, Aug 11, 2026 at 3:56 PM Gary Guo <gary@garyguo.net> wrote:
> >
> > Replace the `build_error!(VTABLE_DEFAULT_ERROR)` boilerplate with the
> > `#[optional]` attribute.
> >
> > Signed-off-by: Gary Guo <gary@garyguo.net>
>
> Arnd, Greg: may I get a quick Acked-by on this patch?
>
> It is a change that simplifies boilerplate -- no "real" change for
> you; miscdevice is just the example for the series.
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute
2026-08-11 13:55 [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Gary Guo
` (2 preceding siblings ...)
2026-08-11 13:55 ` [PATCH 3/3] rust: misc: use `#[optional]` attribute of `#[vtable]` macro Gary Guo
@ 2026-10-02 19:10 ` Miguel Ojeda
2026-10-02 20:37 ` Gary Guo
3 siblings, 1 reply; 8+ messages in thread
From: Miguel Ojeda @ 2026-10-02 19:10 UTC (permalink / raw)
To: Gary Guo
Cc: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Arnd Bergmann, Greg Kroah-Hartman,
rust-for-linux, linux-kernel
On Tue, Aug 11, 2026 at 3:56 PM Gary Guo <gary@garyguo.net> wrote:
>
> Currently there are a lot of boilerplate with the
> `build_error!(VTABLE_DEFAULT_ERROR)` because Rust want a default
> implementation but we insert `NULL` into C vtable and never call the
> Rust-side method if it is not overridden.
>
> Add an `#[optional]` attribute that injects the same default
> implementation to avoid duplicating this everywhere. As an example, the
> misc device vtable trait is converted.
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
Applied to `rust-next` -- thanks everyone!
[ Reworded for typo. - Miguel ]
[ Rewrapped docs. Reworded message, comment and error for typos. Rebased.
- Miguel ]
[ Reworded title for prefix. - Miguel ]
I was tempted to replace the hardcoded message with the
`VTABLE_DEFAULT_ERROR` constant, but I assume you did it so that we
can just remove the constant later when everyone is migrated.
By the way, did you consider allowing `unused_variables`? It could be
nice to not have to use `_` in the signatures.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute
2026-10-02 19:10 ` [PATCH 0/3] rust: macros: vtable: add `#[optional]` attribute Miguel Ojeda
@ 2026-10-02 20:37 ` Gary Guo
0 siblings, 0 replies; 8+ messages in thread
From: Gary Guo @ 2026-10-02 20:37 UTC (permalink / raw)
To: Miguel Ojeda, Gary Guo
Cc: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Arnd Bergmann, Greg Kroah-Hartman,
rust-for-linux, linux-kernel
On Fri Oct 2, 2026 at 8:10 PM BST, Miguel Ojeda wrote:
> On Tue, Aug 11, 2026 at 3:56 PM Gary Guo <gary@garyguo.net> wrote:
>>
>> Currently there are a lot of boilerplate with the
>> `build_error!(VTABLE_DEFAULT_ERROR)` because Rust want a default
>> implementation but we insert `NULL` into C vtable and never call the
>> Rust-side method if it is not overridden.
>>
>> Add an `#[optional]` attribute that injects the same default
>> implementation to avoid duplicating this everywhere. As an example, the
>> misc device vtable trait is converted.
>>
>> Signed-off-by: Gary Guo <gary@garyguo.net>
>
> Applied to `rust-next` -- thanks everyone!
>
> [ Reworded for typo. - Miguel ]
>
> [ Rewrapped docs. Reworded message, comment and error for typos. Rebased.
> - Miguel ]
>
> [ Reworded title for prefix. - Miguel ]
>
> I was tempted to replace the hardcoded message with the
> `VTABLE_DEFAULT_ERROR` constant, but I assume you did it so that we
> can just remove the constant later when everyone is migrated.
Correct.
>
> By the way, did you consider allowing `unused_variables`? It could be
> nice to not have to use `_` in the signatures.
I didn't because existing users are all _ prefixed already. But it does make
sense to add that to avoid having to prefix them, just like mandatory methods.
Best,
Gary
^ permalink raw reply [flat|nested] 8+ messages in thread