]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rust: use derive(CoercePointee) on rustc >= 1.84.0
authorXiangfei Ding <dingxiangfei2009@gmail.com>
Tue, 3 Dec 2024 20:47:49 +0000 (04:47 +0800)
committerMiguel Ojeda <ojeda@kernel.org>
Mon, 13 Jan 2025 22:45:30 +0000 (23:45 +0100)
The `kernel` crate relies on both `coerce_unsized` and `dispatch_from_dyn`
unstable features.

Alice Ryhl has proposed [1] the introduction of the unstable macro
`SmartPointer` to reduce such dependence, along with a RFC patch [2].
Since Rust 1.81.0 this macro, later renamed to `CoercePointee` in
Rust 1.84.0 [3], has been fully implemented with the naming discussion
resolved.

This feature is now on track to stabilization in the language.
In order to do so, we shall start using this macro in the `kernel` crate
to prove the functionality and utility of the macro as the justification
of its stabilization.

This patch makes this switch in such a way that the crate remains
backward compatible with older Rust compiler versions,
via the new Kconfig option `RUSTC_HAS_COERCE_POINTEE`.

A minimal demonstration example is added to the
`samples/rust/rust_print_main.rs` module.

Link: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html
Link: https://lore.kernel.org/all/20240823-derive-smart-pointer-v1-1-53769cd37239@google.com/
Link: https://github.com/rust-lang/rust/pull/131284
Signed-off-by: Xiangfei Ding <dingxiangfei2009@gmail.com>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20241203205050.679106-2-dingxiangfei2009@gmail.com
[ Fixed version to 1.84. Renamed option to `RUSTC_HAS_COERCE_POINTEE`
  to match `CC_HAS_*` ones. Moved up new config option, closer to the
  `CC_HAS_*` ones. Simplified Kconfig line. Fixed typos and slightly
  reworded example and commit. Added Link to PR. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
init/Kconfig
rust/kernel/alloc.rs
rust/kernel/lib.rs
rust/kernel/list/arc.rs
rust/kernel/sync/arc.rs
samples/rust/rust_print_main.rs

index e8d2b5128f8733b0ca40dfb8dfcef4b59e5be950..868ffa922b2c2852bdff67a0a17cf49277d39d40 100644 (file)
@@ -129,6 +129,9 @@ config CC_HAS_COUNTED_BY
        # https://github.com/llvm/llvm-project/pull/112636
        depends on !(CC_IS_CLANG && CLANG_VERSION < 190103)
 
+config RUSTC_HAS_COERCE_POINTEE
+       def_bool RUSTC_VERSION >= 108400
+
 config PAHOLE_VERSION
        int
        default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE))
index f2f7f3a53d298cf899e062346202ba3285ce3676..fc9c9c41cd79264621c7709591f87025e9678c5f 100644 (file)
@@ -123,7 +123,7 @@ pub mod flags {
 /// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
 /// an object instance.
 ///
-/// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design
+/// In order to be able to support `#[derive(CoercePointee)]` later on, we need to avoid a design
 /// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind
 /// of `self` parameter.
 ///
index 6063f4a3d9c0c611d0dfaf4d3d62488cdb7496d8..545d1170ee6358e185b48ce10493fc61c646155c 100644 (file)
 
 #![no_std]
 #![feature(arbitrary_self_types)]
-#![feature(coerce_unsized)]
-#![feature(dispatch_from_dyn)]
+#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))]
+#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))]
+#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))]
+#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(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.
index 3483d8c232c4f1d886e6a6a5cdde9b5141b12834..13c50df37b89d1234ca584a7af8a245aabc3f719 100644 (file)
@@ -7,7 +7,7 @@
 use crate::alloc::{AllocError, Flags};
 use crate::prelude::*;
 use crate::sync::{Arc, ArcBorrow, UniqueArc};
-use core::marker::{PhantomPinned, Unsize};
+use core::marker::PhantomPinned;
 use core::ops::Deref;
 use core::pin::Pin;
 use core::sync::atomic::{AtomicBool, Ordering};
@@ -159,6 +159,7 @@ pub use impl_list_arc_safe;
 ///
 /// [`List`]: crate::list::List
 #[repr(transparent)]
+#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
 pub struct ListArc<T, const ID: u64 = 0>
 where
     T: ListArcSafe<ID> + ?Sized,
@@ -443,18 +444,20 @@ where
 
 // This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
 // dynamically-sized type (DST) `U`.
+#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
 impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
 where
-    T: ListArcSafe<ID> + Unsize<U> + ?Sized,
+    T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
     U: ListArcSafe<ID> + ?Sized,
 {
 }
 
 // This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
 // `ListArc<U>`.
+#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
 impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
 where
-    T: ListArcSafe<ID> + Unsize<U> + ?Sized,
+    T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
     U: ListArcSafe<ID> + ?Sized,
 {
 }
index 9f0b04400e8e5f3c09a763f7bd7602b040b0dadc..25d2185df4cb1f1ddee37223a79d6d93f971e25b 100644 (file)
@@ -26,7 +26,7 @@ use crate::{
 use core::{
     alloc::Layout,
     fmt,
-    marker::{PhantomData, Unsize},
+    marker::PhantomData,
     mem::{ManuallyDrop, MaybeUninit},
     ops::{Deref, DerefMut},
     pin::Pin,
@@ -125,6 +125,8 @@ mod std_vendor;
 /// let coerced: Arc<dyn MyTrait> = obj;
 /// # Ok::<(), Error>(())
 /// ```
+#[repr(transparent)]
+#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
 pub struct Arc<T: ?Sized> {
     ptr: NonNull<ArcInner<T>>,
     // NB: this informs dropck that objects of type `ArcInner<T>` may be used in `<Arc<T> as
@@ -180,10 +182,12 @@ impl<T: ?Sized> ArcInner<T> {
 
 // This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
 // dynamically-sized type (DST) `U`.
-impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
+#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
+impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
 
 // This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
-impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
+#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
+impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
 
 // SAFETY: It is safe to send `Arc<T>` 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
@@ -479,6 +483,8 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
 /// obj.as_arc_borrow().use_reference();
 /// # Ok::<(), Error>(())
 /// ```
+#[repr(transparent)]
+#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
 pub struct ArcBorrow<'a, T: ?Sized + 'a> {
     inner: NonNull<ArcInner<T>>,
     _p: PhantomData<&'a ()>,
@@ -486,7 +492,8 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> {
 
 // This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
 // `ArcBorrow<U>`.
-impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
+#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
+impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
     for ArcBorrow<'_, T>
 {
 }
index 7935b4772ec6cee7f5826460012652a158f07838..7e8af5f176a33925881c7d65b34c823028b7b93b 100644 (file)
@@ -34,6 +34,24 @@ 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` implement `Display`. This enables us to express a unified
+        // behaviour, contract or protocol on both `i32` and `&str` into a single `Arc` of
+        // type `Arc<dyn Display>`.
+
+        use core::fmt::Display;
+        fn arc_dyn_print(arc: &Arc<dyn Display>) {
+            pr_info!("Arc<dyn Display> says {arc}");
+        }
+
+        let a_i32_display: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
+        let a_str_display: Arc<dyn Display> = a.clone();
+
+        arc_dyn_print(&a_i32_display);
+        arc_dyn_print(&a_str_display);
+    }
+
     // Pretty-prints the debug formatting with lower-case hexadecimal integers.
     pr_info!("{:#x?}", a);