Skip to content

Commit

Permalink
rust: use derive(CoercePointee) on rustc >= 1.84.0
Browse files Browse the repository at this point in the history
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 [1]
Link: https://lore.kernel.org/all/[email protected]/ [2]
Link: rust-lang/rust#131284 [3]
Signed-off-by: Xiangfei Ding <[email protected]>
Reviewed-by: Fiona Behrens <[email protected]>
Reviewed-by: Alice Ryhl <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
[ 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 <[email protected]>
  • Loading branch information
dingxiangfei2009 authored and ojeda committed Jan 13, 2025
1 parent 05d1f85 commit e21f964
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 11 deletions.
3 changes: 3 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
7 changes: 4 additions & 3 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
#![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.
Expand Down
9 changes: 6 additions & 3 deletions rust/kernel/list/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
{
}
Expand Down
15 changes: 11 additions & 4 deletions rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
use core::{
alloc::Layout,
fmt,
marker::{PhantomData, Unsize},
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -479,14 +483,17 @@ 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 ()>,
}

// 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>
{
}
Expand Down
18 changes: 18 additions & 0 deletions samples/rust/rust_print_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit e21f964

Please sign in to comment.