Auto merge of #27215 - pnkfelix:fsk-placer-take-5-just-in, r=nikomatsakis
Macro desugaring of `in PLACE { BLOCK }` into "simpler" expressions following the in-development "Placer" protocol.
Includes Placer API that one can override to integrate support for `in` into one's own type. (See [RFC 809].)
[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md
Part of #22181
Replaced PR #26180.
Turns on the `in PLACE { BLOCK }` syntax, while leaving in support for the old `box (PLACE) EXPR` syntax (since we need to support that at least until we have a snapshot with support for `in PLACE { BLOCK }`.
(Note that we are not 100% committed to the `in PLACE { BLOCK }` syntax. In particular I still want to play around with some other alternatives. Still, I want to get the fundamental framework for the protocol landed so we can play with implementing it for non `Box` types.)
----
Also, this PR leaves out support for desugaring-based `box EXPR`. We will hopefully land that in the future, but for the short term there are type-inference issues injected by that change that we want to resolve separately.
This commit is contained in:
@@ -184,6 +184,14 @@ extern "rust-intrinsic" {
|
||||
/// elements.
|
||||
pub fn size_of<T>() -> usize;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Moves a value to an uninitialized memory location.
|
||||
///
|
||||
/// Drop glue is not run on the destination.
|
||||
pub fn move_val_init<T>(dst: *mut T, src: T);
|
||||
|
||||
// SNAP d4432b3
|
||||
#[cfg(stage0)]
|
||||
/// Moves a value to an uninitialized memory location.
|
||||
///
|
||||
/// Drop glue is not run on the destination.
|
||||
|
||||
@@ -1266,3 +1266,120 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
|
||||
|
||||
// *const T -> *const U
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
|
||||
|
||||
/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions
|
||||
/// that allocate an intermediate "place" that holds uninitialized
|
||||
/// state. The desugaring evaluates EXPR, and writes the result at
|
||||
/// the address returned by the `pointer` method of this trait.
|
||||
///
|
||||
/// A `Place` can be thought of as a special representation for a
|
||||
/// hypothetical `&uninit` reference (which Rust cannot currently
|
||||
/// express directly). That is, it represents a pointer to
|
||||
/// uninitialized storage.
|
||||
///
|
||||
/// The client is responsible for two steps: First, initializing the
|
||||
/// payload (it can access its address via `pointer`). Second,
|
||||
/// converting the agent to an instance of the owning pointer, via the
|
||||
/// appropriate `finalize` method (see the `InPlace`.
|
||||
///
|
||||
/// If evaluating EXPR fails, then the destructor for the
|
||||
/// implementation of Place to clean up any intermediate state
|
||||
/// (e.g. deallocate box storage, pop a stack, etc).
|
||||
#[unstable(feature = "placement_new_protocol")]
|
||||
pub trait Place<Data: ?Sized> {
|
||||
/// Returns the address where the input value will be written.
|
||||
/// Note that the data at this address is generally uninitialized,
|
||||
/// and thus one should use `ptr::write` for initializing it.
|
||||
fn pointer(&mut self) -> *mut Data;
|
||||
}
|
||||
|
||||
/// Interface to implementations of `in (PLACE) EXPR`.
|
||||
///
|
||||
/// `in (PLACE) EXPR` effectively desugars into:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let p = PLACE;
|
||||
/// let mut place = Placer::make_place(p);
|
||||
/// let raw_place = Place::pointer(&mut place);
|
||||
/// let value = EXPR;
|
||||
/// unsafe {
|
||||
/// std::ptr::write(raw_place, value);
|
||||
/// InPlace::finalize(place)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`;
|
||||
/// if the type of `PLACE` is `P`, then the final type of the whole
|
||||
/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed`
|
||||
/// traits).
|
||||
///
|
||||
/// Values for types implementing this trait usually are transient
|
||||
/// intermediate values (e.g. the return value of `Vec::emplace_back`)
|
||||
/// or `Copy`, since the `make_place` method takes `self` by value.
|
||||
#[unstable(feature = "placement_new_protocol")]
|
||||
pub trait Placer<Data: ?Sized> {
|
||||
/// `Place` is the intermedate agent guarding the
|
||||
/// uninitialized state for `Data`.
|
||||
type Place: InPlace<Data>;
|
||||
|
||||
/// Creates a fresh place from `self`.
|
||||
fn make_place(self) -> Self::Place;
|
||||
}
|
||||
|
||||
/// Specialization of `Place` trait supporting `in (PLACE) EXPR`.
|
||||
#[unstable(feature = "placement_new_protocol")]
|
||||
pub trait InPlace<Data: ?Sized>: Place<Data> {
|
||||
/// `Owner` is the type of the end value of `in (PLACE) EXPR`
|
||||
///
|
||||
/// Note that when `in (PLACE) EXPR` is solely used for
|
||||
/// side-effecting an existing data-structure,
|
||||
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
|
||||
/// information at all (e.g. it can be the unit type `()` in that
|
||||
/// case).
|
||||
type Owner;
|
||||
|
||||
/// Converts self into the final value, shifting
|
||||
/// deallocation/cleanup responsibilities (if any remain), over to
|
||||
/// the returned instance of `Owner` and forgetting self.
|
||||
unsafe fn finalize(self) -> Self::Owner;
|
||||
}
|
||||
|
||||
/// Core trait for the `box EXPR` form.
|
||||
///
|
||||
/// `box EXPR` effectively desugars into:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let mut place = BoxPlace::make_place();
|
||||
/// let raw_place = Place::pointer(&mut place);
|
||||
/// let value = EXPR;
|
||||
/// unsafe {
|
||||
/// ::std::ptr::write(raw_place, value);
|
||||
/// Boxed::finalize(place)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The type of `box EXPR` is supplied from its surrounding
|
||||
/// context; in the above expansion, the result type `T` is used
|
||||
/// to determine which implementation of `Boxed` to use, and that
|
||||
/// `<T as Boxed>` in turn dictates determines which
|
||||
/// implementation of `BoxPlace` to use, namely:
|
||||
/// `<<T as Boxed>::Place as BoxPlace>`.
|
||||
#[unstable(feature = "placement_new_protocol")]
|
||||
pub trait Boxed {
|
||||
/// The kind of data that is stored in this kind of box.
|
||||
type Data; /* (`Data` unused b/c cannot yet express below bound.) */
|
||||
/// The place that will negotiate the storage of the data.
|
||||
type Place: BoxPlace<Self::Data>;
|
||||
|
||||
/// Converts filled place into final owning value, shifting
|
||||
/// deallocation/cleanup responsibilities (if any remain), over to
|
||||
/// returned instance of `Self` and forgetting `filled`.
|
||||
unsafe fn finalize(filled: Self::Place) -> Self;
|
||||
}
|
||||
|
||||
/// Specialization of `Place` trait supporting `box EXPR`.
|
||||
#[unstable(feature = "placement_new_protocol")]
|
||||
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
|
||||
/// Creates a globally fresh place.
|
||||
fn make_place() -> Self;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user