diff --git a/init/Kconfig b/init/Kconfig index 530a382ee0feb3..c4c1bfbbe38cd0 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1964,6 +1964,9 @@ config RUST If unsure, say N. +config RUST_COERCE_POINTEE + def_bool y if RUSTC_VERSION >= 108300 + config RUSTC_VERSION_TEXT string depends on RUST diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3d922920f5769a..17948930db7742 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -13,11 +13,13 @@ #![no_std] #![feature(arbitrary_self_types)] -#![feature(coerce_unsized)] -#![feature(derive_coerce_pointee, pin_coerce_unsized_trait)] +#![cfg_attr( + CONFIG_RUST_COERCE_POINTEE, + feature(derive_coerce_pointee, pin_coerce_unsized_trait) +)] +#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(coerce_unsized, unsize))] #![feature(inline_const)] #![feature(lint_reasons)] -#![feature(unsize)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 01760358dccbdf..39a7e9bc457dfa 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -160,7 +160,7 @@ pub use impl_list_arc_safe; /// /// [`List`]: crate::list::List #[repr(transparent)] -#[derive(CoercePointee)] +#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(CoercePointee))] pub struct ListArc where T: ListArcSafe + ?Sized, @@ -443,7 +443,28 @@ where } } +// This is to allow coercion from `ListArc` to `ListArc` if `T` can be converted to the +// dynamically-sized type (DST) `U`. +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +impl core::ops::CoerceUnsized> for ListArc +where + T: ListArcSafe + Unsize + ?Sized, + U: ListArcSafe + ?Sized, +{ +} + +// This is to allow `ListArc` to be dispatched on when `ListArc` can be coerced into +// `ListArc`. +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +impl core::ops::DispatchFromDyn> for ListArc +where + T: ListArcSafe + Unsize + ?Sized, + U: ListArcSafe + ?Sized, +{ +} + /// `ListArc` is well-behaved so that its dereferencing operation does not mutate. +#[cfg(CONFIG_RUST_COERCE_POINTEE)] unsafe impl, const ID: u64> PinCoerceUnsized for ListArc {} /// A utility for tracking whether a [`ListArc`] exists using an atomic. diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index ae49b611e81db1..9b6a759cee138c 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -23,10 +23,14 @@ use crate::{ try_init, types::{ForeignOwnable, Opaque}, }; +#[cfg(CONFIG_RUST_COERCE_POINTEE)] +use core::marker::CoercePointee; +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +use core::marker::Unsize; use core::{ alloc::Layout, fmt, - marker::{CoercePointee, PhantomData}, + marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, @@ -125,8 +129,8 @@ mod std_vendor; /// let coerced: Arc = obj; /// # Ok::<(), Error>(()) /// ``` -#[repr(transparent)] -#[derive(CoercePointee)] +#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, repr(transparent))] +#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(CoercePointee))] pub struct Arc { ptr: NonNull>, _p: PhantomData>, @@ -172,6 +176,15 @@ impl ArcInner { } } +// This is to allow coercion from `Arc` to `Arc` if `T` can be converted to the +// dynamically-sized type (DST) `U`. +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} + +// This is to allow `Arc` to be dispatched on when `Arc` can be coerced into `Arc`. +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} + // SAFETY: It is safe to send `Arc` to another thread when the underlying `T` is `Sync` because // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs // `T` to be `Send` because any thread that has an `Arc` may ultimately access `T` using a @@ -466,13 +479,21 @@ impl From>> for Arc { /// obj.as_arc_borrow().use_reference(); /// # Ok::<(), Error>(()) /// ``` -#[repr(transparent)] -#[derive(CoercePointee)] +#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, repr(transparent))] +#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(CoercePointee))] pub struct ArcBorrow<'a, T: ?Sized + 'a> { inner: NonNull>, _p: PhantomData<&'a ()>, } +// This is to allow `ArcBorrow` to be dispatched on when `ArcBorrow` can be coerced into +// `ArcBorrow`. +#[cfg(not(CONFIG_RUST_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> + for ArcBorrow<'_, T> +{ +} + impl Clone for ArcBorrow<'_, T> { fn clone(&self) -> Self { *self diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs index 7be389400b6f15..6d921111c4002f 100644 --- a/samples/rust/rust_print.rs +++ b/samples/rust/rust_print.rs @@ -34,14 +34,27 @@ fn arc_print() -> Result { // Uses `dbg` to print, will move `c` (for temporary debugging purposes). dbg!(c); - // `Arc` can be used to delegate dynamic dispatch and the following is an example. - // Both `i32` and `&str` implements `Display`. - // This enables us to express a unified behaviour, contract or protocol on both `i32` and `&str` - // in a single `Arc` type `Arc`. - let a_i32_display: Arc = Arc::new(42i32, GFP_KERNEL)?; - let a_str_display: Arc = a.clone(); - arc_dyn_print(&a_i32_display); - arc_dyn_print(&a_str_display); + #[cfg(CONFIG_RUST_COERCE_POINTEE)] + { + use core::fmt::Display; + fn arc_dyn_print(arc: &Arc) { + pr_info!("Arc says {arc}"); + } + // `Arc` can be used to delegate dynamic dispatch and the following is an example. + // Both `i32` and `&str` implements `Display`. + // This enables us to express a unified behaviour, contract or protocol on both `i32` and `&str` + // in a single `Arc` type `Arc`. + let a_i32_display: Arc = Arc::new(42i32, GFP_KERNEL)?; + let a_str_display: Arc = a.clone(); + arc_dyn_print(&a_i32_display); + arc_dyn_print(&a_str_display); + } + + #[cfg(not(CONFIG_RUST_COERCE_POINTEE))] + pr_info!( + "The demonstration for dynamic dispatching through Arc is skipped. " + "To see the print-out from this example, please upgrade your Rust compiler to 1.83.0 or higher.\n" + ); // Pretty-prints the debug formatting with lower-case hexadecimal integers. pr_info!("{:#x?}", a); @@ -49,10 +62,6 @@ fn arc_print() -> Result { Ok(()) } -fn arc_dyn_print(arc: &Arc) { - pr_info!("Arc says {arc}"); -} - impl kernel::Module for RustPrint { fn init(_module: &'static ThisModule) -> Result { pr_info!("Rust printing macros sample (init)\n");