From 93e590a93bd2f28a3b8e885fa96e2dbb5b003afb Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Fri, 26 Sep 2014 17:42:38 +0200
Subject: [PATCH 1/7] Desugar `box (<place_expr>) <value_expr>` to `Placer`
 protocol.

Note that this narrows desugaring to only be when actual placer is
provided; `box <value_expr>` and `box () <value_expr>` both still fall
through to the `mk_unary(UnUniq, _)` path.

Many more compile-fail tests would need updating if we were not
restricting desugaring to `box` with explicit placer.
---
 src/liballoc/boxed.rs                   |  81 +++++++++++-
 src/liballoc/lib.rs                     |   7 +
 src/libcore/ops.rs                      |  64 +++++++++
 src/librustc/middle/cfg/construct.rs    |   5 +-
 src/librustc/middle/expr_use_visitor.rs |   2 +-
 src/librustc/middle/liveness.rs         |   3 +-
 src/librustc/middle/trans/debuginfo.rs  |   2 +-
 src/librustc/middle/ty.rs               |   3 +-
 src/librustc/middle/typeck/check/mod.rs |   8 +-
 src/libsyntax/ast.rs                    |   2 +-
 src/libsyntax/ext/expand.rs             | 169 ++++++++++++++++++++++++
 src/libsyntax/fold.rs                   |   2 +-
 src/libsyntax/parse/parser.rs           |   6 +-
 src/libsyntax/print/pprust.rs           |   2 +-
 src/libsyntax/visit.rs                  |   2 +-
 src/test/compile-fail/issue-14084.rs    |   5 +-
 16 files changed, 342 insertions(+), 21 deletions(-)

diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 168d0daeb3845..d4a716d8bb11e 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -10,13 +10,17 @@
 
 //! A unique pointer type.
 
+use heap;
+
 use core::any::{Any, AnyRefExt};
 use core::clone::Clone;
 use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
 use core::default::Default;
 use core::fmt;
 use core::intrinsics;
+use core::kinds::Sized;
 use core::mem;
+use core::ops::{Drop, Placer, PlacementAgent};
 use core::option::Option;
 use core::raw::TraitObject;
 use core::result::{Ok, Err, Result};
@@ -36,22 +40,91 @@ use core::result::{Ok, Err, Result};
 /// ```
 #[lang = "exchange_heap"]
 #[experimental = "may be renamed; uncertain about custom allocator design"]
-pub static HEAP: () = ();
+pub static HEAP: ExchangeHeapSingleton =
+    ExchangeHeapSingleton { _force_singleton: () };
+
+/// This the singleton type used solely for `boxed::HEAP`.
+pub struct ExchangeHeapSingleton { _force_singleton: () }
 
 /// A type that represents a uniquely-owned value.
 #[lang = "owned_box"]
 #[unstable = "custom allocators will add an additional type parameter (with default)"]
-pub struct Box<T>(*mut T);
+pub struct Box<Sized? T>(*mut T);
+
+/// `IntermediateBox` represents uninitialized backing storage for `Box`.
+///
+/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
+/// introducing a separate `IntermediateBox<T>`; but then you hit
+/// issues when you e.g. attempt to destructure an instance of `Box`,
+/// since it is a lang item and so it gets special handling by the
+/// compiler.  Easier just to make this parallel type for now.
+///
+/// FIXME (pnkfelix): Currently the `box` protocol only supports
+/// creating instances of sized types. This IntermediateBox is
+/// designed to be forward-compatible with a future protocol that
+/// supports creating instances of unsized types; that is why the type
+/// parameter has the `Sized?` generalization marker, and is also why
+/// this carries an explicit size. However, it probably does not need
+/// to carry the explicit alignment; that is just a work-around for
+/// the fact that the `align_of` intrinsic currently requires the
+/// input type to be Sized (which I do not think is strictly
+/// necessary).
+pub struct IntermediateBox<Sized? T>{
+    ptr: *mut u8,
+    size: uint,
+    align: uint,
+}
+
+impl<T> Placer<T, Box<T>, IntermediateBox<T>> for ExchangeHeapSingleton {
+    fn make_place(&self) -> IntermediateBox<T> {
+        let size = mem::size_of::<T>();
+        let align = mem::align_of::<T>();
+
+        let p = if size == 0 {
+            heap::EMPTY as *mut u8
+        } else {
+            unsafe {
+                heap::allocate(size, align)
+            }
+        };
+
+        IntermediateBox { ptr: p, size: size, align: align }
+    }
+}
+
+impl<Sized? T> PlacementAgent<T, Box<T>> for IntermediateBox<T> {
+    unsafe fn pointer(&self) -> *mut T {
+        self.ptr as *mut T
+    }
+    unsafe fn finalize(self) -> Box<T> {
+        let p = self.ptr as *mut T;
+        mem::forget(self);
+        mem::transmute(p)
+    }
+}
+
+#[unsafe_destructor]
+impl<Sized? T> Drop for IntermediateBox<T> {
+    fn drop(&mut self) {
+        if self.size > 0 {
+            unsafe {
+                heap::deallocate(self.ptr as *mut u8, self.size, self.align)
+            }
+        }
+    }
+}
 
 impl<T: Default> Default for Box<T> {
-    fn default() -> Box<T> { box Default::default() }
+    fn default() -> Box<T> {
+        box (HEAP) { let t : T = Default::default(); t }
+    }
 }
 
 #[unstable]
 impl<T: Clone> Clone for Box<T> {
     /// Returns a copy of the owned box.
     #[inline]
-    fn clone(&self) -> Box<T> { box {(**self).clone()} }
+    fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} }
 
     /// Performs copy-assignment from `source` by reusing the existing allocation.
     #[inline]
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 2df9a585fec99..de2f606a0a059 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -94,8 +94,13 @@ pub mod libc_heap;
 
 // Primitive types using the heaps above
 
+// Need to conditionally define the mod from `boxed.rs` to avoid
+// duplicating the lang-items when building in test cfg; but also need
+// to allow code to have `use boxed::HEAP;` declaration.
 #[cfg(not(test))]
 pub mod boxed;
+#[cfg(test)]
+mod boxed { pub use std::boxed::HEAP; }
 pub mod arc;
 pub mod rc;
 
@@ -126,5 +131,7 @@ pub fn fixme_14344_be_sure_to_link_to_collections() {}
 #[doc(hidden)]
 mod std {
     pub use core::fmt;
+    pub use core::ops;
     pub use core::option;
+    pub use core::ptr;
 }
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index f6e3e7f61cf93..22ea7a76c336d 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -901,3 +901,67 @@ def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
 def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
 def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
 def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
+
+/// Interface to user-implementations of `box (<placer_expr>) <value_expr>`.
+///
+/// `box (P) V` effectively expands into:
+/// `{ let b = P.make_place(); let v = V; unsafe { b.pointer() = v; b.finalize() } }`
+pub trait Placer<Sized? Data, Owner, Interim: PlacementAgent<Data, Owner>> {
+    /// Allocates a place for the data to live, returning an
+    /// intermediate agent to negotiate ownership.
+    fn make_place(&self) -> Interim;
+}
+
+/// Some free functions called by expansions of `box <value_expr>` and
+/// `box (<place>) <value_expr>`.
+pub mod placer {
+    use kinds::Sized;
+    use ops::{Placer, PlacementAgent};
+
+    /// The first argument, `<place>` in `box (<place>) <value>`, must
+    /// implement `Placer`.
+    pub fn parenthesized_input_to_box_must_be_placer<Sized? Data, Owner, A, P>(p: P) -> P
+        where A:PlacementAgent<Data, Owner>,
+              P:Placer<Data, Owner, A>+Sized {
+        p
+    }
+
+    /// Work-around for lack of UFCS: the `box (<place>) <value>`
+    /// syntax expands into calls to the three free functions below in
+    /// order to avoid requiring (or expanding into) declarations like
+    /// `use std::ops::Placer;` and `use std::ops::PlacementAgent;`
+
+    /// Calls `p.make_place()` as work-around for lack of UFCS.
+    pub fn make_place<Sized? Data, Owner, A, P>(p: &P) -> A
+        where A:PlacementAgent<Data, Owner>,
+              P:Placer<Data, Owner, A> {
+        p.make_place()
+    }
+
+    /// Calls `a.pointer()` as work-around for lack of UFCS.
+    pub unsafe fn pointer<Sized? Data, Owner, A>(a: &A) -> *mut Data
+        where A:PlacementAgent<Data, Owner> {
+        a.pointer()
+    }
+
+    /// Calls `a.finalize()` as work-around for lack of UFCS.
+    pub unsafe fn finalize<Sized? Data, Owner, A>(a: A) -> Owner
+        where A:PlacementAgent<Data, Owner> {
+        a.finalize()
+    }
+}
+
+/// Helper trait for expansion of `box (P) V`.
+///
+/// We force all implementers to implement `Drop`, since in the majority of
+/// cases, leaving out a user-defined drop is a bug for these values.
+///
+/// See also `Placer`.
+pub trait PlacementAgent<Sized? Data, Owner> : Drop {
+    /// Returns a pointer to the offset in the place where the data lives.
+    unsafe fn pointer(&self) -> *mut Data;
+
+    /// Converts this intermediate agent into owning pointer for the data,
+    /// forgetting self in the process.
+    unsafe fn finalize(self) -> Owner;
+}
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 4b55a0b26098b..7ba295f92efa8 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -461,15 +461,14 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
             }
 
+            ast::ExprBox(Some(ref l), ref r) |
             ast::ExprIndex(ref l, ref r) |
             ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier
                 self.straightline(expr, pred, [l, r].iter().map(|&e| &**e))
             }
 
-            ast::ExprBox(ref p, ref e) => {
-                self.straightline(expr, pred, [p, e].iter().map(|&e| &**e))
-            }
 
+            ast::ExprBox(None, ref e) |
             ast::ExprAddrOf(_, ref e) |
             ast::ExprCast(ref e, _) |
             ast::ExprUnary(_, ref e) |
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index c413eb67a73ac..8d191fa127fd2 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -501,7 +501,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
             }
 
             ast::ExprBox(ref place, ref base) => {
-                self.consume_expr(&**place);
+                place.as_ref().map(|e|self.consume_expr(&**e));
                 self.consume_expr(&**base);
             }
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 63e9a80adc61a..6a76131731bb9 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1186,7 +1186,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           ExprIndex(ref l, ref r) |
           ExprBinary(_, ref l, ref r) |
-          ExprBox(ref l, ref r) => {
+          ExprBox(Some(ref l), ref r) => {
             let r_succ = self.propagate_through_expr(&**r, succ);
             self.propagate_through_expr(&**l, r_succ)
           }
@@ -1197,6 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_expr(&**e1, succ)
           }
 
+          ExprBox(None, ref e) |
           ExprAddrOf(_, ref e) |
           ExprCast(ref e, _) |
           ExprUnary(_, ref e) |
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index f2c965924cd19..9effbdc3af723 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -3420,7 +3420,7 @@ fn populate_scope_map(cx: &CrateContext,
                 walk_expr(cx, &**sub_exp, scope_stack, scope_map),
 
             ast::ExprBox(ref place, ref sub_expr) => {
-                walk_expr(cx, &**place, scope_stack, scope_map);
+                place.as_ref().map(|e|walk_expr(cx, &**e, scope_stack, scope_map));
                 walk_expr(cx, &**sub_expr, scope_stack, scope_map);
             }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index a7ce93279bd83..a185e830c4c7e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3705,12 +3705,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
 
         ast::ExprLit(_) | // Note: LitStr is carved out above
         ast::ExprUnary(..) |
+        ast::ExprBox(None, _) |
         ast::ExprAddrOf(..) |
         ast::ExprBinary(..) => {
             RvalueDatumExpr
         }
 
-        ast::ExprBox(ref place, _) => {
+        ast::ExprBox(Some(ref place), _) => {
             // Special case `Box<T>` for now:
             let definition = match tcx.def_map.borrow().find(&place.id) {
                 Some(&def) => def,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 5f7b31e573ade..8e25ecc8c1319 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3723,15 +3723,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
     let id = expr.id;
     match expr.node {
       ast::ExprBox(ref place, ref subexpr) => {
-          check_expr(fcx, &**place);
+          place.as_ref().map(|e|check_expr(fcx, &**e));
           check_expr(fcx, &**subexpr);
 
           let mut checked = false;
-          match place.node {
+          place.as_ref().map(|e| match e.node {
               ast::ExprPath(ref path) => {
                   // FIXME(pcwalton): For now we hardcode the two permissible
                   // places: the exchange heap and the managed heap.
-                  let definition = lookup_def(fcx, path.span, place.id);
+                  let definition = lookup_def(fcx, path.span, e.id);
                   let def_id = definition.def_id();
                   let referent_ty = fcx.expr_ty(&**subexpr);
                   if tcx.lang_items.exchange_heap() == Some(def_id) {
@@ -3740,7 +3740,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                   }
               }
               _ => {}
-          }
+          });
 
           if !checked {
               span_err!(tcx.sess, expr.span, E0066,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index df63d161eec35..5e2f9f591c5e3 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -510,7 +510,7 @@ pub struct Expr {
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum Expr_ {
     /// First expr is the place; second expr is the value.
-    ExprBox(P<Expr>, P<Expr>),
+    ExprBox(Option<P<Expr>>, P<Expr>),
     ExprVec(Vec<P<Expr>>),
     ExprCall(P<Expr>, Vec<P<Expr>>),
     ExprMethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>),
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 39b710e0d5725..5c9663012bce5 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -22,6 +22,7 @@ use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use ext::base::*;
 use fold;
 use fold::*;
+use owned_slice::OwnedSlice;
 use parse;
 use parse::token::{fresh_mark, fresh_name, intern};
 use parse::token;
@@ -61,6 +62,174 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             })
         }
 
+        // FIXME (pnkfelix): The code below is designed to handle
+        // *both* `box <value>` and `box (<place>) <value>`, but for
+        // now the desugaring will only apply to the latter.
+        //
+        // The motivation is mostly to make it easier to land without
+        // having to update many tests that are not expecting to deal
+        // with the desugared form in terms of (1.) error messages and
+        // (2.) the dependencies on `::std::ops::placer`.
+        //
+        // To re-enable the more general code paths, just change the
+        // `Some(place)` in this binding to `maybe_place`, and revise
+        // the `let maybe_place = ...` to call `fld.fold_expr(place)`
+        // directly.
+
+        // Desugar ExprBox: `box (<place_expr>) <value_expr>`
+        ast::ExprBox(Some(place), value_expr) => {
+            let value_span = value_expr.span;
+            let place_span = place.span;
+
+            let maybe_place : Option<P<ast::Expr>> = Some(fld.fold_expr(place));
+            let value_expr = fld.fold_expr(value_expr);
+
+            // Desugar `box (<place_expr>) <value_expr>` to something
+            // analogous to:
+            //
+            // {
+            //     fn force_placer<D,T,I,P>(p: P) -> P where P : Placer<D,T,I> { p }
+            //     let place = force_placer(<place_expr>);
+            //     let agent = place.make_place();
+            //     let value = <value_expr>
+            //     unsafe {
+            //         ptr::write(agent.pointer(), value);
+            //         agent.finalize()
+            //     }
+            // }
+            //
+            // The intention of `fn force_placer` is to provide better
+            // error messages when the `<place_expr>` does not
+            // implement the Placer trait.  Likewise, the actual
+            // expansion below actually calls free functions in
+            // `std::ops::placer`, in order to avoid the need for UFCS
+            // (and also to hopefully produce better error messags).
+
+            let place_ident = token::gensym_ident("place1");
+            let agent_ident = token::gensym_ident("agent");
+            let value_ident = token::gensym_ident("value");
+
+            let place = fld.cx.expr_ident(span, place_ident);
+            let agent = fld.cx.expr_ident(span, agent_ident);
+            let value = fld.cx.expr_ident(span, value_ident);
+
+            fn mk_path_for_idents(span: Span,
+                                  idents: &[&'static str]) -> ast::Path {
+                let segments : Vec<ast::PathSegment> =
+                    idents.iter().map(|s| {
+                        ast::PathSegment {
+                            identifier: token::str_to_ident(*s),
+                            lifetimes: vec![],
+                            types: OwnedSlice::empty(),
+                        }
+                    }).collect();
+                ast::Path {
+                    span: span, global: true, segments: segments,
+                }
+            }
+
+            // NOTE: clients using `box <expr>` short-hand need to
+            // either use `libstd` or must make their own local
+            //
+            // ```
+            // mod std { mod boxed { pub use ... as HEAP; }
+            //           mod ops { mod placer { ... } }
+            //           mod ptr { pub use ... as write; } }
+            // ```
+            //
+            // as appropriate.
+
+            let boxed_heap = || -> ast::Path {
+                let idents = ["std", "boxed", "HEAP"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let _force_placer = || -> ast::Path {
+                let idents = ["std", "ops", "placer",
+                              "parenthesized_input_to_box_must_be_placer"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let placer_make_place = || -> ast::Path {
+                let idents = ["std", "ops", "placer", "make_place"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let placer_pointer = || -> ast::Path {
+                let idents = ["std", "ops", "placer", "pointer"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let placer_finalize = || -> ast::Path {
+                let idents = ["std", "ops", "placer", "finalize"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let ptr_write = || -> ast::Path {
+                let idents = ["std", "ptr", "write"];
+                mk_path_for_idents(place_span, idents)
+            };
+
+            let make_call = |f: ast::Path, args: Vec<P<ast::Expr>>| -> P<ast::Expr> {
+                fld.cx.expr_call(span, fld.cx.expr_path(f), args)
+            };
+
+            let stmt_let = |span, bind, expr| fld.cx.stmt_let(span, false, bind, expr);
+
+            // FIXME RE place2 (pnkfelix): This attempt to encode an
+            // assertion that the <place-expr> implements `Placer` is
+            // not working yet; gets type-inference failure with
+            // message "error: unable to infer enough type information
+            // to locate the impl of the trait `core::kinds::Sized`
+            // for the type `<generic #9>`; type annotations required"
+            //
+            // So for now pnkfelix is leaving out the `force_placer`
+            // invocation, which means we may get different type
+            // inference failures that are hard to diagnose, but at
+            // least we will be able to get something running.
+
+            fld.cx.expr_block(fld.cx.block_all(
+                span,
+                vec![],
+                vec![
+                    // let place1 = <place_expr>; // default of ::std::boxed::HEAP
+                    stmt_let(place_span, place_ident, match maybe_place {
+                        Some(place_expr) => place_expr,
+                        None => fld.cx.expr_path(boxed_heap()),
+                    }),
+
+                    // See "FIXME RE place2" above.
+                    //
+                    // // let place2 = force_placer(place1);
+                    // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])),
+
+                    // let agent = placer::make_place(&place1);
+                    stmt_let(place_span, agent_ident, make_call(placer_make_place(),
+                                                                vec![fld.cx.expr_addr_of(place_span, place)])),
+
+                    // let value = <value_expr>;
+                    stmt_let(value_span, value_ident, value_expr),
+                    ],
+
+                // unsafe { ptr::write(placer::pointer(&agent), value);
+                //          placer::finalizer(agent) }
+                {
+                    let call_agent_ptr = make_call(placer_pointer(),
+                                                   vec![fld.cx.expr_addr_of(place_span, agent.clone())]);
+                    let call_ptr_write =
+                        StmtSemi(make_call(ptr_write(), vec![call_agent_ptr, value]),
+                                 ast::DUMMY_NODE_ID);
+                    Some(fld.cx.expr_block(P(ast::Block {
+                        view_items: vec![],
+                        stmts: vec![P(codemap::respan(value_span, call_ptr_write))],
+                        expr: Some(make_call(placer_finalize(), vec![agent])),
+                        id: ast::DUMMY_NODE_ID,
+                        rules: ast::UnsafeBlock(ast::CompilerGenerated),
+                        span: span,
+                    })))
+                }))
+        }
+
         ast::ExprWhile(cond, body, opt_ident) => {
             let cond = fld.fold_expr(cond);
             let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5e29167bf1a29..4596675362b21 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1168,7 +1168,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
         id: folder.new_id(id),
         node: match node {
             ExprBox(p, e) => {
-                ExprBox(folder.fold_expr(p), folder.fold_expr(e))
+                ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e))
             }
             ExprVec(exprs) => {
                 ExprVec(exprs.move_map(|x| folder.fold_expr(x)))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ed806ad803ab1..45073f7469f7a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2749,7 +2749,7 @@ impl<'a> Parser<'a> {
                     self.expect(&token::RPAREN);
                     let subexpression = self.parse_prefix_expr();
                     hi = subexpression.span.hi;
-                    ex = ExprBox(place, subexpression);
+                    ex = ExprBox(Some(place), subexpression);
                     return self.mk_expr(lo, hi, ex);
                 }
             }
@@ -2757,6 +2757,10 @@ impl<'a> Parser<'a> {
             // Otherwise, we use the unique pointer default.
             let subexpression = self.parse_prefix_expr();
             hi = subexpression.span.hi;
+
+            // FIXME (pnkfelix): After working out kinks with box
+            // desugaring, should be `ExprBox(None, subexpression)`
+            // instead.
             ex = self.mk_unary(UnUniq, subexpression);
           }
           _ => return self.parse_dot_or_call_expr()
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index cdcbeedddb239..448d2902056ae 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1400,7 +1400,7 @@ impl<'a> State<'a> {
             ast::ExprBox(ref p, ref e) => {
                 try!(word(&mut self.s, "box"));
                 try!(word(&mut self.s, "("));
-                try!(self.print_expr(&**p));
+                try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
                 try!(self.word_space(")"));
                 try!(self.print_expr(&**e));
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 00377a324a768..588dedd8839b9 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -672,7 +672,7 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) {
 pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
     match expression.node {
         ExprBox(ref place, ref subexpression) => {
-            visitor.visit_expr(&**place);
+            place.as_ref().map(|e|visitor.visit_expr(&**e));
             visitor.visit_expr(&**subexpression)
         }
         ExprVec(ref subexpressions) => {
diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs
index d247bf0913c3b..352b9f703ae00 100644
--- a/src/test/compile-fail/issue-14084.rs
+++ b/src/test/compile-fail/issue-14084.rs
@@ -10,5 +10,8 @@
 
 fn main() {
     box ( () ) 0;
-    //~^ ERROR: only the managed heap and exchange heap are currently supported
+    //~^ ERROR: is not implemented for the type `()`
+
+    // FIXME (pnkfelix): can we improve on the expected error (or
+    // better still, improve the actual error itself)?
 }

From 53865bcdf80afcb7f3a032c7797ec7756f8e7400 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Wed, 22 Oct 2014 17:10:27 +0200
Subject: [PATCH 2/7] Add tests for user-defined use of `box (<place>)
 <value>`.

---
 .../placement-box-user-defined-fail.rs        | 120 +++++++++++
 .../run-pass/placement-box-user-defined.rs    | 196 ++++++++++++++++++
 2 files changed, 316 insertions(+)
 create mode 100644 src/test/run-fail/placement-box-user-defined-fail.rs
 create mode 100644 src/test/run-pass/placement-box-user-defined.rs

diff --git a/src/test/run-fail/placement-box-user-defined-fail.rs b/src/test/run-fail/placement-box-user-defined-fail.rs
new file mode 100644
index 0000000000000..7e63cfa6a2410
--- /dev/null
+++ b/src/test/run-fail/placement-box-user-defined-fail.rs
@@ -0,0 +1,120 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:the right fail
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use std::kinds::marker;
+use std::mem;
+use std::ops::{Placer,PlacementAgent};
+
+#[deriving(PartialEq, Eq, Show)]
+enum Entry {
+    DropInterim(uint),
+    FinalizeInterim(uint),
+    DropAtom(&'static str),
+}
+
+type Record = Vec<Entry>;
+
+struct Atom {
+    record: *mut Record,
+    name: &'static str,
+}
+
+struct InterimAtom {
+    record: *mut Record,
+    name_todo: &'static str,
+    my_count: uint,
+}
+
+struct AtomPool {
+    record: *mut Record,
+    total_count: Cell<uint>,
+}
+
+struct ExpectDropRecord<'a> {
+    record: *mut Record,
+    expect: &'a [Entry],
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for ExpectDropRecord<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            assert_eq!((*self.record).as_slice(), self.expect);
+        }
+    }
+}
+
+pub fn main() {
+    let mut record = vec![];
+    let record = &mut record as *mut Record;
+    let pool = &AtomPool::new(record);
+
+    let expect = [FinalizeInterim(0),
+                  DropInterim(1),
+                  DropAtom("hello")];
+    let expect = ExpectDropRecord { record: record, expect: expect };
+    inner(pool);
+}
+
+fn inner(pool: &AtomPool) {
+    let a = box (pool) "hello";
+    let b = box (pool) { fail!("the right fail"); "world" };
+    let c = box (pool) { fail!("we never"); "get here " };
+}
+
+impl AtomPool {
+    fn new(record: *mut Record) -> AtomPool {
+        AtomPool { record: record, total_count: Cell::new(0) }
+    }
+}
+
+impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a AtomPool {
+    fn make_place(&self) -> InterimAtom {
+        let c = self.total_count.get();
+        self.total_count.set(c + 1);
+        InterimAtom {
+            record: self.record,
+            name_todo: "",
+            my_count: c,
+        }
+    }
+}
+
+impl PlacementAgent<&'static str, Atom> for InterimAtom {
+    unsafe fn pointer(&self) -> *mut &'static str {
+        mem::transmute(&self.name_todo)
+    }
+    unsafe fn finalize(self) -> Atom {
+        unsafe { (*self.record).push(FinalizeInterim(self.my_count)) }
+        let ret = Atom {
+            record: self.record,
+            name: self.name_todo,
+        };
+        mem::forget(self);
+        ret
+    }
+}
+
+impl Drop for InterimAtom {
+    fn drop(&mut self) {
+        unsafe { (*self.record).push(DropInterim(self.my_count)) }
+    }
+}
+
+impl Drop for Atom {
+    fn drop(&mut self) {
+        unsafe { (*self.record).push(DropAtom(self.name)) }
+    }
+}
diff --git a/src/test/run-pass/placement-box-user-defined.rs b/src/test/run-pass/placement-box-user-defined.rs
new file mode 100644
index 0000000000000..70acb8897e52f
--- /dev/null
+++ b/src/test/run-pass/placement-box-user-defined.rs
@@ -0,0 +1,196 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test illustrates use of `box (<place>) <value>` syntax to
+// allocate and initialize user-defined smart-pointer types.
+//
+// (Note that the code itself is somewhat naive, especially since you
+//  wouldn't want to box f32*4 in this way in practice.)
+
+use std::cell::Cell;
+use std::kinds::marker;
+use std::mem;
+use std::ops::{Placer,PlacementAgent};
+
+pub fn main() {
+    let ref arena = PoolFloat4::new();
+    inner(arena);
+
+    let expecting = [true, true, true, true, true];
+    assert_eq!(arena.avail_snapshot().as_slice(), expecting.as_slice());
+}
+
+fn inner(arena: &PoolFloat4) {
+    let avail = || -> Vec<bool> { arena.avail_snapshot() };
+
+    let expecting = [true, true, true, true, true];
+    assert_eq!(avail().as_slice(), expecting.as_slice());
+
+    let a: BoxFloat4 = box (arena) [1.0, 2.0, 3.0, 4.0];
+
+    let expecting = [false, true, true, true, true];
+    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
+
+    let mut order = vec![];
+
+    let b: BoxFloat4 = box ({ order.push("arena"); arena }) [
+        { order.push("10.0"); 10.0 },
+        { order.push("20.0"); 20.0 },
+        { order.push("30.0"); 30.0 },
+        { order.push("40.0"); 40.0 },
+        ];
+
+    let expecting = [false, false, true, true, true];
+    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
+    assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
+    assert_eq!(order, vec!["arena", "10.0", "20.0", "30.0", "40.0"]);
+
+    {
+        let c: BoxFloat4 = box (arena) [100.0, 200.0, 300.0, 400.0];
+        let expecting = [false, false, false, true, true];
+        assert_eq!(avail().as_slice(), expecting.as_slice());
+        assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
+        assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
+        assert_eq!(c.xyzw(), (100.0, 200.0, 300.0, 400.0));
+    }
+
+    let expecting = [false, false, true, true, true];
+    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
+    assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
+}
+
+struct BoxFloat4 {
+    arena: *mut PoolFloat4,
+    f4: *mut f32,
+}
+
+impl BoxFloat4 {
+    fn x(&self) -> f32 { unsafe { *self.f4.offset(0) } }
+    fn y(&self) -> f32 { unsafe { *self.f4.offset(1) } }
+    fn z(&self) -> f32 { unsafe { *self.f4.offset(2) } }
+    fn w(&self) -> f32 { unsafe { *self.f4.offset(3) } }
+
+    fn xyzw(&self) -> (f32,f32,f32,f32) {
+        (self.x(), self.y(), self.z(), self.w())
+    }
+}
+
+struct InterimBoxFloat4 {
+    arena: *mut PoolFloat4,
+    f4: *mut f32,
+}
+
+struct PoolFloat4 {
+    pool: [f32, ..20],
+    avail: [Cell<bool>, ..5],
+    no_copy: marker::NoCopy,
+}
+
+impl PoolFloat4 {
+    fn new() -> PoolFloat4 {
+        let ret = PoolFloat4 {
+            pool: [0.0, ..20],
+            avail: [Cell::new(true),
+                    Cell::new(true),
+                    Cell::new(true),
+                    Cell::new(true),
+                    Cell::new(true),
+                    ],
+            no_copy: marker::NoCopy,
+        };
+
+        ret
+    }
+
+    fn avail_snapshot(&self) -> Vec<bool> {
+        self.avail.iter().map(|c|c.get()).collect()
+    }
+
+    fn first_avail(&self) -> Option<uint> {
+        for i in range(0u, 5) {
+            if self.avail[i].get() {
+                return Some(i);
+            }
+        }
+        None
+    }
+
+    fn find_entry(&self, p: *mut f32) -> Option<uint> {
+        for i in range(0u, 5) {
+            let ptr : &f32 = &self.pool[i*4];
+            let cand: *mut f32 = unsafe { mem::transmute(ptr) };
+            if p == cand {
+                return Some(i);
+            }
+        }
+        None
+    }
+
+    unsafe fn mark_freed(&mut self, p: *mut f32) {
+        let i = match self.find_entry(p) {
+            Some(i) => i,
+            None => {
+                // (avoiding fail! in drop)
+                println!("interim internal consistency failure.");
+                return;
+            }
+        };
+        self.avail[i].set(true);
+        assert_eq!(self.avail[i].get(), true);
+    }
+}
+
+impl<'a> Placer<[f32, ..4], BoxFloat4, InterimBoxFloat4>
+    for &'a PoolFloat4 {
+    fn make_place(&self) -> InterimBoxFloat4 {
+        let i = self.first_avail()
+            .unwrap_or_else(|| fail!("exhausted all spots"));
+
+        self.avail[i].set(false);
+        assert_eq!(self.avail[i].get(), false);
+        unsafe {
+            InterimBoxFloat4 { arena: mem::transmute(*self),
+                               f4: mem::transmute(&self.pool[i*4]) }
+        }
+    }
+}
+
+impl PlacementAgent<[f32, ..4], BoxFloat4> for InterimBoxFloat4 {
+    unsafe fn pointer(&self) -> *mut [f32, ..4] {
+        self.f4 as *mut [f32, ..4]
+    }
+
+    unsafe fn finalize(self) -> BoxFloat4 {
+        let ret = BoxFloat4 { arena: self.arena, f4: self.f4 };
+        mem::forget(self);
+        ret
+    }
+}
+
+impl Drop for InterimBoxFloat4 {
+    fn drop(&mut self) {
+        unsafe {
+            let a : &mut PoolFloat4 = mem::transmute(self.arena);
+            a.mark_freed(self.f4);
+        }
+    }
+}
+
+impl Drop for BoxFloat4 {
+    fn drop(&mut self) {
+        unsafe {
+            let a : &mut PoolFloat4 = mem::transmute(self.arena);
+            a.mark_freed(self.f4);
+        }
+    }
+}

From 040cf98262bd13d74cc48c5553959e5897be8f88 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Wed, 22 Oct 2014 17:43:14 +0200
Subject: [PATCH 3/7] placate `make tidy`.

---
 src/libsyntax/ext/expand.rs | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5c9663012bce5..02ac733f4312e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -204,8 +204,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
                     // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])),
 
                     // let agent = placer::make_place(&place1);
-                    stmt_let(place_span, agent_ident, make_call(placer_make_place(),
-                                                                vec![fld.cx.expr_addr_of(place_span, place)])),
+                    stmt_let(place_span, agent_ident,
+                             make_call(placer_make_place(),
+                                       vec![fld.cx.expr_addr_of(place_span,
+                                                                place)])),
 
                     // let value = <value_expr>;
                     stmt_let(value_span, value_ident, value_expr),
@@ -214,14 +216,20 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
                 // unsafe { ptr::write(placer::pointer(&agent), value);
                 //          placer::finalizer(agent) }
                 {
-                    let call_agent_ptr = make_call(placer_pointer(),
-                                                   vec![fld.cx.expr_addr_of(place_span, agent.clone())]);
+                    let call_agent_ptr =
+                        make_call(placer_pointer(),
+                                  vec![fld.cx.expr_addr_of(place_span,
+                                                           agent.clone())]);
                     let call_ptr_write =
-                        StmtSemi(make_call(ptr_write(), vec![call_agent_ptr, value]),
+                        StmtSemi(make_call(ptr_write(),
+                                           vec![call_agent_ptr, value]),
                                  ast::DUMMY_NODE_ID);
+                    let call_ptr_write =
+                        codemap::respan(value_span, call_ptr_write);
+
                     Some(fld.cx.expr_block(P(ast::Block {
                         view_items: vec![],
-                        stmts: vec![P(codemap::respan(value_span, call_ptr_write))],
+                        stmts: vec![P(call_ptr_write)],
                         expr: Some(make_call(placer_finalize(), vec![agent])),
                         id: ast::DUMMY_NODE_ID,
                         rules: ast::UnsafeBlock(ast::CompilerGenerated),

From 452ecab4d80bd06f3e862a226109166c5dc8369a Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Thu, 23 Oct 2014 18:07:46 +0200
Subject: [PATCH 4/7] Revise the protocol to avoid inadvertantly moving the
 Placer.

---
 src/libcore/ops.rs          |  2 +-
 src/libsyntax/ext/expand.rs | 23 +++++++++++------------
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 22ea7a76c336d..679bb20e58ce4 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -920,7 +920,7 @@ pub mod placer {
 
     /// The first argument, `<place>` in `box (<place>) <value>`, must
     /// implement `Placer`.
-    pub fn parenthesized_input_to_box_must_be_placer<Sized? Data, Owner, A, P>(p: P) -> P
+    pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a P) -> &'a P
         where A:PlacementAgent<Data, Owner>,
               P:Placer<Data, Owner, A>+Sized {
         p
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 02ac733f4312e..29e80fa335921 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -88,8 +88,8 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             // analogous to:
             //
             // {
-            //     fn force_placer<D,T,I,P>(p: P) -> P where P : Placer<D,T,I> { p }
-            //     let place = force_placer(<place_expr>);
+            //     fn force_placer<'a, D,T,I,P>(p: &'a P) -> &'a P where P : Placer<D,T,I> { p }
+            //     let place = force_placer(& <place_expr> );
             //     let agent = place.make_place();
             //     let value = <value_expr>
             //     unsafe {
@@ -192,22 +192,21 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
                 span,
                 vec![],
                 vec![
-                    // let place1 = <place_expr>; // default of ::std::boxed::HEAP
-                    stmt_let(place_span, place_ident, match maybe_place {
-                        Some(place_expr) => place_expr,
-                        None => fld.cx.expr_path(boxed_heap()),
-                    }),
+                    // let place1 = & <place_expr> ; // default of ::std::boxed::HEAP
+                    stmt_let(place_span,
+                             place_ident,
+                             fld.cx.expr_addr_of(place_span, match maybe_place {
+                                 Some(place_expr) => place_expr,
+                                 None => fld.cx.expr_path(boxed_heap()),
+                             })),
 
                     // See "FIXME RE place2" above.
                     //
                     // // let place2 = force_placer(place1);
                     // stmt_let(place_span, place2_ident, make_call(force_placer(), vec![place])),
 
-                    // let agent = placer::make_place(&place1);
-                    stmt_let(place_span, agent_ident,
-                             make_call(placer_make_place(),
-                                       vec![fld.cx.expr_addr_of(place_span,
-                                                                place)])),
+                    // let agent = placer::make_place(place1);
+                    stmt_let(place_span, agent_ident, make_call(placer_make_place(), vec![place])),
 
                     // let value = <value_expr>;
                     stmt_let(value_span, value_ident, value_expr),

From 731e9bac8b8f7688b2d698c4ccfeae82fb3c9a13 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Thu, 23 Oct 2014 18:08:26 +0200
Subject: [PATCH 5/7] A new test: illustrate use of box with emplacing into
 back of Vec.

---
 .../run-pass/placement-box-emplace-back.rs    | 86 +++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 src/test/run-pass/placement-box-emplace-back.rs

diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs
new file mode 100644
index 0000000000000..d2ce863227db2
--- /dev/null
+++ b/src/test/run-pass/placement-box-emplace-back.rs
@@ -0,0 +1,86 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test illustrates use of `box (<place>) <value>` syntax to
+// initialize into the end of a Vec<T>.
+
+#![feature(unsafe_destructor)]
+
+use std::cell::{UnsafeCell};
+use std::ops::{Placer,PlacementAgent};
+
+struct EmplaceBack<'a, T:'a> {
+    vec: &'a mut Vec<T>,
+}
+
+pub fn main() {
+    let mut v : Vec<[f32, ..4]> = vec![];
+    v.push([10., 20., 30., 40.]);
+    v.push([11., 21., 31., 41.]);
+    let mut pv = EmplaceBack { vec: &mut v };
+    let () = box (pv) [12., 22., 32., 42.];
+    let v = pv.vec;
+    assert!(same_contents(
+        v.as_slice(),
+        [[10., 20., 30., 40.],
+         [11., 21., 31., 41.],
+         [12., 22., 32., 42.],
+         ]));
+}
+
+fn same_contents<T:PartialEq>(a: &[[T, ..4]], b: &[[T, ..4]]) -> bool {
+    assert_eq!(a.len(), b.len());
+    let len = a.len();
+    for i in range(0, len) {
+        if a[i].as_slice() != b[i].as_slice() {
+            return false;
+        }
+    }
+    return true;
+}
+
+struct EmplaceBackAgent<T> {
+    vec_ptr: *mut Vec<T>,
+    offset: uint,
+}
+
+impl<'a, T> Placer<T, (), EmplaceBackAgent<T>> for EmplaceBack<'a, T> {
+    fn make_place(&self) -> EmplaceBackAgent<T> {
+        let len = self.vec.len();
+        let v = self.vec as *mut Vec<T>;
+        unsafe {
+            (*v).reserve_additional(1);
+        }
+        EmplaceBackAgent { vec_ptr: v, offset: len }
+    }
+}
+
+impl<T> PlacementAgent<T, ()> for EmplaceBackAgent<T> {
+    unsafe fn pointer(&self) -> *mut T {
+        assert_eq!((*self.vec_ptr).len(), self.offset);
+        assert!(self.offset < (*self.vec_ptr).capacity());
+        (*self.vec_ptr).as_mut_ptr().offset(self.offset.to_int().unwrap())
+    }
+
+    unsafe fn finalize(self) -> () {
+        assert_eq!((*self.vec_ptr).len(), self.offset);
+        assert!(self.offset < (*self.vec_ptr).capacity());
+        (*self.vec_ptr).set_len(self.offset + 1);
+    }
+}
+
+#[unsafe_destructor]
+impl<T> Drop for EmplaceBackAgent<T> {
+    fn drop(&mut self) {
+        // Do not need to do anything; all `make_place` did was ensure
+        // we had some space reserved, it did not touch the state of
+        // the vector itself.
+    }
+}

From b2939849a92ad8a76e5f630d08774c3f87cb4672 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Thu, 23 Oct 2014 18:24:32 +0200
Subject: [PATCH 6/7] Simplify example so that `emplace_back` is "just" an
 additional method on Vec.

---
 .../run-pass/placement-box-emplace-back.rs    | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs
index d2ce863227db2..7cf96231b8678 100644
--- a/src/test/run-pass/placement-box-emplace-back.rs
+++ b/src/test/run-pass/placement-box-emplace-back.rs
@@ -16,17 +16,26 @@
 use std::cell::{UnsafeCell};
 use std::ops::{Placer,PlacementAgent};
 
-struct EmplaceBack<'a, T:'a> {
+struct EmplaceBackPlacer<'a, T:'a> {
     vec: &'a mut Vec<T>,
 }
 
+trait EmplaceBack<'a, T> {
+    fn emplace_back(&'a mut self) -> EmplaceBackPlacer<'a, T>;
+}
+
+impl<'a, T:'a> EmplaceBack<'a, T> for Vec<T> {
+    fn emplace_back(&'a mut self) -> EmplaceBackPlacer<'a, T> {
+        EmplaceBackPlacer { vec: self }
+    }
+}
+
 pub fn main() {
     let mut v : Vec<[f32, ..4]> = vec![];
     v.push([10., 20., 30., 40.]);
     v.push([11., 21., 31., 41.]);
-    let mut pv = EmplaceBack { vec: &mut v };
-    let () = box (pv) [12., 22., 32., 42.];
-    let v = pv.vec;
+    let () = // (Explicitly showing `box` returns `()` here.)
+        box (v.emplace_back()) [12., 22., 32., 42.];
     assert!(same_contents(
         v.as_slice(),
         [[10., 20., 30., 40.],
@@ -51,7 +60,7 @@ struct EmplaceBackAgent<T> {
     offset: uint,
 }
 
-impl<'a, T> Placer<T, (), EmplaceBackAgent<T>> for EmplaceBack<'a, T> {
+impl<'a, T> Placer<T, (), EmplaceBackAgent<T>> for EmplaceBackPlacer<'a, T> {
     fn make_place(&self) -> EmplaceBackAgent<T> {
         let len = self.vec.len();
         let v = self.vec as *mut Vec<T>;

From 3b47ea4f3349fb4d1aed63b5045f17cf805dd0fe Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Fri, 24 Oct 2014 11:05:11 +0200
Subject: [PATCH 7/7] Switched Placer API to take `&mut self` rather than
 `&self`.

This made some things cleaner (e.g. I got to get rid of the `Cell` in
the `AtomPool` example). But it also highlights some weaknesses in my
current expansion -- namely, my use of top-level functions rather than
methods means that I am currently forced to make sure I have the right
level of borrowing in the PLACER input in `box (PLACER) EXPR`. I will
look into my options there -- it may be that the right thing is just
to switch to method invocations.
---
 src/liballoc/boxed.rs                         |  4 +-
 src/libcore/ops.rs                            |  6 +--
 src/libsyntax/ext/expand.rs                   |  8 +--
 .../placement-box-user-defined-fail.rs        | 16 +++---
 .../run-pass/placement-box-emplace-back.rs    |  2 +-
 .../run-pass/placement-box-user-defined.rs    | 53 +++++++++----------
 6 files changed, 42 insertions(+), 47 deletions(-)

diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index d4a716d8bb11e..8ef004c3def23 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -40,7 +40,7 @@ use core::result::{Ok, Err, Result};
 /// ```
 #[lang = "exchange_heap"]
 #[experimental = "may be renamed; uncertain about custom allocator design"]
-pub static HEAP: ExchangeHeapSingleton =
+pub const HEAP: ExchangeHeapSingleton =
     ExchangeHeapSingleton { _force_singleton: () };
 
 /// This the singleton type used solely for `boxed::HEAP`.
@@ -76,7 +76,7 @@ pub struct IntermediateBox<Sized? T>{
 }
 
 impl<T> Placer<T, Box<T>, IntermediateBox<T>> for ExchangeHeapSingleton {
-    fn make_place(&self) -> IntermediateBox<T> {
+    fn make_place(&mut self) -> IntermediateBox<T> {
         let size = mem::size_of::<T>();
         let align = mem::align_of::<T>();
 
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 679bb20e58ce4..8bd55b57ea377 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -909,7 +909,7 @@ def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
 pub trait Placer<Sized? Data, Owner, Interim: PlacementAgent<Data, Owner>> {
     /// Allocates a place for the data to live, returning an
     /// intermediate agent to negotiate ownership.
-    fn make_place(&self) -> Interim;
+    fn make_place(&mut self) -> Interim;
 }
 
 /// Some free functions called by expansions of `box <value_expr>` and
@@ -920,7 +920,7 @@ pub mod placer {
 
     /// The first argument, `<place>` in `box (<place>) <value>`, must
     /// implement `Placer`.
-    pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a P) -> &'a P
+    pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a mut P) -> &'a mut P
         where A:PlacementAgent<Data, Owner>,
               P:Placer<Data, Owner, A>+Sized {
         p
@@ -932,7 +932,7 @@ pub mod placer {
     /// `use std::ops::Placer;` and `use std::ops::PlacementAgent;`
 
     /// Calls `p.make_place()` as work-around for lack of UFCS.
-    pub fn make_place<Sized? Data, Owner, A, P>(p: &P) -> A
+    pub fn make_place<Sized? Data, Owner, A, P>(p: &mut P) -> A
         where A:PlacementAgent<Data, Owner>,
               P:Placer<Data, Owner, A> {
         p.make_place()
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 29e80fa335921..78702e0b847b2 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -89,7 +89,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             //
             // {
             //     fn force_placer<'a, D,T,I,P>(p: &'a P) -> &'a P where P : Placer<D,T,I> { p }
-            //     let place = force_placer(& <place_expr> );
+            //     let place = force_placer(&mut <place_expr> );
             //     let agent = place.make_place();
             //     let value = <value_expr>
             //     unsafe {
@@ -177,7 +177,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             let stmt_let = |span, bind, expr| fld.cx.stmt_let(span, false, bind, expr);
 
             // FIXME RE place2 (pnkfelix): This attempt to encode an
-            // assertion that the <place-expr> implements `Placer` is
+            // assertion that the <place_expr> implements `Placer` is
             // not working yet; gets type-inference failure with
             // message "error: unable to infer enough type information
             // to locate the impl of the trait `core::kinds::Sized`
@@ -192,10 +192,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
                 span,
                 vec![],
                 vec![
-                    // let place1 = & <place_expr> ; // default of ::std::boxed::HEAP
+                    // let place1 = &mut <place_expr> ; // default of ::std::boxed::HEAP
                     stmt_let(place_span,
                              place_ident,
-                             fld.cx.expr_addr_of(place_span, match maybe_place {
+                             fld.cx.expr_mut_addr_of(place_span, match maybe_place {
                                  Some(place_expr) => place_expr,
                                  None => fld.cx.expr_path(boxed_heap()),
                              })),
diff --git a/src/test/run-fail/placement-box-user-defined-fail.rs b/src/test/run-fail/placement-box-user-defined-fail.rs
index 7e63cfa6a2410..3505eb4f57c3e 100644
--- a/src/test/run-fail/placement-box-user-defined-fail.rs
+++ b/src/test/run-fail/placement-box-user-defined-fail.rs
@@ -39,7 +39,7 @@ struct InterimAtom {
 
 struct AtomPool {
     record: *mut Record,
-    total_count: Cell<uint>,
+    total_count: uint,
 }
 
 struct ExpectDropRecord<'a> {
@@ -59,7 +59,7 @@ impl<'a> Drop for ExpectDropRecord<'a> {
 pub fn main() {
     let mut record = vec![];
     let record = &mut record as *mut Record;
-    let pool = &AtomPool::new(record);
+    let mut pool = &mut AtomPool::new(record);
 
     let expect = [FinalizeInterim(0),
                   DropInterim(1),
@@ -68,7 +68,7 @@ pub fn main() {
     inner(pool);
 }
 
-fn inner(pool: &AtomPool) {
+fn inner(mut pool: &mut AtomPool) {
     let a = box (pool) "hello";
     let b = box (pool) { fail!("the right fail"); "world" };
     let c = box (pool) { fail!("we never"); "get here " };
@@ -76,14 +76,14 @@ fn inner(pool: &AtomPool) {
 
 impl AtomPool {
     fn new(record: *mut Record) -> AtomPool {
-        AtomPool { record: record, total_count: Cell::new(0) }
+        AtomPool { record: record, total_count: 0 }
     }
 }
 
-impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a AtomPool {
-    fn make_place(&self) -> InterimAtom {
-        let c = self.total_count.get();
-        self.total_count.set(c + 1);
+impl<'a> Placer<&'static str, Atom, InterimAtom> for &'a mut AtomPool {
+    fn make_place(&mut self) -> InterimAtom {
+        let c = self.total_count;
+        self.total_count = c + 1;
         InterimAtom {
             record: self.record,
             name_todo: "",
diff --git a/src/test/run-pass/placement-box-emplace-back.rs b/src/test/run-pass/placement-box-emplace-back.rs
index 7cf96231b8678..bbd57dc029f66 100644
--- a/src/test/run-pass/placement-box-emplace-back.rs
+++ b/src/test/run-pass/placement-box-emplace-back.rs
@@ -61,7 +61,7 @@ struct EmplaceBackAgent<T> {
 }
 
 impl<'a, T> Placer<T, (), EmplaceBackAgent<T>> for EmplaceBackPlacer<'a, T> {
-    fn make_place(&self) -> EmplaceBackAgent<T> {
+    fn make_place(&mut self) -> EmplaceBackAgent<T> {
         let len = self.vec.len();
         let v = self.vec as *mut Vec<T>;
         unsafe {
diff --git a/src/test/run-pass/placement-box-user-defined.rs b/src/test/run-pass/placement-box-user-defined.rs
index 70acb8897e52f..ee043724848f0 100644
--- a/src/test/run-pass/placement-box-user-defined.rs
+++ b/src/test/run-pass/placement-box-user-defined.rs
@@ -20,28 +20,28 @@ use std::mem;
 use std::ops::{Placer,PlacementAgent};
 
 pub fn main() {
-    let ref arena = PoolFloat4::new();
+    let ref mut arena = PoolFloat4::new();
     inner(arena);
 
     let expecting = [true, true, true, true, true];
     assert_eq!(arena.avail_snapshot().as_slice(), expecting.as_slice());
 }
 
-fn inner(arena: &PoolFloat4) {
-    let avail = || -> Vec<bool> { arena.avail_snapshot() };
+fn inner(arena: &mut PoolFloat4) {
+    fn avail<'a>(arena: &PoolFloat4) -> [bool, ..5] { arena.avail_snapshot() }
 
     let expecting = [true, true, true, true, true];
-    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(avail(arena).as_slice(), expecting.as_slice());
 
-    let a: BoxFloat4 = box (arena) [1.0, 2.0, 3.0, 4.0];
+    let a: BoxFloat4 = box (*arena) [1.0, 2.0, 3.0, 4.0];
 
     let expecting = [false, true, true, true, true];
-    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(avail(arena).as_slice(), expecting.as_slice());
     assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
 
     let mut order = vec![];
 
-    let b: BoxFloat4 = box ({ order.push("arena"); arena }) [
+    let b: BoxFloat4 = box (*{ order.push("arena"); &mut *arena }) [
         { order.push("10.0"); 10.0 },
         { order.push("20.0"); 20.0 },
         { order.push("30.0"); 30.0 },
@@ -49,22 +49,22 @@ fn inner(arena: &PoolFloat4) {
         ];
 
     let expecting = [false, false, true, true, true];
-    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(avail(arena).as_slice(), expecting.as_slice());
     assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
     assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
     assert_eq!(order, vec!["arena", "10.0", "20.0", "30.0", "40.0"]);
 
     {
-        let c: BoxFloat4 = box (arena) [100.0, 200.0, 300.0, 400.0];
+        let c: BoxFloat4 = box (*arena) [100.0, 200.0, 300.0, 400.0];
         let expecting = [false, false, false, true, true];
-        assert_eq!(avail().as_slice(), expecting.as_slice());
+        assert_eq!(avail(arena).as_slice(), expecting.as_slice());
         assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
         assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
         assert_eq!(c.xyzw(), (100.0, 200.0, 300.0, 400.0));
     }
 
     let expecting = [false, false, true, true, true];
-    assert_eq!(avail().as_slice(), expecting.as_slice());
+    assert_eq!(avail(arena).as_slice(), expecting.as_slice());
     assert_eq!(a.xyzw(), (1.0, 2.0, 3.0, 4.0));
     assert_eq!(b.xyzw(), (10.0, 20.0, 30.0, 40.0));
 }
@@ -92,7 +92,7 @@ struct InterimBoxFloat4 {
 
 struct PoolFloat4 {
     pool: [f32, ..20],
-    avail: [Cell<bool>, ..5],
+    avail: [bool, ..5],
     no_copy: marker::NoCopy,
 }
 
@@ -100,25 +100,20 @@ impl PoolFloat4 {
     fn new() -> PoolFloat4 {
         let ret = PoolFloat4 {
             pool: [0.0, ..20],
-            avail: [Cell::new(true),
-                    Cell::new(true),
-                    Cell::new(true),
-                    Cell::new(true),
-                    Cell::new(true),
-                    ],
+            avail: [true, ..5],
             no_copy: marker::NoCopy,
         };
 
         ret
     }
 
-    fn avail_snapshot(&self) -> Vec<bool> {
-        self.avail.iter().map(|c|c.get()).collect()
+    fn avail_snapshot(&self) -> [bool, ..5] {
+        self.avail
     }
 
     fn first_avail(&self) -> Option<uint> {
         for i in range(0u, 5) {
-            if self.avail[i].get() {
+            if self.avail[i] {
                 return Some(i);
             }
         }
@@ -145,22 +140,22 @@ impl PoolFloat4 {
                 return;
             }
         };
-        self.avail[i].set(true);
-        assert_eq!(self.avail[i].get(), true);
+        self.avail[i] = true;
+        assert_eq!(self.avail[i], true);
     }
 }
 
 impl<'a> Placer<[f32, ..4], BoxFloat4, InterimBoxFloat4>
-    for &'a PoolFloat4 {
-    fn make_place(&self) -> InterimBoxFloat4 {
+    for PoolFloat4 {
+    fn make_place(&mut self) -> InterimBoxFloat4 {
         let i = self.first_avail()
             .unwrap_or_else(|| fail!("exhausted all spots"));
 
-        self.avail[i].set(false);
-        assert_eq!(self.avail[i].get(), false);
+        self.avail[i] = false;
+        assert_eq!(self.avail[i], false);
         unsafe {
-            InterimBoxFloat4 { arena: mem::transmute(*self),
-                               f4: mem::transmute(&self.pool[i*4]) }
+            let f4 : *mut f32 = mem::transmute(&self.pool[i*4]);
+            InterimBoxFloat4 { arena: mem::transmute(self), f4: f4 }
         }
     }
 }