summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-07-24 10:12:20 +0000
committerbors <bors@rust-lang.org>2015-07-24 10:12:20 +0000
commit9413a926fcfc88c46ea04534508284a822e1109f (patch)
tree191a7b86544a79d59a31a1c2080dc2bc9b5f4aa3 /src/libcore
parent607f74df2ad6b6fb32ce5b862a9e48a8c4afdad2 (diff)
parentd066a7b5069ff857a5bffe7cb5168fe63158144f (diff)
downloadrust-9413a926fcfc88c46ea04534508284a822e1109f.tar.gz
rust-9413a926fcfc88c46ea04534508284a822e1109f.zip
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.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/intrinsics.rs8
-rw-r--r--src/libcore/ops.rs117
2 files changed, 125 insertions, 0 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index ef022179772..1d466895f2c 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -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.
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index c2a9b8c8308..2ea42011a5c 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -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;
+}