Skip to content

Commit 88c2e11

Browse files
BennoLossinojeda
authored andcommitted
rust: macros: improve #[vtable] documentation
Traits marked with `#[vtable]` need to provide default implementations for optional functions. The C side represents these with `NULL` in the vtable, so the default functions are never actually called. We do not want to replicate the default behavior from C in Rust, because that is not maintainable. Therefore we should use `build_error` in those default implementations. The error message for that is provided at `kernel::error::VTABLE_DEFAULT_ERROR`. Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Finn Behrens <me@kloenk.dev> Link: https://lore.kernel.org/r/20231026201855.1497680-1-benno.lossin@proton.me [ Wrapped paragraph to 80 as requested and capitalized sentence. ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 2dc318e commit 88c2e11

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

rust/kernel/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,7 @@ where
335335
Err(e) => T::from(e.to_errno() as i16),
336336
}
337337
}
338+
339+
/// Error message for calling a default function of a [`#[vtable]`](macros::vtable) trait.
340+
pub const VTABLE_DEFAULT_ERROR: &str =
341+
"This function must not be called, see the #[vtable] documentation.";

rust/macros/lib.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,49 @@ pub fn module(ts: TokenStream) -> TokenStream {
8787
/// implementation could just return `Error::EINVAL`); Linux typically use C
8888
/// `NULL` pointers to represent these functions.
8989
///
90-
/// This attribute is intended to close the gap. Traits can be declared and
91-
/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
92-
/// will be generated for each method in the trait, indicating if the implementor
93-
/// has overridden a method.
90+
/// This attribute closes that gap. A trait can be annotated with the
91+
/// `#[vtable]` attribute. Implementers of the trait will then also have to
92+
/// annotate the trait with `#[vtable]`. This attribute generates a `HAS_*`
93+
/// associated constant bool for each method in the trait that is set to true if
94+
/// the implementer has overridden the associated method.
95+
///
96+
/// For a trait method to be optional, it must have a default implementation.
97+
/// This is also the case for traits annotated with `#[vtable]`, but in this
98+
/// case the default implementation will never be executed. The reason for this
99+
/// is that the functions will be called through function pointers installed in
100+
/// C side vtables. When an optional method is not implemented on a `#[vtable]`
101+
/// trait, a NULL entry is installed in the vtable. Thus the default
102+
/// implementation is never called. Since these traits are not designed to be
103+
/// used on the Rust side, it should not be possible to call the default
104+
/// implementation. This is done to ensure that we call the vtable methods
105+
/// through the C vtable, and not through the Rust vtable. Therefore, the
106+
/// default implementation should call `kernel::build_error`, which prevents
107+
/// calls to this function at compile time:
108+
///
109+
/// ```compile_fail
110+
/// # use kernel::error::VTABLE_DEFAULT_ERROR;
111+
/// kernel::build_error(VTABLE_DEFAULT_ERROR)
112+
/// ```
113+
///
114+
/// Note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`].
94115
///
95-
/// This attribute is not needed if all methods are required.
116+
/// This macro should not be used when all functions are required.
96117
///
97118
/// # Examples
98119
///
99120
/// ```ignore
121+
/// use kernel::error::VTABLE_DEFAULT_ERROR;
100122
/// use kernel::prelude::*;
101123
///
102124
/// // Declares a `#[vtable]` trait
103125
/// #[vtable]
104126
/// pub trait Operations: Send + Sync + Sized {
105127
/// fn foo(&self) -> Result<()> {
106-
/// Err(EINVAL)
128+
/// kernel::build_error(VTABLE_DEFAULT_ERROR)
107129
/// }
108130
///
109131
/// fn bar(&self) -> Result<()> {
110-
/// Err(EINVAL)
132+
/// kernel::build_error(VTABLE_DEFAULT_ERROR)
111133
/// }
112134
/// }
113135
///
@@ -125,6 +147,8 @@ pub fn module(ts: TokenStream) -> TokenStream {
125147
/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
126148
/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
127149
/// ```
150+
///
151+
/// [`kernel::error::VTABLE_DEFAULT_ERROR`]: ../kernel/error/constant.VTABLE_DEFAULT_ERROR.html
128152
#[proc_macro_attribute]
129153
pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
130154
vtable::vtable(attr, ts)

0 commit comments

Comments
 (0)