mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-22 07:53:11 -05:00
rust: use derive(CoercePointee) on rustc >= 1.84.0
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/20240823-derive-smart-pointer-v1-1-53769cd37239@google.com/ [2] Link: https://github.com/rust-lang/rust/pull/131284 [3] 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>
This commit is contained in:
parent
91da5a2414
commit
47cb6bf786
6 changed files with 43 additions and 11 deletions
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 @@ fn try_new_list_arc(&self) -> bool {
|
|||
///
|
||||
/// [`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 @@ fn as_ref(&self) -> &Arc<T> {
|
|||
|
||||
// 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,
|
||||
{
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
use core::{
|
||||
alloc::Layout,
|
||||
fmt,
|
||||
marker::{PhantomData, Unsize},
|
||||
marker::PhantomData,
|
||||
mem::{ManuallyDrop, MaybeUninit},
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
|
@ -125,6 +125,8 @@
|
|||
/// 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 @@ unsafe fn container_of(ptr: *const T) -> NonNull<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 @@ fn from(item: Pin<UniqueArc<T>>) -> Self {
|
|||
/// 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>
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue