Skip to content

Commit

Permalink
Rollup merge of rust-lang#136351 - Darksonn:coerce-pointee-docs, r=co…
Browse files Browse the repository at this point in the history
…mpiler-errors

Add documentation for derive(CoercePointee)

Part of [RFC 3621][rfc] tracked by rust-lang#123430. This text is heavily based on the guide-level explanation from the RFC.

``@rustbot`` label F-derive_coerce_pointee

[rfc]: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html
  • Loading branch information
matthiaskrgr authored Feb 1, 2025
2 parents 1935bbf + 209bb81 commit 70894fe
Showing 1 changed file with 189 additions and 1 deletion.
190 changes: 189 additions & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone {
fn addr(self) -> *const ();
}

/// Derive macro generating impls of traits related to smart pointers.
/// Derive macro that makes a smart pointer usable with trait objects.
///
/// # What this macro does
///
/// This macro is intended to be used with user-defined pointer types, and makes it possible to
/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this:
///
/// ## Unsizing coercions of the pointee
///
/// By using the macro, the following example will compile:
/// ```
/// #![feature(derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<T: ?Sized>(Box<T>);
///
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// &self.0
/// }
/// }
///
/// trait MyTrait {}
///
/// impl MyTrait for i32 {}
///
/// fn main() {
/// let ptr: MySmartPointer<i32> = MySmartPointer(Box::new(4));
///
/// // This coercion would be an error without the derive.
/// let ptr: MySmartPointer<dyn MyTrait> = ptr;
/// }
/// ```
/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error:
/// ```text
/// error[E0308]: mismatched types
/// --> src/main.rs:11:44
/// |
/// 11 | let ptr: MySmartPointer<dyn MyTrait> = ptr;
/// | --------------------------- ^^^ expected `MySmartPointer<dyn MyTrait>`, found `MySmartPointer<i32>`
/// | |
/// | expected due to this
/// |
/// = note: expected struct `MySmartPointer<dyn MyTrait>`
/// found struct `MySmartPointer<i32>`
/// = help: `i32` implements `MyTrait` so you could box the found value and coerce it to the trait object `Box<dyn MyTrait>`, you will have to change the expected type as well
/// ```
///
/// ## Dyn compatibility
///
/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the
/// type as a receiver are dyn-compatible. For example, this compiles:
///
/// ```
/// #![feature(arbitrary_self_types, derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<T: ?Sized>(Box<T>);
///
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// &self.0
/// }
/// }
///
/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)])
/// trait MyTrait {
/// fn func(self: MySmartPointer<Self>);
/// }
///
/// // But using `dyn MyTrait` requires #[derive(CoercePointee)].
/// fn call_func(value: MySmartPointer<dyn MyTrait>) {
/// value.func();
/// }
/// ```
/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example
/// will fail with this error message:
/// ```text
/// error[E0038]: the trait `MyTrait` is not dyn compatible
/// --> src/lib.rs:21:36
/// |
/// 17 | fn func(self: MySmartPointer<Self>);
/// | -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self`
/// ...
/// 21 | fn call_func(value: MySmartPointer<dyn MyTrait>) {
/// | ^^^^^^^^^^^ `MyTrait` is not dyn compatible
/// |
/// note: for a trait to be dyn compatible it needs to allow building a vtable
/// for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
/// --> src/lib.rs:17:19
/// |
/// 16 | trait MyTrait {
/// | ------- this trait is not dyn compatible...
/// 17 | fn func(self: MySmartPointer<Self>);
/// | ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on
/// ```
///
/// # Requirements for using the macro
///
/// This macro can only be used if:
/// * The type is a `#[repr(transparent)]` struct.
/// * The type of its non-zero-sized field must either be a standard library pointer type
/// (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type
/// also using the `#[derive(CoercePointee)]` macro.
/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has
/// type [`PhantomData`].
///
/// ## Multiple type parameters
///
/// If the type has multiple type parameters, then you must explicitly specify which one should be
/// used for dynamic dispatch. For example:
/// ```
/// # #![feature(derive_coerce_pointee)]
/// # use std::marker::{CoercePointee, PhantomData};
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<#[pointee] T: ?Sized, U> {
/// ptr: Box<T>,
/// _phantom: PhantomData<U>,
/// }
/// ```
/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required.
///
/// # Examples
///
/// A custom implementation of the `Rc` type:
/// ```
/// #![feature(derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
/// use std::ptr::NonNull;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// pub struct Rc<T: ?Sized> {
/// inner: NonNull<RcInner<T>>,
/// }
///
/// struct RcInner<T: ?Sized> {
/// refcount: usize,
/// value: T,
/// }
///
/// impl<T: ?Sized> Deref for Rc<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// let ptr = self.inner.as_ptr();
/// unsafe { &(*ptr).value }
/// }
/// }
///
/// impl<T> Rc<T> {
/// pub fn new(value: T) -> Self {
/// let inner = Box::new(RcInner {
/// refcount: 1,
/// value,
/// });
/// Self {
/// inner: NonNull::from(Box::leak(inner)),
/// }
/// }
/// }
///
/// impl<T: ?Sized> Clone for Rc<T> {
/// fn clone(&self) -> Self {
/// // A real implementation would handle overflow here.
/// unsafe { (*self.inner.as_ptr()).refcount += 1 };
/// Self { inner: self.inner }
/// }
/// }
///
/// impl<T: ?Sized> Drop for Rc<T> {
/// fn drop(&mut self) {
/// let ptr = self.inner.as_ptr();
/// unsafe { (*ptr).refcount -= 1 };
/// if unsafe { (*ptr).refcount } == 0 {
/// drop(unsafe { Box::from_raw(ptr) });
/// }
/// }
/// }
/// ```
#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
Expand Down

0 comments on commit 70894fe

Please sign in to comment.