Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
// # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`.
{
let trait_path =
cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]);
cx.path_all(span, true, path!(span, core::ops::CoercePointeeValidated), vec![]);
let trait_ref = cx.trait_ref(trait_path);
push(Annotatable::Item(
cx.item(
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_error_codes/src/error_codes/E0802.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The target data is not a `struct`.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
enum NotStruct<'a, T: ?Sized> {
Variant(&'a T),
Expand All @@ -19,7 +19,7 @@ in other words.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
struct NotTransparent<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
Expand All @@ -30,7 +30,7 @@ The target data has no data field.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoField<'a, #[pointee] T: ?Sized> {}
Expand All @@ -40,7 +40,7 @@ The target data is not generic over any data, or has no generic type parameter.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoGeneric<'a>(&'a u8);
Expand All @@ -51,7 +51,7 @@ a pointee for coercion.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
Expand All @@ -64,7 +64,7 @@ pointees for coercion.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct TooManyPointees<
Expand All @@ -78,7 +78,7 @@ The type parameter that is designated as a pointee is not marked `?Sized`.

```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
use std::ops::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoMaybeSized<'a, #[pointee] T> {
Expand Down
209 changes: 1 addition & 208 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,212 +1132,5 @@ pub trait FnPtr: Copy + Clone {
fn addr(self) -> *const ();
}

/// 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, coerce_pointee_validated)]
#[rustc_diagnostic_item = "CoercePointee"]
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
pub macro CoercePointee($item:item) {
/* compiler built-in */
}

/// A trait that is implemented for ADTs with `derive(CoercePointee)` so that
/// the compiler can enforce the derive impls are valid post-expansion, since
/// the derive has stricter requirements than if the impls were written by hand.
///
/// This trait is not intended to be implemented by users or used other than
/// validation, so it should never be stabilized.
#[lang = "coerce_pointee_validated"]
#[unstable(feature = "coerce_pointee_validated", issue = "none")]
#[doc(hidden)]
pub trait CoercePointeeValidated {
/* compiler built-in */
}
pub use crate::ops::CoercePointee;
4 changes: 4 additions & 0 deletions library/core/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ pub use self::try_trait::Yeet;
pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
pub use self::try_trait::{FromResidual, Try};
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
pub use self::unsize::CoercePointee;
#[unstable(feature = "coerce_pointee_validated", issue = "none")]
pub use self::unsize::CoercePointeeValidated;
#[unstable(feature = "coerce_unsized", issue = "18598")]
pub use self::unsize::CoerceUnsized;
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
Expand Down
Loading
Loading