Skip to content

Commit 70894fe

Browse files
authored
Rollup merge of #136351 - Darksonn:coerce-pointee-docs, r=compiler-errors
Add documentation for derive(CoercePointee) Part of [RFC 3621][rfc] tracked by #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
2 parents 1935bbf + 209bb81 commit 70894fe

File tree

1 file changed

+189
-1
lines changed

1 file changed

+189
-1
lines changed

library/core/src/marker.rs

+189-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone {
10911091
fn addr(self) -> *const ();
10921092
}
10931093

1094-
/// Derive macro generating impls of traits related to smart pointers.
1094+
/// Derive macro that makes a smart pointer usable with trait objects.
1095+
///
1096+
/// # What this macro does
1097+
///
1098+
/// This macro is intended to be used with user-defined pointer types, and makes it possible to
1099+
/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this:
1100+
///
1101+
/// ## Unsizing coercions of the pointee
1102+
///
1103+
/// By using the macro, the following example will compile:
1104+
/// ```
1105+
/// #![feature(derive_coerce_pointee)]
1106+
/// use std::marker::CoercePointee;
1107+
/// use std::ops::Deref;
1108+
///
1109+
/// #[derive(CoercePointee)]
1110+
/// #[repr(transparent)]
1111+
/// struct MySmartPointer<T: ?Sized>(Box<T>);
1112+
///
1113+
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
1114+
/// type Target = T;
1115+
/// fn deref(&self) -> &T {
1116+
/// &self.0
1117+
/// }
1118+
/// }
1119+
///
1120+
/// trait MyTrait {}
1121+
///
1122+
/// impl MyTrait for i32 {}
1123+
///
1124+
/// fn main() {
1125+
/// let ptr: MySmartPointer<i32> = MySmartPointer(Box::new(4));
1126+
///
1127+
/// // This coercion would be an error without the derive.
1128+
/// let ptr: MySmartPointer<dyn MyTrait> = ptr;
1129+
/// }
1130+
/// ```
1131+
/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error:
1132+
/// ```text
1133+
/// error[E0308]: mismatched types
1134+
/// --> src/main.rs:11:44
1135+
/// |
1136+
/// 11 | let ptr: MySmartPointer<dyn MyTrait> = ptr;
1137+
/// | --------------------------- ^^^ expected `MySmartPointer<dyn MyTrait>`, found `MySmartPointer<i32>`
1138+
/// | |
1139+
/// | expected due to this
1140+
/// |
1141+
/// = note: expected struct `MySmartPointer<dyn MyTrait>`
1142+
/// found struct `MySmartPointer<i32>`
1143+
/// = 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
1144+
/// ```
1145+
///
1146+
/// ## Dyn compatibility
1147+
///
1148+
/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the
1149+
/// type as a receiver are dyn-compatible. For example, this compiles:
1150+
///
1151+
/// ```
1152+
/// #![feature(arbitrary_self_types, derive_coerce_pointee)]
1153+
/// use std::marker::CoercePointee;
1154+
/// use std::ops::Deref;
1155+
///
1156+
/// #[derive(CoercePointee)]
1157+
/// #[repr(transparent)]
1158+
/// struct MySmartPointer<T: ?Sized>(Box<T>);
1159+
///
1160+
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
1161+
/// type Target = T;
1162+
/// fn deref(&self) -> &T {
1163+
/// &self.0
1164+
/// }
1165+
/// }
1166+
///
1167+
/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)])
1168+
/// trait MyTrait {
1169+
/// fn func(self: MySmartPointer<Self>);
1170+
/// }
1171+
///
1172+
/// // But using `dyn MyTrait` requires #[derive(CoercePointee)].
1173+
/// fn call_func(value: MySmartPointer<dyn MyTrait>) {
1174+
/// value.func();
1175+
/// }
1176+
/// ```
1177+
/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example
1178+
/// will fail with this error message:
1179+
/// ```text
1180+
/// error[E0038]: the trait `MyTrait` is not dyn compatible
1181+
/// --> src/lib.rs:21:36
1182+
/// |
1183+
/// 17 | fn func(self: MySmartPointer<Self>);
1184+
/// | -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self`
1185+
/// ...
1186+
/// 21 | fn call_func(value: MySmartPointer<dyn MyTrait>) {
1187+
/// | ^^^^^^^^^^^ `MyTrait` is not dyn compatible
1188+
/// |
1189+
/// note: for a trait to be dyn compatible it needs to allow building a vtable
1190+
/// for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
1191+
/// --> src/lib.rs:17:19
1192+
/// |
1193+
/// 16 | trait MyTrait {
1194+
/// | ------- this trait is not dyn compatible...
1195+
/// 17 | fn func(self: MySmartPointer<Self>);
1196+
/// | ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on
1197+
/// ```
1198+
///
1199+
/// # Requirements for using the macro
1200+
///
1201+
/// This macro can only be used if:
1202+
/// * The type is a `#[repr(transparent)]` struct.
1203+
/// * The type of its non-zero-sized field must either be a standard library pointer type
1204+
/// (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type
1205+
/// also using the `#[derive(CoercePointee)]` macro.
1206+
/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has
1207+
/// type [`PhantomData`].
1208+
///
1209+
/// ## Multiple type parameters
1210+
///
1211+
/// If the type has multiple type parameters, then you must explicitly specify which one should be
1212+
/// used for dynamic dispatch. For example:
1213+
/// ```
1214+
/// # #![feature(derive_coerce_pointee)]
1215+
/// # use std::marker::{CoercePointee, PhantomData};
1216+
/// #[derive(CoercePointee)]
1217+
/// #[repr(transparent)]
1218+
/// struct MySmartPointer<#[pointee] T: ?Sized, U> {
1219+
/// ptr: Box<T>,
1220+
/// _phantom: PhantomData<U>,
1221+
/// }
1222+
/// ```
1223+
/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required.
1224+
///
1225+
/// # Examples
1226+
///
1227+
/// A custom implementation of the `Rc` type:
1228+
/// ```
1229+
/// #![feature(derive_coerce_pointee)]
1230+
/// use std::marker::CoercePointee;
1231+
/// use std::ops::Deref;
1232+
/// use std::ptr::NonNull;
1233+
///
1234+
/// #[derive(CoercePointee)]
1235+
/// #[repr(transparent)]
1236+
/// pub struct Rc<T: ?Sized> {
1237+
/// inner: NonNull<RcInner<T>>,
1238+
/// }
1239+
///
1240+
/// struct RcInner<T: ?Sized> {
1241+
/// refcount: usize,
1242+
/// value: T,
1243+
/// }
1244+
///
1245+
/// impl<T: ?Sized> Deref for Rc<T> {
1246+
/// type Target = T;
1247+
/// fn deref(&self) -> &T {
1248+
/// let ptr = self.inner.as_ptr();
1249+
/// unsafe { &(*ptr).value }
1250+
/// }
1251+
/// }
1252+
///
1253+
/// impl<T> Rc<T> {
1254+
/// pub fn new(value: T) -> Self {
1255+
/// let inner = Box::new(RcInner {
1256+
/// refcount: 1,
1257+
/// value,
1258+
/// });
1259+
/// Self {
1260+
/// inner: NonNull::from(Box::leak(inner)),
1261+
/// }
1262+
/// }
1263+
/// }
1264+
///
1265+
/// impl<T: ?Sized> Clone for Rc<T> {
1266+
/// fn clone(&self) -> Self {
1267+
/// // A real implementation would handle overflow here.
1268+
/// unsafe { (*self.inner.as_ptr()).refcount += 1 };
1269+
/// Self { inner: self.inner }
1270+
/// }
1271+
/// }
1272+
///
1273+
/// impl<T: ?Sized> Drop for Rc<T> {
1274+
/// fn drop(&mut self) {
1275+
/// let ptr = self.inner.as_ptr();
1276+
/// unsafe { (*ptr).refcount -= 1 };
1277+
/// if unsafe { (*ptr).refcount } == 0 {
1278+
/// drop(unsafe { Box::from_raw(ptr) });
1279+
/// }
1280+
/// }
1281+
/// }
1282+
/// ```
10951283
#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
10961284
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
10971285
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]

0 commit comments

Comments
 (0)