Skip to content

Commit 23a34ef

Browse files
committed
Generalize PinCoerceUnsized into a new PinSafePointer trait
1 parent 5043948 commit 23a34ef

5 files changed

Lines changed: 202 additions & 45 deletions

File tree

library/alloc/src/boxed.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ use core::ops::{
200200
};
201201
#[cfg(not(no_global_oom_handling))]
202202
use core::ops::{Residual, Try};
203-
use core::pin::{Pin, PinCoerceUnsized};
203+
use core::pin::{Pin, PinSafePointer};
204204
use core::ptr::{self, NonNull, Unique};
205205
use core::task::{Context, Poll};
206206

@@ -2324,8 +2324,27 @@ impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box
23242324
#[unstable(feature = "coerce_unsized", issue = "18598")]
23252325
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
23262326

2327+
// A pointer can only be pin safe if it does not implement certain safe traits
2328+
// maliciously. Since `Box` is fundamental, downstream crates may be able to
2329+
// implement those traits for `Box<LocalType>`, so we must carefully check that
2330+
// this is not a problem for each trait.
2331+
//
2332+
// The `Box` type always implements `Deref` and `DerefMut`, so despite being
2333+
// fundamental, downstream crates cannot implement these traits for
2334+
// `Box<LocalType>`.
2335+
//
2336+
// Conversely, downstream crates are able to implement `Clone`, `Debug`, and
2337+
// `Display` for `Box<LocalType>` as long as `LocalType` does not implement
2338+
// said trait. However, the `Box<T>` type does not treat the existence of an
2339+
// `&Box<T>` as evidence that the `T` is not pinned, so this is not
2340+
// problematic.
2341+
//
2342+
// Finally, even if downstream crates provide their own implementation of
2343+
// `Clone` for `Box<LocalType>`, it is not problematic for the cloned box to be
2344+
// wrapped in `Pin`, since the same conversion could have been carried out
2345+
// safely as `Box::pin((*p).clone())`.
23272346
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2328-
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
2347+
unsafe impl<T: ?Sized, A: Allocator + 'static> PinSafePointer for Box<T, A> {}
23292348

23302349
// It is quite crucial that we only allow the `Global` allocator here.
23312350
// Handling arbitrary custom allocators (which can affect the `Box` layout heavily!)

library/alloc/src/rc.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ use core::ops::{Residual, Try};
260260
use core::panic::{RefUnwindSafe, UnwindSafe};
261261
#[cfg(not(no_global_oom_handling))]
262262
use core::pin::Pin;
263-
use core::pin::PinCoerceUnsized;
263+
use core::pin::PinSafePointer;
264264
use core::ptr::{self, NonNull, drop_in_place};
265265
#[cfg(not(no_global_oom_handling))]
266266
use core::slice::from_raw_parts_mut;
@@ -2444,12 +2444,19 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> {
24442444
}
24452445
}
24462446

2447+
// The API of this pointer type enforces that if the `T` is pinned, then *all*
2448+
// clones of this `Rc<T>` are wrapped as `Pin<Rc<T>>`. Since an `&Rc<T>` could
2449+
// be used to obtain an `Rc<T>` that is not wrapped in `Pin` (and later used
2450+
// with `Rc::get_mut`), this means that this type treats `&Rc<T>` as evidence
2451+
// that the `T` is not pinned. The implementations of various traits are written
2452+
// accordingly. Since this type is not fundamental, downstream crates cannot
2453+
// provide malicious implementations of any of the traits relevant for `Pin`.
24472454
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2448-
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Rc<T, A> {}
2455+
unsafe impl<T: ?Sized, A: Allocator + 'static> PinSafePointer for Rc<T, A> {}
24492456

24502457
//#[unstable(feature = "unique_rc_arc", issue = "112566")]
24512458
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2452-
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for UniqueRc<T, A> {}
2459+
unsafe impl<T: ?Sized, A: Allocator + 'static> PinSafePointer for UniqueRc<T, A> {}
24532460

24542461
#[unstable(feature = "deref_pure_trait", issue = "87121")]
24552462
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}

library/alloc/src/sync.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Lega
2525
#[cfg(not(no_global_oom_handling))]
2626
use core::ops::{Residual, Try};
2727
use core::panic::{RefUnwindSafe, UnwindSafe};
28-
use core::pin::{Pin, PinCoerceUnsized};
28+
use core::pin::{Pin, PinSafePointer};
2929
use core::ptr::{self, NonNull};
3030
#[cfg(not(no_global_oom_handling))]
3131
use core::slice::from_raw_parts_mut;
@@ -2451,8 +2451,16 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
24512451
}
24522452
}
24532453

2454+
// The API of this pointer type enforces that if the `T` is pinned, then *all*
2455+
// clones of this `Arc<T>` are wrapped as `Pin<Arc<T>>`. Since an `&Arc<T>`
2456+
// could be used to obtain an `Arc<T>` that is not wrapped in `Pin` (and later
2457+
// used with `Arc::get_mut`), this means that this type treats `&Arc<T>` as
2458+
// evidence that the `T` is not pinned. The implementations of various traits
2459+
// are written accordingly. Since this type is not fundamental, downstream
2460+
// crates cannot provide malicious implementations of any of the traits relevant
2461+
// for `Pin`.
24542462
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2455-
unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Arc<T, A> {}
2463+
unsafe impl<T: ?Sized, A: Allocator + 'static> PinSafePointer for Arc<T, A> {}
24562464

24572465
#[unstable(feature = "deref_pure_trait", issue = "87121")]
24582466
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
@@ -4893,7 +4901,7 @@ impl<T: ?Sized, A: Allocator> Deref for UniqueArc<T, A> {
48934901

48944902
// #[unstable(feature = "unique_rc_arc", issue = "112566")]
48954903
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
4896-
unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueArc<T> {}
4904+
unsafe impl<T: ?Sized, A: Allocator + 'static> PinSafePointer for UniqueArc<T, A> {}
48974905

48984906
#[unstable(feature = "unique_rc_arc", issue = "112566")]
48994907
impl<T: ?Sized, A: Allocator> DerefMut for UniqueArc<T, A> {

library/core/src/cell.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ use crate::marker::{Destruct, PhantomData, Unsize};
255255
use crate::mem::{self, ManuallyDrop};
256256
use crate::ops::{self, CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
257257
use crate::panic::const_panic;
258-
use crate::pin::PinCoerceUnsized;
258+
use crate::pin::PinSafePointer;
259259
use crate::ptr::{self, NonNull};
260260
use crate::range;
261261

@@ -2718,8 +2718,14 @@ fn assert_coerce_unsized(
27182718
let _: RefCell<&dyn Send> = d;
27192719
}
27202720

2721+
// The implementations of Deref/DerefMut are not malicious, so we can allow the
2722+
// user to perform unsizing coercions with `Pin<Ref<'b, T>>` pointers if they
2723+
// can manage to create one.
27212724
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2722-
unsafe impl<'b, T: ?Sized> PinCoerceUnsized for Ref<'b, T> {}
2725+
unsafe impl<'b, T: ?Sized> PinSafePointer for Ref<'b, T> {}
27232726

2727+
// The implementations of Deref/DerefMut are not malicious, so we can allow the
2728+
// user to perform unsizing coercions with `Pin<RefMut<'b, T>>` pointers if they
2729+
// can manage to create one.
27242730
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
2725-
unsafe impl<'b, T: ?Sized> PinCoerceUnsized for RefMut<'b, T> {}
2731+
unsafe impl<'b, T: ?Sized> PinSafePointer for RefMut<'b, T> {}

library/core/src/pin.rs

Lines changed: 151 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,9 +1080,8 @@ pub use self::unsafe_pinned::UnsafePinned;
10801080
/// [subtle-details]: self#subtle-details-and-the-drop-guarantee "pin subtle details"
10811081
/// [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
10821082
//
1083-
// Note: the `Clone` derive below causes unsoundness as it's possible to implement
1084-
// `Clone` for mutable references.
1085-
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311> for more details.
1083+
// Note: the `Clone` derive below is sound because either `Ptr: PinSafePointer`
1084+
// or the pointee is `Unpin`.
10861085
#[stable(feature = "pin", since = "1.33.0")]
10871086
#[lang = "pin"]
10881087
#[fundamental]
@@ -1097,7 +1096,8 @@ pub struct Pin<Ptr> {
10971096
// issues. `&self.pointer` should not be accessible to untrusted trait
10981097
// implementations.
10991098
//
1100-
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73> for more details.
1099+
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73> and the
1100+
// `PinSafePointer` trait for more details.
11011101

11021102
#[stable(feature = "pin_trait_impls", since = "1.41.0")]
11031103
impl<Ptr: Deref, Q: Deref> PartialEq<Pin<Q>> for Pin<Ptr>
@@ -1230,11 +1230,15 @@ impl<Ptr: Deref> Pin<Ptr> {
12301230
/// points to is pinned, that is a violation of the API contract and may lead to undefined
12311231
/// behavior in later (even safe) operations.
12321232
///
1233-
/// By using this method, you are also making a promise about the [`Deref`],
1234-
/// [`DerefMut`], and [`Drop`] implementations of `Ptr`, if they exist. Most importantly, they
1235-
/// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref`
1236-
/// will call `DerefMut::deref_mut` and `Deref::deref` *on the pointer type `Ptr`*
1237-
/// and expect these methods to uphold the pinning invariants.
1233+
/// By using this method, you are also making a promise about several trait
1234+
/// implementations of `Ptr` itself, if they exist. Most importantly, they
1235+
/// must not move out of their `self` arguments: `Pin::as_mut` and
1236+
/// `Pin::as_ref` will call `DerefMut::deref_mut` and `Deref::deref` *on the
1237+
/// pointer type `Ptr`* and expect these methods to uphold the pinning
1238+
/// invariants. These requirements are specified in more detail on the
1239+
/// [`PinSafePointer`] trait, and `Ptr` must abide by the safety
1240+
/// requirements of that trait.
1241+
///
12381242
/// Moreover, by calling this method you promise that the reference `Ptr`
12391243
/// dereferences to will not be moved out of again; in particular, it
12401244
/// must not be possible to obtain a `&mut Ptr::Target` and then
@@ -1690,7 +1694,7 @@ impl<Ptr: [const] Deref> const Deref for Pin<Ptr> {
16901694
mod helper {
16911695
/// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`.
16921696
///
1693-
/// The `Pin` type implements the unsafe trait `PinCoerceUnsized`, which essentially requires
1697+
/// The `Pin` type implements the unsafe trait `PinSafePointer`, which essentially requires
16941698
/// that the type does not have a malicious `Deref` or `DerefMut` impl. However, without this
16951699
/// helper module, downstream crates are able to write `impl DerefMut for Pin<LocalType>` as
16961700
/// long as it does not overlap with the impl provided by stdlib. This is because `Pin` is
@@ -1781,6 +1785,10 @@ unsafe impl<Ptr: DerefPure> DerefPure for Pin<Ptr> {}
17811785
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
17821786
impl<Ptr: LegacyReceiver> LegacyReceiver for Pin<Ptr> {}
17831787

1788+
// The following implementations allow untrusted trait implementations to access
1789+
// `&self.pointer`, which is only sound because these traits are mentioned in
1790+
// the safety requirements of `PinSafePointer`.
1791+
17841792
#[stable(feature = "pin", since = "1.33.0")]
17851793
impl<Ptr: fmt::Debug> fmt::Debug for Pin<Ptr> {
17861794
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1810,49 +1818,158 @@ impl<Ptr: fmt::Pointer> fmt::Pointer for Pin<Ptr> {
18101818
#[stable(feature = "pin", since = "1.33.0")]
18111819
impl<Ptr, U> CoerceUnsized<Pin<U>> for Pin<Ptr>
18121820
where
1813-
Ptr: CoerceUnsized<U> + PinCoerceUnsized,
1814-
U: PinCoerceUnsized,
1821+
Ptr: CoerceUnsized<U> + PinSafePointer,
1822+
U: PinSafePointer,
18151823
{
18161824
}
18171825

18181826
#[stable(feature = "pin", since = "1.33.0")]
18191827
impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr>
18201828
where
1821-
Ptr: DispatchFromDyn<U> + PinCoerceUnsized,
1822-
U: PinCoerceUnsized,
1829+
Ptr: DispatchFromDyn<U> + PinSafePointer,
1830+
U: PinSafePointer,
18231831
{
18241832
}
18251833

18261834
#[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")]
1827-
/// Trait that indicates that this is a pointer or a wrapper for one, where
1828-
/// unsizing can be performed on the pointee when it is pinned.
1835+
/// Trait that indicates that this is a pointer that does not misbehave when
1836+
/// combined with [`Pin`].
1837+
///
1838+
/// Note that for backwards compatibility reasons, it is possible to create a
1839+
/// [`Pin<P>`] for pointer types `P` that do not implement this trait. However,
1840+
/// this can only be done safely if `<P as Deref>::Target` implements `Unpin`,
1841+
/// which means that pinning has no effect.
18291842
///
18301843
/// # Safety
18311844
///
1832-
/// Given a pointer of this type, the concrete type returned by its
1833-
/// `deref` method and (if it implements `DerefMut`) its `deref_mut` method
1834-
/// must be the same type and must not change without a modification.
1835-
/// The following operations are not considered modifications:
1836-
///
1837-
/// * Moving the pointer.
1838-
/// * Performing unsizing coercions on the pointer.
1839-
/// * Performing dynamic dispatch with the pointer.
1840-
/// * Calling `deref` or `deref_mut` on the pointer.
1841-
///
1842-
/// The concrete type of a trait object is the type that the vtable corresponds
1843-
/// to. The concrete type of a slice is an array of the same element type and
1844-
/// the length specified in the metadata. The concrete type of a sized type
1845-
/// is the type itself.
1846-
pub unsafe trait PinCoerceUnsized: Deref {}
1845+
/// Types that implement this trait must not provide "malicious" implementations
1846+
/// of any safe traits used by [`Pin`].
1847+
///
1848+
/// ## The pointer must always reference the same object
1849+
///
1850+
/// Calls to [`deref`]/[`deref_mut`] on the same `Pin<P>` instance must always
1851+
/// refer to the same object. That is, the address returned by these methods
1852+
/// must not change. This applies even if the pointer type is moved.
1853+
///
1854+
/// Furthermore, if the pointer type can participate in unsizing coercions or
1855+
/// dynamic dispatch, then these coercions must also not change the underlying
1856+
/// concrete type. Here, the concrete type of a trait object is the type that
1857+
/// the vtable corresponds to. The concrete type of a slice is an array of the
1858+
/// same element type and the length specified in the metadata. The concrete
1859+
/// type of a sized type is the type itself.
1860+
///
1861+
/// As an example, after unsizing coercing a pinned pointer, `deref_mut` must
1862+
/// not return a `#[repr(transparent)]` wrapper around the value it referenced
1863+
/// before being unsized, even if the address is unchanged.
1864+
///
1865+
/// ## The pointer must not move its pointee
1866+
///
1867+
/// The [`deref_mut`] method and the pointer type's destructor are called with a
1868+
/// `&mut self` receiver, but they must behave as-if it was a `self: Pin<&mut
1869+
/// Self>` receiver. That is, they must not move out of the underlying value.
1870+
///
1871+
/// As an example, `deref_mut` must not invoke `swap` on the inner value.
1872+
///
1873+
/// ## Shared access to the pointer
1874+
///
1875+
/// If this pointer type uses `&P` references as evidence that this value is not
1876+
/// pinned, then it must not treat the `&self` argument passed to [`Clone`] or
1877+
/// the formatting traits ([`fmt::Debug`], [`fmt::Display`], [`fmt::Pointer`])
1878+
/// as such evidence.
1879+
///
1880+
/// As an example, given a `Pin<Arc<T>>` there is no way to obtain an `&Arc<T>`
1881+
/// (note that `Deref` just gives a `&T`). Because of this, the [`Arc`] type can
1882+
/// assume that an `&Arc<T>` value can only exist if the `T` is not pinned,
1883+
/// which justifies the soundness of the [`Arc::get_mut`] method.
1884+
///
1885+
/// ## Cloning pinned pointers
1886+
///
1887+
/// When a [`Pin<P>`] is cloned, the `P` pointer value returned by `clone` is
1888+
/// passed to [`Pin::new_unchecked`]. The implementation of [`Clone`] must
1889+
/// return a value such that this is sound.
1890+
///
1891+
/// For example, when a `Pin<&T>` is cloned, the resulting `&T` points at the
1892+
/// same value. The value is known to be pinned since a `Pin<&T>` to it exists,
1893+
/// so it is safe to wrap the `&T` returned by `clone` in `Pin`.
1894+
///
1895+
/// [`deref`]: Deref::deref
1896+
/// [`deref_mut`]: DerefMut::deref_mut
1897+
/// [`clone`]: Clone::clone
1898+
/// [`Arc`]: ../../std/sync/struct.Arc.html "Arc"
1899+
/// [`Arc::get_mut`]: ../../std/sync/struct.Arc.html#method.get_mut "Arc::get_mut"
1900+
pub unsafe trait PinSafePointer: Deref + Sized {}
18471901

1902+
// A pointer can only be pin safe if it does not implement certain safe traits
1903+
// maliciously. Since `&T` is fundamental, downstream crates may be able to
1904+
// implement those traits for `&LocalType`, so we must carefully check that
1905+
// this is not a problem for each trait.
1906+
//
1907+
// The `&T` type always implements [`Deref`] and [`Clone`], so despite being
1908+
// fundamental, downstream crates cannot implement these traits for
1909+
// `&LocalType`.
1910+
//
1911+
// The `&T` type has a negative blanket implementations for [`DerefMut`], so
1912+
// downstream crates cannot implement `DerefMut` for `&LocalType`.
1913+
//
1914+
// Conversely, downstream crates are able to implement `Debug` and `Display` for
1915+
// `&LocalType` as long as `LocalType` does not implement said trait. However,
1916+
// the existence of an `&T` is not treated as evidence that the `T` is not
1917+
// pinned, so this is not problematic.
18481918
#[stable(feature = "pin", since = "1.33.0")]
1849-
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}
1919+
unsafe impl<'a, T: ?Sized> PinSafePointer for &'a T {}
18501920

1921+
// A pointer can only be pin safe if it does not implement certain safe traits
1922+
// maliciously. Since `&mut T` is fundamental, downstream crates may be able to
1923+
// implement those traits for `&mut LocalType`, so we must carefully check that
1924+
// this is not a problem for each trait.
1925+
//
1926+
// The `&mut T` type always implements [`Deref`] and [`DerefMut`], so despite
1927+
// being fundamental, downstream crates cannot implement these traits for `&mut
1928+
// LocalType`.
1929+
//
1930+
// The `&mut T` type has a negative blanket implementations for [`Clone`], so
1931+
// downstream crates cannot implement `Clone` for `&mut LocalType`.
1932+
//
1933+
// Conversely, downstream crates are able to implement `Debug` and `Display`
1934+
// for `&LocalType` as long as `LocalType` does not implement said trait.
1935+
// However, the existence of an `&T` is not treated as evidence that the `T` is
1936+
// not pinned, so this is not problematic.
18511937
#[stable(feature = "pin", since = "1.33.0")]
1852-
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}
1938+
unsafe impl<'a, T: ?Sized> PinSafePointer for &'a mut T {}
18531939

1940+
// A pointer can only be pin safe if it does not implement certain safe traits
1941+
// maliciously. `Pin` implements these traits by forwarding to `P`, which also
1942+
// asserts that these implementations are not malicious, so the implementations
1943+
// provided by `core` are ok. However, since `Pin<T>` is fundamental,
1944+
// downstream crates may be able to implement those traits for `Pin<LocalType>`
1945+
// directly, so we must carefully check that if a downstream crate can
1946+
// implement these traits for `Pin<LocalType>`, then this does not lead to any
1947+
// problems for the `Pin<Pin<LocalType>>` type.
1948+
//
1949+
// The `Pin<P>` type only implements `Deref` when `P: Deref`, so downstream
1950+
// crates can implement `Deref` for `Pin<LocalType>` in cases where `LocalType:
1951+
// !Deref`. However, as `Deref` is a super-trait for `PinSafePointer`, we do
1952+
// not assert that `Pin<P>` is pin safe in that scenario.
1953+
//
1954+
// The `Pin<P>` type only implements `DerefMut` when `P: DerefMut` and
1955+
// `P::Target: Unpin`, so normally downstream crates would be able to provide
1956+
// an implementation of `DerefMut` for `Pin<LocalType>` when `LocalType` does
1957+
// not satisfy those conditions. However, a special hack is used to prevent
1958+
// such downstream implementations, so this is not a problem. See
1959+
// [#145608](https://github.com/rust-lang/rust/pull/145608) for details.
1960+
//
1961+
// Conversely, downstream crates are able to implement `Clone`, `Debug` and
1962+
// `Display` for `Pin<LocalType>` as long as `LocalType` does not implement
1963+
// said trait. However, the existence of an `&Pin<P>` is not treated as
1964+
// evidence that the value is not pinned, so this is not problematic.
1965+
//
1966+
// Furthermore, in the case of `Clone`, cloning a `Pin<Pin<P>>` will utilize
1967+
// `Pin::new_unchecked` to convert from `Pin<P>` to `Pin<Pin<P>>`. However,
1968+
// given that the implementation of `Clone` returned a `Pin<P>`, we know that
1969+
// the target value is pinned, so this conversion is okay even if `Clone` was
1970+
// implemented for `Pin<P>` by a downstream crate.
18541971
#[stable(feature = "pin", since = "1.33.0")]
1855-
unsafe impl<T: PinCoerceUnsized> PinCoerceUnsized for Pin<T> {}
1972+
unsafe impl<P: PinSafePointer> PinSafePointer for Pin<P> {}
18561973

18571974
/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally.
18581975
///

0 commit comments

Comments
 (0)