From 40598895394004a82bef1a7d9f99efdabd552d43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 13:08:46 +0100 Subject: [PATCH 01/24] improve Pin documentation --- src/libcore/marker.rs | 12 ++- src/libcore/pin.rs | 198 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 190 insertions(+), 20 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c4b41f1a3090c..f9a4f75c92ae2 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -597,7 +597,8 @@ unsafe impl Freeze for &mut T {} /// Types which can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and will consider moves to always be safe, +/// Since Rust itself has no notion of immovable types, and will consider moves +/// (e.g. through assignment or [`mem::replace`]) to always be safe, /// this trait cannot prevent types from moving by itself. /// /// Instead it can be used to prevent moves through the type system, @@ -606,7 +607,12 @@ unsafe impl Freeze for &mut T {} /// See the [`pin module`] documentation for more information on pinning. /// /// Implementing this trait lifts the restrictions of pinning off a type, -/// which then allows it to move out with functions such as [`replace`]. +/// which then allows it to move out with functions such as [`mem::replace`]. +/// +/// `Unpin` has no consequence at all for non-pinned data. In particular, +/// [`mem::replace`] will happily move `!Unpin` data. However, you cannot use +/// [`mem::replace`] on data wrapped inside a [`Pin`], and *that* is what makes +/// this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// @@ -623,7 +629,7 @@ unsafe impl Freeze for &mut T {} /// /// This trait is automatically implemented for almost every type. /// -/// [`replace`]: ../../std/mem/fn.replace.html +/// [`mem::replace`]: ../../std/mem/fn.replace.html /// [`Pin`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index ee9098d73ee92..b8a0a93eddb77 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -16,7 +16,7 @@ //! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved, //! but the value behind it cannot. //! -//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`], +//! Since data can be moved out of `&mut` and `Box` with functions such as [`mem::swap`], //! changing the location of the underlying data, [`Pin`] prohibits accessing the //! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of //! APIs for accessing and using the value. [`Pin`] also guarantees that no other @@ -24,21 +24,22 @@ //! self-references and other special behaviors that are only possible for unmovable //! values. //! -//! However, these restrictions are usually not necessary. Many types are always freely -//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect -//! of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function identically, as do -//! `Pin<&mut T>` and `&mut T`. +//! It is worth reiterating that [`Pin`] does *not* change the fact that the Rust compiler +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` +//! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being +//! moved by making it impossible to call methods like [`mem::swap`] on them. //! -//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether -//! or not `Box` is `Unpin` has no affect on the behavior of `Pin>`. Similarly, -//! `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, even though the -//! `T` underneath them isn't, because the pointers in `Pin>` and `Pin<&mut _>` -//! are always freely movable, even if the data they point to isn't. +//! # `Unpin` //! -//! [`Pin`]: struct.Pin.html -//! [`Unpin`]: ../../std/marker/trait.Unpin.html -//! [`swap`]: ../../std/mem/fn.swap.html -//! [`Box`]: ../../std/boxed/struct.Box.html +//! However, these restrictions are usually not necessary. Many types are always freely +//! movable, even when pinned. These types implement the [`Unpin`] auto-trait, which +//! nullifies the effect of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function +//! identically, as do `Pin<&mut T>` and `&mut T`. +//! +//! Note that pinning and `Unpin` only affect the pointed-to type, not the pointer +//! type itself that got wrapped in `Pin`. For example, whether or not `Box` is +//! `Unpin` has no affect on the behavior of `Pin>` (here, `T` is the +//! pointed-to type). //! //! # Examples //! @@ -94,6 +95,106 @@ //! // let new_unmoved = Unmovable::new("world".to_string()); //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` +//! +//! # `Drop` guarantee +//! +//! The purpose of pinning is to be able to rely on the placement of some data in memory. +//! To make this work, not just moving the data is restricted; deallocating or overwriting +//! it is restricted, too. Concretely, for pinned data you have to maintain the invariant +//! that *it will not get overwritten or deallocated until `drop` was called*. +//! ("Overwriting" here refers to other ways of invalidating storage, such as switching +//! from one enum variant to another.) +//! +//! The purpose of this guarantee is to allow data structures that store pointers +//! to pinned data. For example, in an intrusive doubly-linked list, every element +//! will have pointers to its predecessor and successor in the list. Every element +//! will be pinned, because moving the elements around would invalidate the pointers. +//! Moreover, the `Drop` implemenetation of a linked list element will patch the pointers +//! of its predecessor and successor to remove itself from the list. Clearly, if an element +//! could be deallocated or overwritten without calling `drop`, the pointers into it +//! from its neighbouring elements would become invalid, breaking the data structure. +//! +//! Notice that this guarantee does *not* mean that memory does not leak! It is still +//! completely okay not to ever call `drop` on a pinned element (e.g., you can still +//! call [`mem::forget`] on a `Pin>`). What you may not do is free or reuse the storage +//! without calling `drop`. +//! +//! # `Drop` implementation +//! +//! If your type relies on pinning (for example, because it contains internal +//! references, or because you are implementing something like the intrusive +//! doubly-linked list mentioned in the previous section), you have to be careful +//! when implementing `Drop`: notice that `drop` takes `&mut self`, but this +//! will be called even if your type was previously pinned! It is as if the +//! compiler automatically called `get_unchecked_mut`. This can never cause +//! a problem in safe code because implementing a type that relies on pinning +//! requires unsafe code, but be aware that deciding to make use of pinning +//! in your type (for example by implementing some operation on `Pin<&[mut] Self>`) +//! has consequences for your `Drop` implemenetation as well. +//! +//! # Projections and Structural Pinning +//! +//! One interesting question arises when considering pinning and "container types" -- +//! types such as `Vec` or `Box` but also `RefCell`; types that serve as wrappers +//! around other types. When can such a type have a "projection" operation, an +//! operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? +//! This does not just apply to generic container types, even for normal structs +//! the question arises whether `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>` +//! is an operation that can be soundly added to the API. +//! +//! This question is closely related to the question of whether pinning is "structural": +//! when you have pinned a container, have you pinned its contents? Adding a +//! projection to the API answers that question with a "yes" by offering pinned access +//! to the contents. +//! +//! In general, as the author of a type you get to decide whether pinning is structural, and +//! whether projections are provided. However, there are a couple requirements to be +//! upheld when adding projection operations: +//! +//! 1. The container must only be [`Unpin`] if all its fields are `Unpin`. This is the default, +//! but `Unpin` is a safe trait, so as the author of the container it is your responsibility +//! *not* to add something like `impl Unpin for Container`. (Notice that adding a +//! projection operation requires unsafe code, so the fact that `Unpin` is a safe trait +//! does not break the principle that you only have to worry about any of this if +//! you use `unsafe`.) +//! 2. The destructor of the container must not move out of its argument. This is the exact +//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, +//! but the container (and hence its fields) might have been pinned before. +//! You have to guarantee that you do not move a field inside your `Drop` implementation. +//! 3. Your container type must *not* be `#[repr(packed)]`. Packed structs have their fields +//! moved around when they are dropped to properly align them, which is in conflict with +//! claiming that the fields are pinned when your struct is. +//! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: +//! you must make sure that, once your container is pinned, the memory containing the +//! content is not overwritten or deallocated without calling the content's destructors. +//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail +//! to call `drop` on all elements if one of the destructors panics. This violates the +//! `Drop` guarantee, because it can lead to elements being deallocated without +//! their destructor being called. +//! 5. You must not offer any other operations that could lead to data being moved out of +//! the fields when your type is pinned. This is usually not a concern, but can become +//! tricky when interior mutability is involved. For example, imagine `RefCell` +//! would have a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. +//! This would be catastrophic, because it is possible to move out of a pinned +//! `RefCell`: from `x: Pin<&mut RefCell>`, use `let y = x.into_ref().get_ref()` to obtain +//! `y: &RefCell`, and from there use `y.borrow_mut().deref_mut()` to obtain `&mut T` +//! which can be used with [`mem::swap`]. +//! +//! On the other hand, if you decide *not* to offer any pinning projections, you +//! are free to do `impl Unpin for Container`. In the standard library, +//! we do this for all pointer types: `Box: Unpin` holds for all `T`. +//! It makes a lot of sense to do this for pointer types, because moving the `Box` +//! does not actually move the `T`: the `Box` can be freely movable even if the `T` +//! is not. In fact, even `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, +//! for the same reason. +//! +//! [`Pin`]: struct.Pin.html +//! [`Unpin`]: ../../std/marker/trait.Unpin.html +//! [`mem::swap`]: ../../std/mem/fn.swap.html +//! [`mem::forget`]: ../../std/mem/fn.forget.html +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [drop-impl]: #drop-implementation +//! [drop-guarantee]: #drop-guarantee #![stable(feature = "pin", since = "1.33.0")] @@ -170,7 +271,12 @@ where P::Target: Unpin, { /// Construct a new `Pin` around a pointer to some data of a type that - /// implements `Unpin`. + /// implements [`Unpin`]. + /// + /// Unlike `Pin::new_unchecked`, this method is safe because the pointer + /// `P` dereferences to an [`Unpin`] type, which nullifies the pinning guarantees. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn new(pointer: P) -> Pin

{ @@ -191,8 +297,33 @@ impl Pin

{ /// not guarantee that the data `P` points to is pinned, constructing a /// `Pin

` is undefined behavior. /// + /// By using this method, you are making a promise about the `P::Deref` and + /// `P::DerefMut` implementations, if they exist. Most importantly, they + /// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref` + /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pinned pointer* + /// and expect these methods to uphold the pinning invariants. + /// Moreover, by calling this method you promise that the reference `P` + /// dereferences to will not be moved out of again; in particular, it + /// must not be possible to obtain a `&mut P::Target` and then + /// move out of that reference (using, for example [`replace`]). + /// + /// For example, the following is a *violation* of `Pin`'s safety: + /// ``` + /// use std::mem; + /// use std::pin::Pin; + /// + /// fn foo(mut a: T, b: T) { + /// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again + /// let a2 = mem::replace(&mut a, b); + /// // the address of `a` changed to `a2`'s stack slot, so `a` got moved even + /// // though we have previously pinned it! + /// } + /// ``` + /// /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used /// instead. + /// + /// [`replace`]: ../../std/mem/fn.replace.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ @@ -200,6 +331,12 @@ impl Pin

{ } /// Gets a pinned shared reference from this pinned pointer. + /// + /// This is a generic method to go from `&Pin>` to `Pin<&T>`. + /// It is safe because, as part of the contract of `Pin::new_unchecked`, + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `SmartPointer::Deref` are likewise + /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { @@ -209,13 +346,22 @@ impl Pin

{ impl Pin

{ /// Gets a pinned mutable reference from this pinned pointer. + /// + /// This is a generic method to go from `&mut Pin>` to `Pin<&mut T>`. + /// It is safe because, as part of the contract of `Pin::new_unchecked`, + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `SmartPointer::DerefMut` are likewise + /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_mut(self: &mut Pin

) -> Pin<&mut P::Target> { unsafe { Pin::new_unchecked(&mut *self.pointer) } } - /// Assign a new value to the memory behind the pinned reference. + /// Assigns a new value to the memory behind the pinned reference. + /// + /// This overwrites pinned data, but that is okay: its destructor gets + /// run before being overwritten, so no pinning guarantee is violated. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn set(self: &mut Pin

, value: P::Target) @@ -227,10 +373,12 @@ impl Pin

{ } impl<'a, T: ?Sized> Pin<&'a T> { - /// Construct a new pin by mapping the interior value. + /// Constructs a new pin by mapping the interior value. /// /// For example, if you wanted to get a `Pin` of a field of something, /// you could use this to get access to that field in one line of code. + /// However, there are several gotchas with these "pinning projections"; + /// see the [`pin` module] documentation for further details on that topic. /// /// # Safety /// @@ -238,6 +386,8 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. + /// + /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where F: FnOnce(&T) -> &U, @@ -249,11 +399,21 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// Gets a shared reference out of a pin. /// + /// This is safe because it is not possible to move out of a shared reference. + /// It may seem like there is an issue here with interior mutability: in fact, + /// it *is* possible to move a `T` out of a `&RefCell`. However, this is + /// not a problem as long as there does not also exist a `Pin<&T>` pointing + /// to the same data, and `RefCell` does not let you create a pinned reference + /// to its contents. See the discussion on ["pinning projections"] for further + /// details. + /// /// Note: `Pin` also implements `Deref` to the target, which can be used /// to access the inner value. However, `Deref` only provides a reference /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. + /// + /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn get_ref(self: Pin<&'a T>) -> &'a T { @@ -306,6 +466,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// For example, if you wanted to get a `Pin` of a field of something, /// you could use this to get access to that field in one line of code. + /// However, there are several gotchas with these "pinning projections"; + /// see the [`pin` module] documentation for further details on that topic. /// /// # Safety /// @@ -313,6 +475,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. + /// + /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where F: FnOnce(&mut T) -> &mut U, From a8d18b9560736dc3291cee253b0329b1a6ec0faf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 19:46:33 +0100 Subject: [PATCH 02/24] apply some of the feedback --- src/libcore/marker.rs | 6 ++--- src/libcore/pin.rs | 53 +++++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f9a4f75c92ae2..6def815e27dbc 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -597,11 +597,11 @@ unsafe impl Freeze for &mut T {} /// Types which can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and will consider moves +/// Since Rust itself has no notion of immovable types, and considers moves /// (e.g. through assignment or [`mem::replace`]) to always be safe, /// this trait cannot prevent types from moving by itself. /// -/// Instead it can be used to prevent moves through the type system, +/// Instead it is used to prevent moves through the type system, /// by controlling the behavior of pointers wrapped in the [`Pin`] wrapper, /// which "pin" the type in place by not allowing it to be moved out of them. /// See the [`pin module`] documentation for more information on pinning. @@ -610,7 +610,7 @@ unsafe impl Freeze for &mut T {} /// which then allows it to move out with functions such as [`mem::replace`]. /// /// `Unpin` has no consequence at all for non-pinned data. In particular, -/// [`mem::replace`] will happily move `!Unpin` data. However, you cannot use +/// [`mem::replace`] happily moves `!Unpin` data. However, you cannot use /// [`mem::replace`] on data wrapped inside a [`Pin`], and *that* is what makes /// this system work. /// diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index b8a0a93eddb77..58d2636912dac 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -32,7 +32,8 @@ //! # `Unpin` //! //! However, these restrictions are usually not necessary. Many types are always freely -//! movable, even when pinned. These types implement the [`Unpin`] auto-trait, which +//! movable, even when pinned, because they do not rely on having a stable address. +//! These types implement the [`Unpin`] auto-trait, which //! nullifies the effect of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function //! identically, as do `Pin<&mut T>` and `&mut T`. //! @@ -99,20 +100,22 @@ //! # `Drop` guarantee //! //! The purpose of pinning is to be able to rely on the placement of some data in memory. -//! To make this work, not just moving the data is restricted; deallocating or overwriting -//! it is restricted, too. Concretely, for pinned data you have to maintain the invariant -//! that *it will not get overwritten or deallocated until `drop` was called*. -//! ("Overwriting" here refers to other ways of invalidating storage, such as switching -//! from one enum variant to another.) +//! To make this work, not just moving the data is restricted; deallocating, repurposing or +//! otherwise invalidating the memory used to store the data is restricted, too. +//! Concretely, for pinned data you have to maintain the invariant +//! that *its memory will not get invalidated from the momentit gets pinned until +//! when `drop` is called*. Memory can be invalidated by deallocation, but also by +//! replacing a `Some(v)` by `None`, or calling `Vec::set_len` to "kill" some elements +//! off of a vector. //! //! The purpose of this guarantee is to allow data structures that store pointers //! to pinned data. For example, in an intrusive doubly-linked list, every element //! will have pointers to its predecessor and successor in the list. Every element //! will be pinned, because moving the elements around would invalidate the pointers. -//! Moreover, the `Drop` implemenetation of a linked list element will patch the pointers +//! Moreover, the `Drop` implementation of a linked list element will patch the pointers //! of its predecessor and successor to remove itself from the list. Clearly, if an element //! could be deallocated or overwritten without calling `drop`, the pointers into it -//! from its neighbouring elements would become invalid, breaking the data structure. +//! from its neighbouring elements would become invalid, which would break the data structure. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still //! completely okay not to ever call `drop` on a pinned element (e.g., you can still @@ -130,7 +133,9 @@ //! a problem in safe code because implementing a type that relies on pinning //! requires unsafe code, but be aware that deciding to make use of pinning //! in your type (for example by implementing some operation on `Pin<&[mut] Self>`) -//! has consequences for your `Drop` implemenetation as well. +//! has consequences for your `Drop` implementation as well: if an element +//! of your type could have been pinned, you must treat Drop as implicitly taking +//! `Pin<&mut Self>`. //! //! # Projections and Structural Pinning //! @@ -151,12 +156,12 @@ //! whether projections are provided. However, there are a couple requirements to be //! upheld when adding projection operations: //! -//! 1. The container must only be [`Unpin`] if all its fields are `Unpin`. This is the default, -//! but `Unpin` is a safe trait, so as the author of the container it is your responsibility -//! *not* to add something like `impl Unpin for Container`. (Notice that adding a -//! projection operation requires unsafe code, so the fact that `Unpin` is a safe trait -//! does not break the principle that you only have to worry about any of this if -//! you use `unsafe`.) +//! 1. The container must only be [`Unpin`] if all the fields one can project to are +//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of +//! the container it is your responsibility *not* to add something like +//! `impl Unpin for Container`. (Notice that adding a projection operation +//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break +//! the principle that you only have to worry about any of this if you use `unsafe`.) //! 2. The destructor of the container must not move out of its argument. This is the exact //! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, //! but the container (and hence its fields) might have been pinned before. @@ -293,9 +298,13 @@ impl Pin

{ /// # Safety /// /// This constructor is unsafe because we cannot guarantee that the data - /// pointed to by `pointer` is pinned. If the constructed `Pin

` does + /// pointed to by `pointer` is pinned forever. If the constructed `Pin

` does /// not guarantee that the data `P` points to is pinned, constructing a - /// `Pin

` is undefined behavior. + /// `Pin

` is unsafe. In particular, calling `Pin::new_unchecked` + /// on an `&'a mut T` is unsafe because while you are able to pin it for the given + /// lifetime `'a`, you have no control over whether it is kept pinned once `'a` + /// ends. A value, once pinned, must remain pinned forever + /// (unless its type implements `Unpin`). /// /// By using this method, you are making a promise about the `P::Deref` and /// `P::DerefMut` implementations, if they exist. Most importantly, they @@ -305,17 +314,17 @@ impl Pin

{ /// Moreover, by calling this method you promise that the reference `P` /// dereferences to will not be moved out of again; in particular, it /// must not be possible to obtain a `&mut P::Target` and then - /// move out of that reference (using, for example [`replace`]). + /// move out of that reference (using, for example [`mem::swap`]). /// /// For example, the following is a *violation* of `Pin`'s safety: /// ``` /// use std::mem; /// use std::pin::Pin; /// - /// fn foo(mut a: T, b: T) { + /// fn foo(mut a: T, mut b: T) { /// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again - /// let a2 = mem::replace(&mut a, b); - /// // the address of `a` changed to `a2`'s stack slot, so `a` got moved even + /// mem::swap(&mut a, &mut b); + /// // the address of `a` changed to `b`'s stack slot, so `a` got moved even /// // though we have previously pinned it! /// } /// ``` @@ -323,7 +332,7 @@ impl Pin

{ /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used /// instead. /// - /// [`replace`]: ../../std/mem/fn.replace.html + /// [`mem::swap`]: ../../std/mem/fn.swap.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ From a8111b7d30e8c47c339852987d304fa126f1b4a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 19:50:43 +0100 Subject: [PATCH 03/24] Apply suggestions from code review Co-Authored-By: RalfJung --- src/libcore/pin.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 58d2636912dac..ed56f76c14cfc 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -24,7 +24,7 @@ //! self-references and other special behaviors that are only possible for unmovable //! values. //! -//! It is worth reiterating that [`Pin`] does *not* change the fact that the Rust compiler +//! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler //! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being //! moved by making it impossible to call methods like [`mem::swap`] on them. @@ -39,7 +39,7 @@ //! //! Note that pinning and `Unpin` only affect the pointed-to type, not the pointer //! type itself that got wrapped in `Pin`. For example, whether or not `Box` is -//! `Unpin` has no affect on the behavior of `Pin>` (here, `T` is the +//! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the //! pointed-to type). //! //! # Examples @@ -110,8 +110,8 @@ //! //! The purpose of this guarantee is to allow data structures that store pointers //! to pinned data. For example, in an intrusive doubly-linked list, every element -//! will have pointers to its predecessor and successor in the list. Every element -//! will be pinned, because moving the elements around would invalidate the pointers. +//! has pointers to its predecessor and successor in the list. Every element +//! must also be pinned, because moving the elements around would invalidate the pointers. //! Moreover, the `Drop` implementation of a linked list element will patch the pointers //! of its predecessor and successor to remove itself from the list. Clearly, if an element //! could be deallocated or overwritten without calling `drop`, the pointers into it @@ -119,7 +119,7 @@ //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still //! completely okay not to ever call `drop` on a pinned element (e.g., you can still -//! call [`mem::forget`] on a `Pin>`). What you may not do is free or reuse the storage +//! call [`mem::forget`] on a `Pin>`). However you may *not* then free or reuse the storage //! without calling `drop`. //! //! # `Drop` implementation @@ -127,8 +127,8 @@ //! If your type relies on pinning (for example, because it contains internal //! references, or because you are implementing something like the intrusive //! doubly-linked list mentioned in the previous section), you have to be careful -//! when implementing `Drop`: notice that `drop` takes `&mut self`, but this -//! will be called even if your type was previously pinned! It is as if the +//! when implementing `Drop`. The `drop` function takes `&mut self`, but this +//! is called *even if your type was previously pinned*! It is as if the //! compiler automatically called `get_unchecked_mut`. This can never cause //! a problem in safe code because implementing a type that relies on pinning //! requires unsafe code, but be aware that deciding to make use of pinning @@ -140,7 +140,7 @@ //! # Projections and Structural Pinning //! //! One interesting question arises when considering pinning and "container types" -- -//! types such as `Vec` or `Box` but also `RefCell`; types that serve as wrappers +//! types such as `Vec`, `Box`, or `RefCell`; types that serve as wrappers //! around other types. When can such a type have a "projection" operation, an //! operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? //! This does not just apply to generic container types, even for normal structs @@ -170,7 +170,7 @@ //! moved around when they are dropped to properly align them, which is in conflict with //! claiming that the fields are pinned when your struct is. //! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: -//! you must make sure that, once your container is pinned, the memory containing the +//! once your container is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail //! to call `drop` on all elements if one of the destructors panics. This violates the @@ -186,9 +186,9 @@ //! which can be used with [`mem::swap`]. //! //! On the other hand, if you decide *not* to offer any pinning projections, you -//! are free to do `impl Unpin for Container`. In the standard library, -//! we do this for all pointer types: `Box: Unpin` holds for all `T`. -//! It makes a lot of sense to do this for pointer types, because moving the `Box` +//! are free to `impl Unpin for Container`. In the standard library, +//! this is done for all pointer types: `Box: Unpin` holds for all `T`. +//! It makes sense to do this for pointer types, because moving the `Box` //! does not actually move the `T`: the `Box` can be freely movable even if the `T` //! is not. In fact, even `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, //! for the same reason. From 442c4867365d048faec81aeb4f91b67129897795 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 20:17:20 +0100 Subject: [PATCH 04/24] separate section for doubly-linked list, reword projections intro --- src/libcore/marker.rs | 4 +-- src/libcore/pin.rs | 72 ++++++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 6def815e27dbc..86c28d4a24ae3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -611,8 +611,8 @@ unsafe impl Freeze for &mut T {} /// /// `Unpin` has no consequence at all for non-pinned data. In particular, /// [`mem::replace`] happily moves `!Unpin` data. However, you cannot use -/// [`mem::replace`] on data wrapped inside a [`Pin`], and *that* is what makes -/// this system work. +/// [`mem::replace`] on data wrapped inside a [`Pin`] because you cannot get the +/// `&mut T` you need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index ed56f76c14cfc..8317f20e0a41d 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -25,9 +25,10 @@ //! values. //! //! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler -//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being -//! moved by making it impossible to call methods like [`mem::swap`] on them. +//! moved by making it impossible to call methods like [`mem::swap`] on them. These +//! methods all need an `&mut T`, and you cannot obtain that from a `Pin`. //! //! # `Unpin` //! @@ -42,7 +43,7 @@ //! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the //! pointed-to type). //! -//! # Examples +//! # Example: Self-referential struct //! //! ```rust //! use std::pin::Pin; @@ -97,6 +98,21 @@ //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` //! +//! # Example: intrusive doubly-linked list +//! +//! In an intrusive doubly-linked list, the collection does not actually allocate +//! the memory for the elements itself. Allocation is controlled by the clients, +//! and elements can live on a stack frame that lives shorter than the collection does. +//! +//! To make this work, every element has pointers to its predecessor and successor in +//! the list. Element can only be added when they are pinned, because moving the elements +//! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked +//! list element will patch the pointers of its predecessor and successor to remove itself +//! from the list. +//! +//! To make this work, it is crucial taht we can actually rely on `drop` being called. +//! And, in fact, this is a guarantee that `Pin` provides. +//! //! # `Drop` guarantee //! //! The purpose of pinning is to be able to rely on the placement of some data in memory. @@ -108,29 +124,25 @@ //! replacing a `Some(v)` by `None`, or calling `Vec::set_len` to "kill" some elements //! off of a vector. //! -//! The purpose of this guarantee is to allow data structures that store pointers -//! to pinned data. For example, in an intrusive doubly-linked list, every element -//! has pointers to its predecessor and successor in the list. Every element -//! must also be pinned, because moving the elements around would invalidate the pointers. -//! Moreover, the `Drop` implementation of a linked list element will patch the pointers -//! of its predecessor and successor to remove itself from the list. Clearly, if an element -//! could be deallocated or overwritten without calling `drop`, the pointers into it +//! This is exactly the kind of guarantee that the intrusive linked list from the previous +//! section needs to function correctly. Clearly, if an element +//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it //! from its neighbouring elements would become invalid, which would break the data structure. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still //! completely okay not to ever call `drop` on a pinned element (e.g., you can still -//! call [`mem::forget`] on a `Pin>`). However you may *not* then free or reuse the storage -//! without calling `drop`. +//! call [`mem::forget`] on a `Pin>`). In the example of the doubly-linked +//! list, that element would just stay in the list. However you may not free or reuse the storage +//! *without calling `drop`*. //! //! # `Drop` implementation //! -//! If your type relies on pinning (for example, because it contains internal -//! references, or because you are implementing something like the intrusive -//! doubly-linked list mentioned in the previous section), you have to be careful +//! If your type uses pinning (such as the two examples above), you have to be careful //! when implementing `Drop`. The `drop` function takes `&mut self`, but this //! is called *even if your type was previously pinned*! It is as if the -//! compiler automatically called `get_unchecked_mut`. This can never cause -//! a problem in safe code because implementing a type that relies on pinning +//! compiler automatically called `get_unchecked_mut`. +//! +//! This can never cause a problem in safe code because implementing a type that relies on pinning //! requires unsafe code, but be aware that deciding to make use of pinning //! in your type (for example by implementing some operation on `Pin<&[mut] Self>`) //! has consequences for your `Drop` implementation as well: if an element @@ -139,16 +151,14 @@ //! //! # Projections and Structural Pinning //! -//! One interesting question arises when considering pinning and "container types" -- -//! types such as `Vec`, `Box`, or `RefCell`; types that serve as wrappers -//! around other types. When can such a type have a "projection" operation, an -//! operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? -//! This does not just apply to generic container types, even for normal structs -//! the question arises whether `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>` -//! is an operation that can be soundly added to the API. +//! One interesting question arises when considering the interaction of pinning and +//! the fields of a struct. When can a struct have a "projection operation", i.e., +//! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? +//! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`) +//! have an operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? //! //! This question is closely related to the question of whether pinning is "structural": -//! when you have pinned a container, have you pinned its contents? Adding a +//! when you have pinned a wrapper type, have you pinned its contents? Adding a //! projection to the API answers that question with a "yes" by offering pinned access //! to the contents. //! @@ -156,21 +166,21 @@ //! whether projections are provided. However, there are a couple requirements to be //! upheld when adding projection operations: //! -//! 1. The container must only be [`Unpin`] if all the fields one can project to are +//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of -//! the container it is your responsibility *not* to add something like +//! the wrapper it is your responsibility *not* to add something like //! `impl Unpin for Container`. (Notice that adding a projection operation //! requires unsafe code, so the fact that `Unpin` is a safe trait does not break //! the principle that you only have to worry about any of this if you use `unsafe`.) -//! 2. The destructor of the container must not move out of its argument. This is the exact +//! 2. The destructor of the wrapper must not move out of its argument. This is the exact //! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, -//! but the container (and hence its fields) might have been pinned before. +//! but the wrapper (and hence its fields) might have been pinned before. //! You have to guarantee that you do not move a field inside your `Drop` implementation. -//! 3. Your container type must *not* be `#[repr(packed)]`. Packed structs have their fields +//! 3. Your wrapper type must *not* be `#[repr(packed)]`. Packed structs have their fields //! moved around when they are dropped to properly align them, which is in conflict with //! claiming that the fields are pinned when your struct is. //! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: -//! once your container is pinned, the memory that contains the +//! once your wrapper is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail //! to call `drop` on all elements if one of the destructors panics. This violates the From 0ba99f62d1f76a82d208a9e0dab1357b626fb2bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 20:26:42 +0100 Subject: [PATCH 05/24] more work on projections and RefCell example --- src/libcore/pin.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 8317f20e0a41d..3058ae8d9db24 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -149,22 +149,23 @@ //! of your type could have been pinned, you must treat Drop as implicitly taking //! `Pin<&mut Self>`. //! +//! In particular, if your type is `#[repr(packed)]`, the compiler will automatically +//! move fields around to be able to drop them. As a consequence, you cannot use +//! pinning with a `#[repr(packed)]` type. +//! //! # Projections and Structural Pinning //! //! One interesting question arises when considering the interaction of pinning and -//! the fields of a struct. When can a struct have a "projection operation", i.e., +//! the fields of a struct. When can a struct have a "pinning projection", i.e., //! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? //! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`) //! have an operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? //! //! This question is closely related to the question of whether pinning is "structural": -//! when you have pinned a wrapper type, have you pinned its contents? Adding a +//! when you have pinned a wrapper type, have you pinned its contents? Deciding this +//! is entirely up to the author of any given type. However, adding a //! projection to the API answers that question with a "yes" by offering pinned access -//! to the contents. -//! -//! In general, as the author of a type you get to decide whether pinning is structural, and -//! whether projections are provided. However, there are a couple requirements to be -//! upheld when adding projection operations: +//! to the contents. In that case, there are a couple requirements to be upheld: //! //! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of @@ -185,15 +186,24 @@ //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail //! to call `drop` on all elements if one of the destructors panics. This violates the //! `Drop` guarantee, because it can lead to elements being deallocated without -//! their destructor being called. +//! their destructor being called. (`VecDeque` has no pinning projections, so this +//! does not cause unsoundness.) //! 5. You must not offer any other operations that could lead to data being moved out of //! the fields when your type is pinned. This is usually not a concern, but can become //! tricky when interior mutability is involved. For example, imagine `RefCell` //! would have a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. -//! This would be catastrophic, because it is possible to move out of a pinned -//! `RefCell`: from `x: Pin<&mut RefCell>`, use `let y = x.into_ref().get_ref()` to obtain -//! `y: &RefCell`, and from there use `y.borrow_mut().deref_mut()` to obtain `&mut T` -//! which can be used with [`mem::swap`]. +//! Then we could do the following: +//! ```ignore +//! fn exploit_ref_cell(rc: Pin<&mut RefCell) { +//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` +//! let rc_shr: &RefCell = rc.into_ref().get_ref(); +//! let b = rc_shr.borrow_mut(); +//! let content = &mut *b; // and here we have `&mut T` to the same data +//! } +//! ``` +//! This is catastrophic, it means we can first pin the content of the `RefCell` +//! (using `RefCell::get_pin_mut`) and then move that content using the mutable +//! reference we got later. //! //! On the other hand, if you decide *not* to offer any pinning projections, you //! are free to `impl Unpin for Container`. In the standard library, From 30403802068b920eb3b3f6ffbc1e89068de43292 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 20:50:16 +0100 Subject: [PATCH 06/24] rewrite pin module intro --- src/libcore/marker.rs | 3 ++- src/libcore/pin.rs | 48 ++++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 86c28d4a24ae3..455517c929473 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -610,7 +610,8 @@ unsafe impl Freeze for &mut T {} /// which then allows it to move out with functions such as [`mem::replace`]. /// /// `Unpin` has no consequence at all for non-pinned data. In particular, -/// [`mem::replace`] happily moves `!Unpin` data. However, you cannot use +/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not +/// just when `T: Unpin`). However, you cannot use /// [`mem::replace`] on data wrapped inside a [`Pin`] because you cannot get the /// `&mut T` you need for that, and *that* is what makes this system work. /// diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 3058ae8d9db24..2d674fe4f791e 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -2,33 +2,35 @@ //! //! It is sometimes useful to have objects that are guaranteed to not move, //! in the sense that their placement in memory does not change, and can thus be relied upon. -//! //! A prime example of such a scenario would be building self-referential structs, //! since moving an object with pointers to itself will invalidate them, //! which could cause undefined behavior. //! +//! [`Pin`] ensures that the pointee of any pointer type has a stable location in memory, +//! meaning it cannot be moved elsewhere and its memory cannot be deallocated +//! until it gets dropped. We say that the pointee is "pinned". +//! //! By default, all types in Rust are movable. Rust allows passing all types by-value, -//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and -//! moving the values they contain. In order to prevent objects from moving, they must -//! be pinned by wrapping a pointer to the data in the [`Pin`] type. -//! Doing this prohibits moving the value behind the pointer. -//! For example, `Pin>` functions much like a regular `Box`, -//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved, -//! but the value behind it cannot. -//! -//! Since data can be moved out of `&mut` and `Box` with functions such as [`mem::swap`], -//! changing the location of the underlying data, [`Pin`] prohibits accessing the -//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of -//! APIs for accessing and using the value. [`Pin`] also guarantees that no other -//! functions will move the pointed-to value. This allows for the creation of -//! self-references and other special behaviors that are only possible for unmovable -//! values. +//! and common smart-pointer types such as `Box` and `&mut` allow replacing and +//! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. +//! [`Pin`] wraps a pointer type, so `Pin>` functions much like a regular `Box` +//! (when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated). +//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin`] does not let clients actually +//! obtain a `Box` or reference to pinned data, which implies that you cannot use +//! operations such as [`mem::swap`]: +//! ``` +//! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) { +//! // `mem::swap` needs `&mut T`, but we cannot get it. +//! // We are stuck, we cannot swap the contents of these references. +//! // We could use `Pin::get_unchecked_mut`, but that is unsafe for a reason: +//! // we are not allowed to use it for moving things out of the `Pin`. +//! } +//! ``` //! //! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler //! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being -//! moved by making it impossible to call methods like [`mem::swap`] on them. These -//! methods all need an `&mut T`, and you cannot obtain that from a `Pin`. +//! moved by making it impossible to call methods like [`mem::swap`] on them. //! //! # `Unpin` //! @@ -43,7 +45,7 @@ //! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the //! pointed-to type). //! -//! # Example: Self-referential struct +//! # Example: self-referential struct //! //! ```rust //! use std::pin::Pin; @@ -119,7 +121,7 @@ //! To make this work, not just moving the data is restricted; deallocating, repurposing or //! otherwise invalidating the memory used to store the data is restricted, too. //! Concretely, for pinned data you have to maintain the invariant -//! that *its memory will not get invalidated from the momentit gets pinned until +//! that *its memory will not get invalidated from the moment it gets pinned until //! when `drop` is called*. Memory can be invalidated by deallocation, but also by //! replacing a `Some(v)` by `None`, or calling `Vec::set_len` to "kill" some elements //! off of a vector. @@ -318,13 +320,13 @@ impl Pin

{ /// # Safety /// /// This constructor is unsafe because we cannot guarantee that the data - /// pointed to by `pointer` is pinned forever. If the constructed `Pin

` does + /// pointed to by `pointer` is pinned, meaning that the data will not be moved or + /// its storage invalidated until it gets dropped. If the constructed `Pin

` does /// not guarantee that the data `P` points to is pinned, constructing a /// `Pin

` is unsafe. In particular, calling `Pin::new_unchecked` /// on an `&'a mut T` is unsafe because while you are able to pin it for the given /// lifetime `'a`, you have no control over whether it is kept pinned once `'a` - /// ends. A value, once pinned, must remain pinned forever - /// (unless its type implements `Unpin`). + /// ends. A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). /// /// By using this method, you are making a promise about the `P::Deref` and /// `P::DerefMut` implementations, if they exist. Most importantly, they From c774bc650a6b19e6ca6b970dda294ba8937a6548 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 20:54:31 +0100 Subject: [PATCH 07/24] examples --- src/libcore/pin.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 2d674fe4f791e..a142fd811ad8e 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -36,7 +36,9 @@ //! //! However, these restrictions are usually not necessary. Many types are always freely //! movable, even when pinned, because they do not rely on having a stable address. -//! These types implement the [`Unpin`] auto-trait, which +//! This includes all the basic types (`bool`, `i32` and friends, references) +//! as well as types consisting solely of these types. +//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which //! nullifies the effect of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function //! identically, as do `Pin<&mut T>` and `&mut T`. //! From c8f4efc006c24bfb427e9dd70853fb3e41584aa9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 21:12:48 +0100 Subject: [PATCH 08/24] mention interaction with Deref in intro --- src/libcore/pin.rs | 47 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index a142fd811ad8e..8acc215d01738 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -19,6 +19,7 @@ //! obtain a `Box` or reference to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: //! ``` +//! use std::pin::Pin; //! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) { //! // `mem::swap` needs `&mut T`, but we cannot get it. //! // We are stuck, we cannot swap the contents of these references. @@ -32,6 +33,15 @@ //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being //! moved by making it impossible to call methods like [`mem::swap`] on them. //! +//! [`Pin`] can be used to wrap any pointer type, and as such it interacts with +//! [`Deref`] and [`DerefMut`]. A `Pin

` where `P: Deref` should be considered +//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin>` is +//! an owned pointer to a pinned `T`, and a `Pin>` is a reference-counted +//! pointer to a pinned `T`. +//! For correctness, [`Pin`] relies on the [`Deref`] and [`DerefMut`] implementations +//! to not move out of their `self` parameter, and to only ever return a pointer +//! to pinned data when they are called on a pinned pointer. +//! //! # `Unpin` //! //! However, these restrictions are usually not necessary. Many types are always freely @@ -114,7 +124,7 @@ //! list element will patch the pointers of its predecessor and successor to remove itself //! from the list. //! -//! To make this work, it is crucial taht we can actually rely on `drop` being called. +//! To make this work, it is crucial that we can actually rely on `drop` being called. //! And, in fact, this is a guarantee that `Pin` provides. //! //! # `Drop` guarantee @@ -219,6 +229,8 @@ //! //! [`Pin`]: struct.Pin.html //! [`Unpin`]: ../../std/marker/trait.Unpin.html +//! [`Deref`]: ../../std/ops/trait.Deref.html +//! [`DerefMut`]: ../../std/ops/trait.DerefMut.html //! [`mem::swap`]: ../../std/mem/fn.swap.html //! [`mem::forget`]: ../../std/mem/fn.forget.html //! [`Box`]: ../../std/boxed/struct.Box.html @@ -319,16 +331,16 @@ impl Pin

{ /// Construct a new `Pin` around a reference to some data of a type that /// may or may not implement `Unpin`. /// + /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used + /// instead. + /// /// # Safety /// /// This constructor is unsafe because we cannot guarantee that the data /// pointed to by `pointer` is pinned, meaning that the data will not be moved or /// its storage invalidated until it gets dropped. If the constructed `Pin

` does /// not guarantee that the data `P` points to is pinned, constructing a - /// `Pin

` is unsafe. In particular, calling `Pin::new_unchecked` - /// on an `&'a mut T` is unsafe because while you are able to pin it for the given - /// lifetime `'a`, you have no control over whether it is kept pinned once `'a` - /// ends. A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). + /// `Pin

` is unsafe. In particular, /// /// By using this method, you are making a promise about the `P::Deref` and /// `P::DerefMut` implementations, if they exist. Most importantly, they @@ -340,21 +352,38 @@ impl Pin

{ /// must not be possible to obtain a `&mut P::Target` and then /// move out of that reference (using, for example [`mem::swap`]). /// - /// For example, the following is a *violation* of `Pin`'s safety: + /// For example, calling `Pin::new_unchecked` + /// on an `&'a mut T` is unsafe because while you are able to pin it for the given + /// lifetime `'a`, you have no control over whether it is kept pinned once `'a` ends: /// ``` /// use std::mem; /// use std::pin::Pin; /// - /// fn foo(mut a: T, mut b: T) { + /// fn move_pinned_ref(mut a: T, mut b: T) { /// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again /// mem::swap(&mut a, &mut b); /// // the address of `a` changed to `b`'s stack slot, so `a` got moved even /// // though we have previously pinned it! /// } /// ``` + /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). /// - /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used - /// instead. + /// Similarily, calling `Pin::new_unchecked` on a `Rc` is unsafe because there could be + /// aliases to the same data that are not subject to the pinning restrictions: + /// ``` + /// use std::rc::Rc; + /// use std::pin::Pin; + /// + /// fn move_pinned_rc(mut x: Rc) { + /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; + /// { let p: Pin<&T> = pinned.as_ref(); } // should mean the pointee can never move again + /// drop(pinned); + /// let content = Rc::get_mut(&mut x).unwrap(); + /// // Now, if `x` was the only reference, we have a mutable reference to + /// // data that we pinned above, which we could use to move it as we have + /// // seen in the previous example. + /// } + /// ``` /// /// [`mem::swap`]: ../../std/mem/fn.swap.html #[stable(feature = "pin", since = "1.33.0")] From 11e48ebb29777fe8e8e23b7a538bb43d40fbdac3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 21:18:56 +0100 Subject: [PATCH 09/24] please the mericless tidy, oh tidy --- src/libcore/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 8acc215d01738..5056005bcd773 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -207,7 +207,7 @@ //! tricky when interior mutability is involved. For example, imagine `RefCell` //! would have a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. //! Then we could do the following: -//! ```ignore +//! ```compile_fail //! fn exploit_ref_cell(rc: Pin<&mut RefCell) { //! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` //! let rc_shr: &RefCell = rc.into_ref().get_ref(); From 2c6981a315df920fa83607bc3f858e39af5abfde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 21:23:53 +0100 Subject: [PATCH 10/24] improve linked list -> drop transition --- src/libcore/pin.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 5056005bcd773..68213ab01537f 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -124,8 +124,11 @@ //! list element will patch the pointers of its predecessor and successor to remove itself //! from the list. //! -//! To make this work, it is crucial that we can actually rely on `drop` being called. -//! And, in fact, this is a guarantee that `Pin` provides. +//! Crucially, we have to be able to rely on `drop` being called. If an element +//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it +//! from its neighbouring elements would become invalid, which would break the data structure. +//! +//! This is why pinning also comes with a `drop`-related guarantee. //! //! # `Drop` guarantee //! @@ -139,9 +142,7 @@ //! off of a vector. //! //! This is exactly the kind of guarantee that the intrusive linked list from the previous -//! section needs to function correctly. Clearly, if an element -//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it -//! from its neighbouring elements would become invalid, which would break the data structure. +//! section needs to function correctly. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still //! completely okay not to ever call `drop` on a pinned element (e.g., you can still From d5df8a49d73c273aa9feb5f508e16f939af5ab34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 21:25:39 +0100 Subject: [PATCH 11/24] improve wording --- src/libcore/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 68213ab01537f..2395dce9693d1 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -205,8 +205,8 @@ //! does not cause unsoundness.) //! 5. You must not offer any other operations that could lead to data being moved out of //! the fields when your type is pinned. This is usually not a concern, but can become -//! tricky when interior mutability is involved. For example, imagine `RefCell` -//! would have a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. +//! tricky when interior mutability is involved. For example, imagine if `RefCell` +//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. //! Then we could do the following: //! ```compile_fail //! fn exploit_ref_cell(rc: Pin<&mut RefCell) { From 9c241aa7144b17aa423dde02cc6cd5f2964a73c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Feb 2019 21:27:48 +0100 Subject: [PATCH 12/24] expand Unpin example --- src/libcore/marker.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 455517c929473..38c9fe79f844b 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -618,14 +618,16 @@ unsafe impl Freeze for &mut T {} /// So this, for example, can only be done on types implementing `Unpin`: /// /// ```rust -/// use std::mem::replace; +/// use std::mem; /// use std::pin::Pin; /// /// let mut string = "this".to_string(); /// let mut pinned_string = Pin::new(&mut string); /// -/// // dereferencing the pointer mutably is only possible because String implements Unpin -/// replace(&mut *pinned_string, "other".to_string()); +/// // We need a mutable reference to call `mem::replace`. +/// // We can obtain such a reference by (implicitly) invoking `Pin::deref_mut`, +/// // but that is only possible because `String` implements `Unpin`. +/// mem::replace(&mut *pinned_string, "other".to_string()); /// ``` /// /// This trait is automatically implemented for almost every type. From c52560d788e69677826964f9f25f28687ef5c70c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Feb 2019 09:45:28 +0100 Subject: [PATCH 13/24] tweaks --- src/libcore/pin.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 2395dce9693d1..6d3c3af17f567 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -16,7 +16,7 @@ //! [`Pin`] wraps a pointer type, so `Pin>` functions much like a regular `Box` //! (when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated). //! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin`] does not let clients actually -//! obtain a `Box` or reference to pinned data, which implies that you cannot use +//! obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: //! ``` //! use std::pin::Pin; @@ -29,9 +29,10 @@ //! ``` //! //! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler -//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` //! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being -//! moved by making it impossible to call methods like [`mem::swap`] on them. +//! moved by making it impossible to call methods that require `&mut T` on them +//! (like [`mem::swap`]). //! //! [`Pin`] can be used to wrap any pointer type, and as such it interacts with //! [`Deref`] and [`DerefMut`]. A `Pin

` where `P: Deref` should be considered @@ -221,7 +222,7 @@ //! reference we got later. //! //! On the other hand, if you decide *not* to offer any pinning projections, you -//! are free to `impl Unpin for Container`. In the standard library, +//! are free to `impl Unpin for Container`. In the standard library, //! this is done for all pointer types: `Box: Unpin` holds for all `T`. //! It makes sense to do this for pointer types, because moving the `Box` //! does not actually move the `T`: the `Box` can be freely movable even if the `T` @@ -341,7 +342,7 @@ impl Pin

{ /// pointed to by `pointer` is pinned, meaning that the data will not be moved or /// its storage invalidated until it gets dropped. If the constructed `Pin

` does /// not guarantee that the data `P` points to is pinned, constructing a - /// `Pin

` is unsafe. In particular, + /// `Pin

` is unsafe. /// /// By using this method, you are making a promise about the `P::Deref` and /// `P::DerefMut` implementations, if they exist. Most importantly, they @@ -353,9 +354,9 @@ impl Pin

{ /// must not be possible to obtain a `&mut P::Target` and then /// move out of that reference (using, for example [`mem::swap`]). /// - /// For example, calling `Pin::new_unchecked` - /// on an `&'a mut T` is unsafe because while you are able to pin it for the given - /// lifetime `'a`, you have no control over whether it is kept pinned once `'a` ends: + /// For example, calling `Pin::new_unchecked` on an `&'a mut T` is unsafe because + /// while you are able to pin it for the given lifetime `'a`, you have no control + /// over whether it is kept pinned once `'a` ends: /// ``` /// use std::mem; /// use std::pin::Pin; @@ -395,10 +396,10 @@ impl Pin

{ /// Gets a pinned shared reference from this pinned pointer. /// - /// This is a generic method to go from `&Pin>` to `Pin<&T>`. + /// This is a generic method to go from `&Pin>` to `Pin<&T>`. /// It is safe because, as part of the contract of `Pin::new_unchecked`, - /// the pointee cannot move after `Pin>` got created. - /// "Malicious" implementations of `SmartPointer::Deref` are likewise + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `Pointer::Deref` are likewise /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] @@ -410,10 +411,10 @@ impl Pin

{ impl Pin

{ /// Gets a pinned mutable reference from this pinned pointer. /// - /// This is a generic method to go from `&mut Pin>` to `Pin<&mut T>`. + /// This is a generic method to go from `&mut Pin>` to `Pin<&mut T>`. /// It is safe because, as part of the contract of `Pin::new_unchecked`, - /// the pointee cannot move after `Pin>` got created. - /// "Malicious" implementations of `SmartPointer::DerefMut` are likewise + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `Pointer::DerefMut` are likewise /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] From 06b2affa7879e609bcef70d726f900d8430f6e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Feb 2019 18:28:12 +0100 Subject: [PATCH 14/24] tweak pinning projections --- src/libcore/pin.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 6d3c3af17f567..01d384f3e1938 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -174,29 +174,31 @@ //! One interesting question arises when considering the interaction of pinning and //! the fields of a struct. When can a struct have a "pinning projection", i.e., //! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? -//! In a similar vein, when can a container type (such as `Vec`, `Box`, or `RefCell`) -//! have an operation with type `fn(Pin<&[mut] Container>) -> Pin<&[mut] T>`? +//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) +//! have an operation with type `fn(Pin<&[mut] Wrapper>) -> Pin<&[mut] T>`? //! //! This question is closely related to the question of whether pinning is "structural": //! when you have pinned a wrapper type, have you pinned its contents? Deciding this -//! is entirely up to the author of any given type. However, adding a -//! projection to the API answers that question with a "yes" by offering pinned access -//! to the contents. In that case, there are a couple requirements to be upheld: +//! is entirely up to the author of any given type. For many types, both answers are reasonable +//! (e.g., there could be a version of `Vec` with structural pinning and another +//! version where the contents remain movable even when the `Vec` is pinned). +//! If pinning is not structural, the wrapper can `impl Unpin for Wrapper`. +//! If pinning is structural, the wrapper type can offer pinning projections. +//! However, structural pinning comes with a few extra requirements: //! //! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of //! the wrapper it is your responsibility *not* to add something like -//! `impl Unpin for Container`. (Notice that adding a projection operation +//! `impl Unpin for Wrapper`. (Notice that adding a projection operation //! requires unsafe code, so the fact that `Unpin` is a safe trait does not break //! the principle that you only have to worry about any of this if you use `unsafe`.) //! 2. The destructor of the wrapper must not move out of its argument. This is the exact //! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, //! but the wrapper (and hence its fields) might have been pinned before. //! You have to guarantee that you do not move a field inside your `Drop` implementation. -//! 3. Your wrapper type must *not* be `#[repr(packed)]`. Packed structs have their fields -//! moved around when they are dropped to properly align them, which is in conflict with -//! claiming that the fields are pinned when your struct is. -//! 4. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: +//! In particular, as explained previously, this means that your wrapper type must *not* +//! be `#[repr(packed)]`. +//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: //! once your wrapper is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. //! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail @@ -204,7 +206,7 @@ //! `Drop` guarantee, because it can lead to elements being deallocated without //! their destructor being called. (`VecDeque` has no pinning projections, so this //! does not cause unsoundness.) -//! 5. You must not offer any other operations that could lead to data being moved out of +//! 4. You must not offer any other operations that could lead to data being moved out of //! the fields when your type is pinned. This is usually not a concern, but can become //! tricky when interior mutability is involved. For example, imagine if `RefCell` //! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. @@ -222,13 +224,20 @@ //! reference we got later. //! //! On the other hand, if you decide *not* to offer any pinning projections, you -//! are free to `impl Unpin for Container`. In the standard library, +//! do not have to do anything. If your type also does not do any pinning itself, +//! you are free to `impl Unpin for Wrapper`. In the standard library, //! this is done for all pointer types: `Box: Unpin` holds for all `T`. //! It makes sense to do this for pointer types, because moving the `Box` //! does not actually move the `T`: the `Box` can be freely movable even if the `T` //! is not. In fact, even `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, //! for the same reason. //! +//! Another case where you might want to have a wrapper without structural pinning is when even +//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally, +//! if it is not possible to satisfy the requirements for structural pinning, it makes sense +//! to add the `impl Unpin for Wrapper` to explicitly document this fact, and to let +//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy. +//! //! [`Pin`]: struct.Pin.html //! [`Unpin`]: ../../std/marker/trait.Unpin.html //! [`Deref`]: ../../std/ops/trait.Deref.html From 1b556f16c9e6779610a8f64fe06f9947bc2cdbe8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Feb 2019 19:34:10 +0100 Subject: [PATCH 15/24] expand pinning projections --- src/libcore/pin.rs | 79 ++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 01d384f3e1938..b238c56da66fa 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -182,46 +182,49 @@ //! is entirely up to the author of any given type. For many types, both answers are reasonable //! (e.g., there could be a version of `Vec` with structural pinning and another //! version where the contents remain movable even when the `Vec` is pinned). -//! If pinning is not structural, the wrapper can `impl Unpin for Wrapper`. -//! If pinning is structural, the wrapper type can offer pinning projections. +//! If the type should have pinning projections, pinning must be structural. //! However, structural pinning comes with a few extra requirements: //! -//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are -//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of -//! the wrapper it is your responsibility *not* to add something like -//! `impl Unpin for Wrapper`. (Notice that adding a projection operation -//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break -//! the principle that you only have to worry about any of this if you use `unsafe`.) -//! 2. The destructor of the wrapper must not move out of its argument. This is the exact -//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, -//! but the wrapper (and hence its fields) might have been pinned before. -//! You have to guarantee that you do not move a field inside your `Drop` implementation. -//! In particular, as explained previously, this means that your wrapper type must *not* -//! be `#[repr(packed)]`. -//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: -//! once your wrapper is pinned, the memory that contains the -//! content is not overwritten or deallocated without calling the content's destructors. -//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail -//! to call `drop` on all elements if one of the destructors panics. This violates the -//! `Drop` guarantee, because it can lead to elements being deallocated without -//! their destructor being called. (`VecDeque` has no pinning projections, so this -//! does not cause unsoundness.) -//! 4. You must not offer any other operations that could lead to data being moved out of -//! the fields when your type is pinned. This is usually not a concern, but can become -//! tricky when interior mutability is involved. For example, imagine if `RefCell` -//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. -//! Then we could do the following: -//! ```compile_fail -//! fn exploit_ref_cell(rc: Pin<&mut RefCell) { -//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` -//! let rc_shr: &RefCell = rc.into_ref().get_ref(); -//! let b = rc_shr.borrow_mut(); -//! let content = &mut *b; // and here we have `&mut T` to the same data -//! } -//! ``` -//! This is catastrophic, it means we can first pin the content of the `RefCell` -//! (using `RefCell::get_pin_mut`) and then move that content using the mutable -//! reference we got later. +//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are +//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of +//! the wrapper it is your responsibility *not* to add something like +//! `impl Unpin for Wrapper`. (Notice that adding a projection operation +//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break +//! the principle that you only have to worry about any of this if you use `unsafe`.) +//! 2. The destructor of the wrapper must not move out of its argument. This is the exact +//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, +//! but the wrapper (and hence its fields) might have been pinned before. +//! You have to guarantee that you do not move a field inside your `Drop` implementation. +//! In particular, as explained previously, this means that your wrapper type must *not* +//! be `#[repr(packed)]`. +//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: +//! once your wrapper is pinned, the memory that contains the +//! content is not overwritten or deallocated without calling the content's destructors. +//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail +//! to call `drop` on all elements if one of the destructors panics. This violates the +//! `Drop` guarantee, because it can lead to elements being deallocated without +//! their destructor being called. (`VecDeque` has no pinning projections, so this +//! does not cause unsoundness.) +//! 4. You must not offer any other operations that could lead to data being moved out of +//! the fields when your type is pinned. For example, if the wrapper contains an +//! `Option` and there is an operation such as `fn(Pin<&mut Wrapper>) -> Option`, +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- that means +//! pinning cannot be structural. +//! +//! For a more complex example of moving data out of a pinnd type, imagine if `RefCell` +//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. +//! Then we could do the following: +//! ```compile_fail +//! fn exploit_ref_cell(rc: Pin<&mut RefCell) { +//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` +//! let rc_shr: &RefCell = rc.into_ref().get_ref(); +//! let b = rc_shr.borrow_mut(); +//! let content = &mut *b; // and here we have `&mut T` to the same data +//! } +//! ``` +//! This is catastrophic, it means we can first pin the content of the `RefCell` +//! (using `RefCell::get_pin_mut`) and then move that content using the mutable +//! reference we got later. //! //! On the other hand, if you decide *not* to offer any pinning projections, you //! do not have to do anything. If your type also does not do any pinning itself, From c9ade6a577ae92d951aecd95973fefb69cdbf08a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 09:57:29 +0100 Subject: [PATCH 16/24] more pin projections tweaking --- src/libcore/pin.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index b238c56da66fa..4245c9dcd99a8 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -177,23 +177,30 @@ //! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) //! have an operation with type `fn(Pin<&[mut] Wrapper>) -> Pin<&[mut] T>`? //! -//! This question is closely related to the question of whether pinning is "structural": -//! when you have pinned a wrapper type, have you pinned its contents? Deciding this -//! is entirely up to the author of any given type. For many types, both answers are reasonable -//! (e.g., there could be a version of `Vec` with structural pinning and another -//! version where the contents remain movable even when the `Vec` is pinned). -//! If the type should have pinning projections, pinning must be structural. +//! This question is closely related to the question of whether pinning is "structural". +//! Structural pinning means that when you have pinned a wrapper type, the contents are +//! also pinned. Structural pinning thus explains why pinning projections are correct. This means +//! that if the type should have pinning projections for some fields, pinning must be structural +//! for those fields. +//! +//! In general, deciding for which fields pinning is structural (and thus for which fields +//! pinning projections could be offered) is entirely up to the author of any given type. +//! For many types, both answers are reasonable. For example, there could be a version +//! of `Vec` with structural pinning and `get_pin`/`get_pin_mut` projections to access +//! the `Vec` elements, and another version where the contents remain movable even when +//! the `Vec` is pinned. +//! //! However, structural pinning comes with a few extra requirements: //! -//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are +//! 1. The wrapper must only be [`Unpin`] if all the structural fields are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of //! the wrapper it is your responsibility *not* to add something like //! `impl Unpin for Wrapper`. (Notice that adding a projection operation //! requires unsafe code, so the fact that `Unpin` is a safe trait does not break //! the principle that you only have to worry about any of this if you use `unsafe`.) -//! 2. The destructor of the wrapper must not move out of its argument. This is the exact -//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, -//! but the wrapper (and hence its fields) might have been pinned before. +//! 2. The destructor of the wrapper must not move structural fields out of its argument. This +//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes +//! `&mut self`, but the wrapper (and hence its fields) might have been pinned before. //! You have to guarantee that you do not move a field inside your `Drop` implementation. //! In particular, as explained previously, this means that your wrapper type must *not* //! be `#[repr(packed)]`. From 59bdb31c890adf726aec2036c3c8170c2e3a1767 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 10:21:59 +0100 Subject: [PATCH 17/24] final pin projections tweaking --- src/libcore/pin.rs | 50 +++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 4245c9dcd99a8..bcd5c65d3815c 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -177,20 +177,12 @@ //! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) //! have an operation with type `fn(Pin<&[mut] Wrapper>) -> Pin<&[mut] T>`? //! -//! This question is closely related to the question of whether pinning is "structural". -//! Structural pinning means that when you have pinned a wrapper type, the contents are -//! also pinned. Structural pinning thus explains why pinning projections are correct. This means -//! that if the type should have pinning projections for some fields, pinning must be structural -//! for those fields. +//! Having a pinning projection for some field means that pinning is "structural": +//! when the wrapper is pinned, the field must be considered pinned, too. +//! After all, the pinning projection lets us get a `Pin<&[mut] Field>`. //! -//! In general, deciding for which fields pinning is structural (and thus for which fields -//! pinning projections could be offered) is entirely up to the author of any given type. -//! For many types, both answers are reasonable. For example, there could be a version -//! of `Vec` with structural pinning and `get_pin`/`get_pin_mut` projections to access -//! the `Vec` elements, and another version where the contents remain movable even when -//! the `Vec` is pinned. -//! -//! However, structural pinning comes with a few extra requirements: +//! However, structural pinning comes with a few extra requirements, so not all +//! wrappers can be structural and hence not all wrappers can offer pinning projections: //! //! 1. The wrapper must only be [`Unpin`] if all the structural fields are //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of @@ -214,8 +206,9 @@ //! does not cause unsoundness.) //! 4. You must not offer any other operations that could lead to data being moved out of //! the fields when your type is pinned. For example, if the wrapper contains an -//! `Option` and there is an operation such as `fn(Pin<&mut Wrapper>) -> Option`, -//! that operation can be used to move a `T` out of a pinned `Wrapper` -- that means +//! `Option` and there is a `take`-like operation with type +//! `fn(Pin<&mut Wrapper>) -> Option`, +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means //! pinning cannot be structural. //! //! For a more complex example of moving data out of a pinnd type, imagine if `RefCell` @@ -233,20 +226,23 @@ //! (using `RefCell::get_pin_mut`) and then move that content using the mutable //! reference we got later. //! -//! On the other hand, if you decide *not* to offer any pinning projections, you -//! do not have to do anything. If your type also does not do any pinning itself, -//! you are free to `impl Unpin for Wrapper`. In the standard library, -//! this is done for all pointer types: `Box: Unpin` holds for all `T`. +//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, +//! and the choice is up to the author. A `Vec` with structural pinning could +//! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling +//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! +//! Nor could it allow `push`, which might reallocate and thus also move the contents. +//! A `Vec` without structural pinning could `impl Unpin for Vec`, because the contents +//! are never pinned and the `Vec` itself is fine with being moved as well. +//! +//! In the standard library, pointer types generally do not have structural pinning, +//! and thus they do not offer pinning projections. This is why `Box: Unpin` holds for all `T`. //! It makes sense to do this for pointer types, because moving the `Box` -//! does not actually move the `T`: the `Box` can be freely movable even if the `T` +//! does not actually move the `T`: the `Box` can be freely movable (aka `Unpin`) even if the `T` //! is not. In fact, even `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, -//! for the same reason. -//! -//! Another case where you might want to have a wrapper without structural pinning is when even -//! a pinned wrapper lets its contents move, e.g. with a `take`-like operation. And, finally, -//! if it is not possible to satisfy the requirements for structural pinning, it makes sense -//! to add the `impl Unpin for Wrapper` to explicitly document this fact, and to let -//! library clients benefit from the easier interaction with [`Pin`] that [`Unpin`] types enjoy. +//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves +//! can be moved without moving the pinned data. For both `Box` and `Pin>`, +//! whether the content is pinned is entirely independent of whether the pointer is +//! pinned, meaning pinning is *not* structural. //! //! [`Pin`]: struct.Pin.html //! [`Unpin`]: ../../std/marker/trait.Unpin.html From e61a8a94f7762abcd2e77a3108f766d2f5bb1185 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 21 Feb 2019 15:28:46 +0100 Subject: [PATCH 18/24] Apply suggestions from code review Co-Authored-By: RalfJung --- src/libcore/marker.rs | 4 +-- src/libcore/pin.rs | 77 ++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 38c9fe79f844b..91fd41e97b3f3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -612,7 +612,7 @@ unsafe impl Freeze for &mut T {} /// `Unpin` has no consequence at all for non-pinned data. In particular, /// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not /// just when `T: Unpin`). However, you cannot use -/// [`mem::replace`] on data wrapped inside a [`Pin`] because you cannot get the +/// [`mem::replace`] on data wrapped inside a [`Pin

`] because you cannot get the /// `&mut T` you need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: @@ -633,7 +633,7 @@ unsafe impl Freeze for &mut T {} /// This trait is automatically implemented for almost every type. /// /// [`mem::replace`]: ../../std/mem/fn.replace.html -/// [`Pin`]: ../pin/struct.Pin.html + /// [`Pin

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] #[cfg_attr(not(stage0), lang = "unpin")] diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index bcd5c65d3815c..9ce8530956546 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -6,16 +6,16 @@ //! since moving an object with pointers to itself will invalidate them, //! which could cause undefined behavior. //! -//! [`Pin`] ensures that the pointee of any pointer type has a stable location in memory, +//! A [`Pin

`] ensures that the pointee of any pointer type `P` has a stable location in memory, //! meaning it cannot be moved elsewhere and its memory cannot be deallocated //! until it gets dropped. We say that the pointee is "pinned". //! //! By default, all types in Rust are movable. Rust allows passing all types by-value, -//! and common smart-pointer types such as `Box` and `&mut` allow replacing and -//! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. -//! [`Pin`] wraps a pointer type, so `Pin>` functions much like a regular `Box` -//! (when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated). -//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin`] does not let clients actually +//! and common smart-pointer types such as `Box` and `&mut T` allow replacing and +//! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. +//! [`Pin

`] wraps a pointer type `P`, so `Pin>` functions much like a regular `Box`: +//! when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated. +//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients actually //! obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: //! ``` @@ -28,18 +28,18 @@ //! } //! ``` //! -//! It is worth reiterating that [`Pin`] does *not* change the fact that a Rust compiler -//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin` -//! prevents certain *values* (pointed to by pointers wrapped in `Pin`) from being +//! It is worth reiterating that [`Pin

`] does *not* change the fact that a Rust compiler +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin

` +//! prevents certain *values* (pointed to by pointers wrapped in `Pin

`) from being //! moved by making it impossible to call methods that require `&mut T` on them //! (like [`mem::swap`]). //! -//! [`Pin`] can be used to wrap any pointer type, and as such it interacts with +//! [`Pin

`] can be used to wrap any pointer type `P`, and as such it interacts with //! [`Deref`] and [`DerefMut`]. A `Pin

` where `P: Deref` should be considered //! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin>` is //! an owned pointer to a pinned `T`, and a `Pin>` is a reference-counted //! pointer to a pinned `T`. -//! For correctness, [`Pin`] relies on the [`Deref`] and [`DerefMut`] implementations +//! For correctness, [`Pin

`] relies on the [`Deref`] and [`DerefMut`] implementations //! to not move out of their `self` parameter, and to only ever return a pointer //! to pinned data when they are called on a pinned pointer. //! @@ -50,11 +50,11 @@ //! This includes all the basic types (`bool`, `i32` and friends, references) //! as well as types consisting solely of these types. //! Types that do not care about pinning implement the [`Unpin`] auto-trait, which -//! nullifies the effect of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function +//! cancels the effect of [`Pin

`]. For `T: Unpin`, `Pin>` and `Box` function //! identically, as do `Pin<&mut T>` and `&mut T`. //! //! Note that pinning and `Unpin` only affect the pointed-to type, not the pointer -//! type itself that got wrapped in `Pin`. For example, whether or not `Box` is +//! type `P` itself that got wrapped in `Pin

`. For example, whether or not `Box` is //! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the //! pointed-to type). //! @@ -120,7 +120,7 @@ //! and elements can live on a stack frame that lives shorter than the collection does. //! //! To make this work, every element has pointers to its predecessor and successor in -//! the list. Element can only be added when they are pinned, because moving the elements +//! the list. Elements can only be added when they are pinned, because moving the elements //! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked //! list element will patch the pointers of its predecessor and successor to remove itself //! from the list. @@ -129,17 +129,17 @@ //! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it //! from its neighbouring elements would become invalid, which would break the data structure. //! -//! This is why pinning also comes with a `drop`-related guarantee. +//! Therefore, pinning also comes with a `drop`-related guarantee. //! //! # `Drop` guarantee //! //! The purpose of pinning is to be able to rely on the placement of some data in memory. -//! To make this work, not just moving the data is restricted; deallocating, repurposing or +//! To make this work, not just moving the data is restricted; deallocating, repurposing, or //! otherwise invalidating the memory used to store the data is restricted, too. //! Concretely, for pinned data you have to maintain the invariant //! that *its memory will not get invalidated from the moment it gets pinned until //! when `drop` is called*. Memory can be invalidated by deallocation, but also by -//! replacing a `Some(v)` by `None`, or calling `Vec::set_len` to "kill" some elements +//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements //! off of a vector. //! //! This is exactly the kind of guarantee that the intrusive linked list from the previous @@ -174,7 +174,7 @@ //! One interesting question arises when considering the interaction of pinning and //! the fields of a struct. When can a struct have a "pinning projection", i.e., //! an operation with type `fn(Pin<&[mut] Struct>) -> Pin<&[mut] Field>`? -//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) +//! In a similar vein, when can a generic wrapper type (such as `Vec`, `Box`, or `RefCell`) //! have an operation with type `fn(Pin<&[mut] Wrapper>) -> Pin<&[mut] T>`? //! //! Having a pinning projection for some field means that pinning is "structural": @@ -199,7 +199,7 @@ //! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: //! once your wrapper is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. -//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail +//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail //! to call `drop` on all elements if one of the destructors panics. This violates the //! `Drop` guarantee, because it can lead to elements being deallocated without //! their destructor being called. (`VecDeque` has no pinning projections, so this @@ -208,31 +208,31 @@ //! the fields when your type is pinned. For example, if the wrapper contains an //! `Option` and there is a `take`-like operation with type //! `fn(Pin<&mut Wrapper>) -> Option`, -//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- which means //! pinning cannot be structural. //! -//! For a more complex example of moving data out of a pinnd type, imagine if `RefCell` +//! For a more complex example of moving data out of a pinned type, imagine if `RefCell` //! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. //! Then we could do the following: //! ```compile_fail //! fn exploit_ref_cell(rc: Pin<&mut RefCell) { -//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` +//! { let p = rc.as_mut().get_pin_mut(); } // Here we get pinned access to the `T`. //! let rc_shr: &RefCell = rc.into_ref().get_ref(); //! let b = rc_shr.borrow_mut(); -//! let content = &mut *b; // and here we have `&mut T` to the same data +//! let content = &mut *b; // And here we have `&mut T` to the same data. //! } //! ``` -//! This is catastrophic, it means we can first pin the content of the `RefCell` +//! This is catastrophic, it means we can first pin the content of the `RefCell` //! (using `RefCell::get_pin_mut`) and then move that content using the mutable //! reference we got later. //! -//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, -//! and the choice is up to the author. A `Vec` with structural pinning could +//! For a type like `Vec`, both possibilites (structural pinning or not) make sense, +//! and the choice is up to the author. A `Vec` with structural pinning could //! have `get_pin`/`get_pin_mut` projections. However, it could *not* allow calling -//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! +//! `pop` on a pinned `Vec` because that would move the (structurally pinned) contents! //! Nor could it allow `push`, which might reallocate and thus also move the contents. -//! A `Vec` without structural pinning could `impl Unpin for Vec`, because the contents -//! are never pinned and the `Vec` itself is fine with being moved as well. +//! A `Vec` without structural pinning could `impl Unpin for Vec`, because the contents +//! are never pinned and the `Vec` itself is fine with being moved as well. //! //! In the standard library, pointer types generally do not have structural pinning, //! and thus they do not offer pinning projections. This is why `Box: Unpin` holds for all `T`. @@ -244,13 +244,16 @@ //! whether the content is pinned is entirely independent of whether the pointer is //! pinned, meaning pinning is *not* structural. //! -//! [`Pin`]: struct.Pin.html +//! [`Pin

`]: struct.Pin.html //! [`Unpin`]: ../../std/marker/trait.Unpin.html //! [`Deref`]: ../../std/ops/trait.Deref.html //! [`DerefMut`]: ../../std/ops/trait.DerefMut.html //! [`mem::swap`]: ../../std/mem/fn.swap.html //! [`mem::forget`]: ../../std/mem/fn.forget.html -//! [`Box`]: ../../std/boxed/struct.Box.html +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len +//! [`None`]: ../../std/option/enum.Option.html#variant.None +//! [`Some(v)`]: ../../std/option/enum.Option.html#variant.Some //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee @@ -328,11 +331,11 @@ impl Pin

where P::Target: Unpin, { - /// Construct a new `Pin` around a pointer to some data of a type that + /// Construct a new `Pin

` around a pointer to some data of a type that /// implements [`Unpin`]. /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer - /// `P` dereferences to an [`Unpin`] type, which nullifies the pinning guarantees. + /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html #[stable(feature = "pin", since = "1.33.0")] @@ -345,7 +348,7 @@ where } impl Pin

{ - /// Construct a new `Pin` around a reference to some data of a type that + /// Construct a new `Pin

` around a reference to some data of a type that /// may or may not implement `Unpin`. /// /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used @@ -379,13 +382,13 @@ impl Pin

{ /// fn move_pinned_ref(mut a: T, mut b: T) { /// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again /// mem::swap(&mut a, &mut b); - /// // the address of `a` changed to `b`'s stack slot, so `a` got moved even + /// // The address of `a` changed to `b`'s stack slot, so `a` got moved even /// // though we have previously pinned it! /// } /// ``` /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). /// - /// Similarily, calling `Pin::new_unchecked` on a `Rc` is unsafe because there could be + /// Similarily, calling `Pin::new_unchecked` on an `Rc` is unsafe because there could be /// aliases to the same data that are not subject to the pinning restrictions: /// ``` /// use std::rc::Rc; @@ -482,7 +485,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// It may seem like there is an issue here with interior mutability: in fact, /// it *is* possible to move a `T` out of a `&RefCell`. However, this is /// not a problem as long as there does not also exist a `Pin<&T>` pointing - /// to the same data, and `RefCell` does not let you create a pinned reference + /// to the same data, and `RefCell` does not let you create a pinned reference /// to its contents. See the discussion on ["pinning projections"] for further /// details. /// From 2db0e0d65c0215b1a5d232860c0c2ad3ec8c37d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 15:30:31 +0100 Subject: [PATCH 19/24] tweaks and fix weird space --- src/libcore/marker.rs | 2 +- src/libcore/pin.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 91fd41e97b3f3..255d09a0417e3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -633,7 +633,7 @@ unsafe impl Freeze for &mut T {} /// This trait is automatically implemented for almost every type. /// /// [`mem::replace`]: ../../std/mem/fn.replace.html - /// [`Pin

`]: ../pin/struct.Pin.html +/// [`Pin

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] #[cfg_attr(not(stage0), lang = "unpin")] diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 9ce8530956546..e045702bca235 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -53,7 +53,7 @@ //! cancels the effect of [`Pin

`]. For `T: Unpin`, `Pin>` and `Box` function //! identically, as do `Pin<&mut T>` and `&mut T`. //! -//! Note that pinning and `Unpin` only affect the pointed-to type, not the pointer +//! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer //! type `P` itself that got wrapped in `Pin

`. For example, whether or not `Box` is //! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the //! pointed-to type). From bcc55e5e79585baba752b5016a905dbb3d1b1ef8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 15:31:09 +0100 Subject: [PATCH 20/24] we only list some examples of basic types --- src/libcore/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index e045702bca235..d4446faed7b33 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -47,7 +47,7 @@ //! //! However, these restrictions are usually not necessary. Many types are always freely //! movable, even when pinned, because they do not rely on having a stable address. -//! This includes all the basic types (`bool`, `i32` and friends, references) +//! This includes all the basic types (like `bool`, `i32`, references) //! as well as types consisting solely of these types. //! Types that do not care about pinning implement the [`Unpin`] auto-trait, which //! cancels the effect of [`Pin

`]. For `T: Unpin`, `Pin>` and `Box` function From 6b880074734e1916f6347d46de28fa44b1f1bae2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 15:33:55 +0100 Subject: [PATCH 21/24] explain unsafe --- src/libcore/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index d4446faed7b33..697c352550fdb 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -359,8 +359,8 @@ impl Pin

{ /// This constructor is unsafe because we cannot guarantee that the data /// pointed to by `pointer` is pinned, meaning that the data will not be moved or /// its storage invalidated until it gets dropped. If the constructed `Pin

` does - /// not guarantee that the data `P` points to is pinned, constructing a - /// `Pin

` is unsafe. + /// not guarantee that the data `P` points to is pinned, that is a violation of + /// the API contract and may lead to undefined behavior in later (safe) operations. /// /// By using this method, you are making a promise about the `P::Deref` and /// `P::DerefMut` implementations, if they exist. Most importantly, they From 32a9614a4e466d5b27227948c9500743066628c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 16:05:49 +0100 Subject: [PATCH 22/24] this is for you, tidy --- src/libcore/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 697c352550fdb..ff10c33681d22 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -15,8 +15,8 @@ //! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. //! [`Pin

`] wraps a pointer type `P`, so `Pin>` functions much like a regular `Box`: //! when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated. -//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients actually -//! obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use +//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients +//! actually obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: //! ``` //! use std::pin::Pin; From 811af4289cf58d8ac5a501ade19058d2a86fc170 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 17:18:18 +0100 Subject: [PATCH 23/24] fix link --- src/libcore/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 255d09a0417e3..29606cb19038f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -602,7 +602,7 @@ unsafe impl Freeze for &mut T {} /// this trait cannot prevent types from moving by itself. /// /// Instead it is used to prevent moves through the type system, -/// by controlling the behavior of pointers wrapped in the [`Pin`] wrapper, +/// by controlling the behavior of pointers `P` wrapped in the [`Pin

`] wrapper, /// which "pin" the type in place by not allowing it to be moved out of them. /// See the [`pin module`] documentation for more information on pinning. /// From 497439c199131ba65f03c116aec2e9cd5a7e63ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 23:13:49 +0100 Subject: [PATCH 24/24] take a bit more space for new_unchecked examples --- src/libcore/pin.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index ff10c33681d22..f9f20dcea9e2e 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -380,10 +380,13 @@ impl Pin

{ /// use std::pin::Pin; /// /// fn move_pinned_ref(mut a: T, mut b: T) { - /// unsafe { let p = Pin::new_unchecked(&mut a); } // should mean `a` can never move again + /// unsafe { + /// let p: Pin<&mut T> = Pin::new_unchecked(&mut a); + /// // This should mean the pointee `a` can never move again. + /// } /// mem::swap(&mut a, &mut b); /// // The address of `a` changed to `b`'s stack slot, so `a` got moved even - /// // though we have previously pinned it! + /// // though we have previously pinned it! We have violated the pinning API contract. /// } /// ``` /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). @@ -396,12 +399,15 @@ impl Pin

{ /// /// fn move_pinned_rc(mut x: Rc) { /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; - /// { let p: Pin<&T> = pinned.as_ref(); } // should mean the pointee can never move again + /// { + /// let p: Pin<&T> = pinned.as_ref(); + /// // This should mean the pointee can never move again. + /// } /// drop(pinned); /// let content = Rc::get_mut(&mut x).unwrap(); /// // Now, if `x` was the only reference, we have a mutable reference to /// // data that we pinned above, which we could use to move it as we have - /// // seen in the previous example. + /// // seen in the previous example. We have violated the pinning API contract. /// } /// ``` ///