On Thu Jul 3, 2025 at 3:55 PM CEST, Tamir Duberstein wrote:
On Thu, Jul 3, 2025 at 5:32 AM Benno Lossin lossin@kernel.org wrote:
On Tue Jul 1, 2025 at 6:49 PM CEST, Tamir Duberstein wrote:
Introduce a `fmt!` macro which wraps all arguments in `kernel::fmt::Adapter` and a `kernel::fmt::Display` trait. This enables formatting of foreign types (like `core::ffi::CStr`) that do not implement `core::fmt::Display` due to concerns around lossy conversions which do not apply in the kernel.
Replace all direct calls to `format_args!` with `fmt!`.
Replace all implementations of `core::fmt::Display` with implementations of `kernel::fmt::Display`.
Suggested-by: Alice Ryhl aliceryhl@google.com Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Cu... Acked-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Reviewed-by: Alice Ryhl aliceryhl@google.com Signed-off-by: Tamir Duberstein tamird@gmail.com
drivers/block/rnull.rs | 2 +- drivers/gpu/nova-core/gpu.rs | 4 +- rust/kernel/block/mq.rs | 2 +- rust/kernel/device.rs | 2 +- rust/kernel/fmt.rs | 89 +++++++++++++++++++++++++++++++++++++++ rust/kernel/kunit.rs | 6 +-- rust/kernel/lib.rs | 1 + rust/kernel/prelude.rs | 3 +- rust/kernel/print.rs | 4 +- rust/kernel/seq_file.rs | 2 +- rust/kernel/str.rs | 22 ++++------ rust/macros/fmt.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++ rust/macros/lib.rs | 19 +++++++++ rust/macros/quote.rs | 7 ++++ scripts/rustdoc_test_gen.rs | 2 +- 15 files changed, 236 insertions(+), 28 deletions(-)
This would be a lot easier to review if he proc-macro and the call replacement were different patches.
Also the `kernel/fmt.rs` file should be a different commit.
Can you help me understand why? The changes you ask to be separated would all be in different files, so why would separate commits make it easier to review?
It takes less time to go through the entire patch and give a RB. I can take smaller time chunks and don't have to get back into the entire context of the patch when I don't have 30-60min available.
In this patch the biggest problem is the rename & addition of new things, maybe just adding 200 lines in those files could be okay to go together, see below for more.
I prefer to keep things in one commit because the changes are highly interdependent. The proc macro doesn't make sense without kernel/fmt.rs and kernel/fmt.rs is useless without the proc macro.
I think that `Adapter`, the custom `Display` and their impl blocks don't need to be in the same commit as the proc-macro. They are related, but maybe someone is not well-versed in proc-macros and thus doesn't want to review that part.
diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs new file mode 100644 index 000000000000..348d16987de6 --- /dev/null +++ b/rust/kernel/fmt.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0
+//! Formatting utilities.
+use core::fmt;
I think we should pub export all types that we are still using from `core::fmt`. For example `Result`, `Formatter`, `Debug` etc.
That way I can still use the same pattern of importing `fmt` and then writing
impl fmt::Display for MyType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {} }
Great idea, done for the next spin. It would be nice to be able to lint against references to `core::fmt` outside of kernel/fmt.rs.
I think there was something in clippy that can do that globally and we could allow that in this file?
+/// Internal adapter used to route allow implementations of formatting traits for foreign types. +/// +/// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly. +/// +/// [`fmt!`]: crate::prelude::fmt! +#[doc(hidden)] +pub struct Adapter<T>(pub T);
+macro_rules! impl_fmt_adapter_forward {
- ($($trait:ident),* $(,)?) => {
$(
impl<T: fmt::$trait> fmt::$trait for Adapter<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(t) = self;
fmt::$trait::fmt(t, f)
}
}
)*
- };
+}
+impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, Pointer, LowerExp, UpperExp);
+/// A copy of [`fmt::Display`] that allows us to implement it for foreign types. +/// +/// Types should implement this trait rather than [`fmt::Display`]. Together with the [`Adapter`] +/// type and [`fmt!`] macro, it allows for formatting foreign types (e.g. types from core) which do +/// not implement [`fmt::Display`] directly. +/// +/// [`fmt!`]: crate::prelude::fmt! +pub trait Display {
- /// Same as [`fmt::Display::fmt`].
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
+}
+impl<T: ?Sized + Display> Display for &T {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(*self, f)
- }
+}
+impl<T: ?Sized + Display> fmt::Display for Adapter<&T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(t) = self;
Display::fmt(t, f)
Why not `Display::fmt(&self.0, f)`?
I like destructuring because it shows me that there's only one field. With `self.0` I don't see that.
And what is the benefit here?
- let mut args = TokenStream::from_iter(first_opt);
- {
let mut flush = |args: &mut TokenStream, current: &mut TokenStream| {
You don't need to pass `args` as a closure argument, since you always call it with `&mut args`.
This doesn't work because of the borrow checker. If I wrote what you suggest, then `args` is mutably borrowed by the closure, which prohibits the mutable borrow needed for the .extend() call here:
Ahh right... Well then it's fine.
--- Cheers, Benno