From e12711540a00ded4021250f7b2a31773fc4dc734 Mon Sep 17 00:00:00 2001
From: Patrick Walton <pcwalton@mimiga.net>
Date: Tue, 17 Dec 2013 16:46:18 -0800
Subject: [PATCH] librustc: Implement placement `box` for GC and unique
 pointers.

---
 src/librustc/middle/cfg/construct.rs         |   4 +
 src/librustc/middle/dataflow.rs              |   5 +
 src/librustc/middle/lang_items.rs            |   6 +-
 src/librustc/middle/liveness.rs              |   7 +-
 src/librustc/middle/mem_categorization.rs    |   2 +-
 src/librustc/middle/moves.rs                 |   5 +
 src/librustc/middle/trans/debuginfo.rs       |   5 +
 src/librustc/middle/trans/expr.rs            | 105 ++++++++++++++-----
 src/librustc/middle/trans/tvec.rs            |   7 +-
 src/librustc/middle/ty.rs                    |  16 ++-
 src/librustc/middle/typeck/check/mod.rs      |  71 ++++++++++++-
 src/librustc/middle/typeck/check/regionck.rs |   1 +
 src/libstd/gc.rs                             |  18 ++++
 src/libstd/owned.rs                          |  14 +++
 src/libstd/prelude.rs                        |   4 +
 src/libsyntax/ast.rs                         |   2 +
 src/libsyntax/fold.rs                        |   3 +
 src/libsyntax/parse/parser.rs                |  16 ++-
 src/libsyntax/print/pprust.rs                |   7 ++
 src/libsyntax/visit.rs                       |   4 +
 src/test/compile-fail/new-box-syntax-bad.rs  |  14 +++
 src/test/run-pass/new-box-syntax.rs          |  22 +++-
 22 files changed, 296 insertions(+), 42 deletions(-)
 create mode 100644 src/test/compile-fail/new-box-syntax-bad.rs

diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index d5823e025be10..0beae3ce5c1fa 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -394,6 +394,10 @@ impl CFGBuilder {
                 self.straightline(expr, pred, [l, r])
             }
 
+            ast::ExprBox(p, e) => {
+                self.straightline(expr, pred, [p, e])
+            }
+
             ast::ExprAddrOf(_, e) |
             ast::ExprDoBody(e) |
             ast::ExprCast(e, _) |
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index ab19cdf627fcc..ffa356d6b0643 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -721,6 +721,11 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
                 self.walk_expr(e, in_out, loop_scopes);
             }
 
+            ast::ExprBox(s, e) => {
+                self.walk_expr(s, in_out, loop_scopes);
+                self.walk_expr(e, in_out, loop_scopes);
+            }
+
             ast::ExprInlineAsm(ref inline_asm) => {
                 for &(_, expr) in inline_asm.inputs.iter() {
                     self.walk_expr(expr, in_out, loop_scopes);
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 844a27668db96..31b36f10b40f1 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -207,7 +207,7 @@ pub fn collect_language_items(crate: &ast::Crate,
 }
 
 lets_do_this! {
-    There are 37 lang items.
+    There are 40 lang items.
 
 //  ID, Variant name,                    Name,                      Method name;
     0,  FreezeTraitLangItem,             "freeze",                  freeze_trait;
@@ -256,5 +256,9 @@ lets_do_this! {
     35, TypeIdLangItem,                  "type_id",                 type_id;
 
     36, EhPersonalityLangItem,           "eh_personality",          eh_personality_fn;
+
+    37, ManagedHeapLangItem,             "managed_heap",            managed_heap;
+    38, ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
+    39, GcLangItem,                      "gc",                      gc;
 }
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 3f82974c8aa0b..9e74c57c581ad 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -556,7 +556,7 @@ fn visit_expr(v: &mut LivenessVisitor, expr: &Expr, this: @IrMaps) {
       ExprAgain(_) | ExprLit(_) | ExprRet(..) | ExprBlock(..) |
       ExprAssign(..) | ExprAssignOp(..) | ExprMac(..) |
       ExprStruct(..) | ExprRepeat(..) | ExprParen(..) |
-      ExprInlineAsm(..) => {
+      ExprInlineAsm(..) | ExprBox(..) => {
           visit::walk_expr(v, expr, this);
       }
     }
@@ -1252,7 +1252,8 @@ impl Liveness {
           }
 
           ExprIndex(_, l, r) |
-          ExprBinary(_, _, l, r) => {
+          ExprBinary(_, _, l, r) |
+          ExprBox(l, r) => {
             self.propagate_through_exprs([l, r], succ)
           }
 
@@ -1546,7 +1547,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
       ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
       ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
-      ExprSelf(..) => {
+      ExprSelf(..) | ExprBox(..) => {
         visit::walk_expr(this, expr, ());
       }
       ExprForLoop(..) => fail!("non-desugared expr_for_loop")
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 645c2e79a56e7..14eb564314718 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -438,7 +438,7 @@ impl mem_categorization_ctxt {
           ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
           ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
           ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
-          ast::ExprInlineAsm(..) => {
+          ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
             return self.cat_rvalue_node(expr, expr_ty);
           }
 
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 0d45a87f3f995..462c557c61d34 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -591,6 +591,11 @@ impl VisitContext {
                 self.use_expr(base, comp_mode);
             }
 
+            ExprBox(place, base) => {
+                self.use_expr(place, comp_mode);
+                self.use_expr(base, comp_mode);
+            }
+
             ExprMac(..) => {
                 self.tcx.sess.span_bug(
                     expr.span,
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 549e5d18fbead..5690802b7e046 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -2616,6 +2616,11 @@ fn populate_scope_map(cx: &CrateContext,
             ast::ExprField(@ref sub_exp, _, _) |
             ast::ExprParen(@ref sub_exp)       => walk_expr(cx, sub_exp, scope_stack, scope_map),
 
+            ast::ExprBox(@ref place, @ref sub_expr) => {
+                walk_expr(cx, place, scope_stack, scope_map);
+                walk_expr(cx, sub_expr, scope_stack, scope_map);
+            }
+
             ast::ExprRet(exp_opt) => match exp_opt {
                 Some(@ref sub_exp) => walk_expr(cx, sub_exp, scope_stack, scope_map),
                 None => ()
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 422e70425054e..8505109dab2aa 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -619,6 +619,14 @@ fn trans_rvalue_datum_unadjusted<'a>(bcx: &'a Block<'a>, expr: &ast::Expr)
             return tvec::trans_uniq_or_managed_vstore(bcx, heap,
                                                       expr, contents);
         }
+        ast::ExprBox(_, contents) => {
+            // Special case for `~T`. (The other case, for GC, is handled in
+            // `trans_rvalue_dps_unadjusted`.)
+            let box_ty = expr_ty(bcx, expr);
+            let contents_ty = expr_ty(bcx, contents);
+            let heap = heap_for_unique(bcx, contents_ty);
+            return trans_boxed_expr(bcx, box_ty, contents, contents_ty, heap)
+        }
         ast::ExprLit(lit) => {
             return trans_immediate_lit(bcx, expr, *lit);
         }
@@ -828,6 +836,11 @@ fn trans_rvalue_dps_unadjusted<'a>(
         ast::ExprAssignOp(callee_id, op, dst, src) => {
             return trans_assign_op(bcx, expr, callee_id, op, dst, src);
         }
+        ast::ExprBox(_, contents) => {
+            // Special case for `Gc<T>` for now. The other case, for unique
+            // pointers, is handled in `trans_rvalue_datum_unadjusted`.
+            return trans_gc(bcx, expr, contents, dest)
+        }
         _ => {
             bcx.tcx().sess.span_bug(
                 expr.span,
@@ -1463,35 +1476,35 @@ fn trans_unary_datum<'a>(
                             trans_unary_datum()")
         }
     };
+}
 
-    fn trans_boxed_expr<'a>(
-                        bcx: &'a Block<'a>,
-                        box_ty: ty::t,
-                        contents: &ast::Expr,
-                        contents_ty: ty::t,
-                        heap: heap)
-                        -> DatumBlock<'a> {
-        let _icx = push_ctxt("trans_boxed_expr");
-        if heap == heap_exchange {
-            let llty = type_of::type_of(bcx.ccx(), contents_ty);
-            let size = llsize_of(bcx.ccx(), llty);
-            let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
-                                                               heap_exchange, size);
-            add_clean_free(bcx, val, heap_exchange);
-            let bcx = trans_into(bcx, contents, SaveIn(val));
-            revoke_clean(bcx, val);
-            return immediate_rvalue_bcx(bcx, val, box_ty);
-        } else {
-            let base::MallocResult {
-                bcx,
-                smart_ptr: bx,
-                body
-            } = base::malloc_general(bcx, contents_ty, heap);
-            add_clean_free(bcx, bx, heap);
-            let bcx = trans_into(bcx, contents, SaveIn(body));
-            revoke_clean(bcx, bx);
-            return immediate_rvalue_bcx(bcx, bx, box_ty);
-        }
+fn trans_boxed_expr<'a>(
+                    bcx: &'a Block<'a>,
+                    box_ty: ty::t,
+                    contents: &ast::Expr,
+                    contents_ty: ty::t,
+                    heap: heap)
+                    -> DatumBlock<'a> {
+    let _icx = push_ctxt("trans_boxed_expr");
+    if heap == heap_exchange {
+        let llty = type_of::type_of(bcx.ccx(), contents_ty);
+        let size = llsize_of(bcx.ccx(), llty);
+        let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
+                                                           heap_exchange, size);
+        add_clean_free(bcx, val, heap_exchange);
+        let bcx = trans_into(bcx, contents, SaveIn(val));
+        revoke_clean(bcx, val);
+        return immediate_rvalue_bcx(bcx, val, box_ty);
+    } else {
+        let base::MallocResult {
+            bcx,
+            smart_ptr: bx,
+            body
+        } = base::malloc_general(bcx, contents_ty, heap);
+        add_clean_free(bcx, bx, heap);
+        let bcx = trans_into(bcx, contents, SaveIn(body));
+        revoke_clean(bcx, bx);
+        return immediate_rvalue_bcx(bcx, bx, box_ty);
     }
 }
 
@@ -1507,6 +1520,42 @@ fn trans_addr_of<'a>(
     return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
 }
 
+pub fn trans_gc<'a>(
+                mut bcx: &'a Block<'a>,
+                expr: &ast::Expr,
+                contents: &ast::Expr,
+                dest: Dest)
+                -> &'a Block<'a> {
+    let contents_ty = expr_ty(bcx, contents);
+    let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
+    let expr_ty = expr_ty(bcx, expr);
+
+    let addr = match dest {
+        Ignore => {
+            return trans_boxed_expr(bcx,
+                                    box_ty,
+                                    contents,
+                                    contents_ty,
+                                    heap_managed).bcx
+        }
+        SaveIn(addr) => addr,
+    };
+
+    let repr = adt::represent_type(bcx.ccx(), expr_ty);
+    adt::trans_start_init(bcx, repr, addr, 0);
+    let field_dest = adt::trans_field_ptr(bcx, repr, addr, 0, 0);
+    let contents_datum_block = trans_boxed_expr(bcx,
+                                                box_ty,
+                                                contents,
+                                                contents_ty,
+                                                heap_managed);
+    bcx = contents_datum_block.bcx;
+    bcx = contents_datum_block.datum.move_to(bcx, INIT, field_dest);
+
+    // Next, wrap it up in the struct.
+    bcx
+}
+
 // Important to get types for both lhs and rhs, because one might be _|_
 // and the other not.
 fn trans_eager_binop<'a>(
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index 18bfe52f643a5..ba7d9642ad9d2 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -13,8 +13,8 @@ use back::abi;
 use lib;
 use lib::llvm::{llvm, ValueRef};
 use middle::lang_items::StrDupUniqFnLangItem;
-use middle::trans::base;
 use middle::trans::base::*;
+use middle::trans::base;
 use middle::trans::build::*;
 use middle::trans::callee;
 use middle::trans::common::*;
@@ -23,14 +23,12 @@ use middle::trans::expr::{Dest, Ignore, SaveIn};
 use middle::trans::expr;
 use middle::trans::glue;
 use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
+use middle::trans::type_::Type;
 use middle::trans::type_of;
 use middle::ty;
 use util::common::indenter;
 use util::ppaux::ty_to_str;
 
-use middle::trans::type_::Type;
-
-use std::option::None;
 use syntax::ast;
 use syntax::codemap;
 
@@ -689,3 +687,4 @@ pub fn iter_vec_unboxed<'r,
     let dataptr = get_dataptr(bcx, body_ptr);
     return iter_vec_raw(bcx, dataptr, vec_ty, fill, f);
 }
+
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index a4acc33fe9693..34351ebc09b95 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -12,8 +12,8 @@ use driver::session;
 use metadata::csearch;
 use metadata;
 use middle::const_eval;
+use middle::lang_items::{ExchangeHeapLangItem, OpaqueStructLangItem};
 use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
-use middle::lang_items::OpaqueStructLangItem;
 use middle::freevars;
 use middle::resolve;
 use middle::resolve_lifetime;
@@ -3241,6 +3241,20 @@ pub fn expr_kind(tcx: ctxt,
             RvalueDatumExpr
         }
 
+        ast::ExprBox(place, _) => {
+            // Special case `~T` for now:
+            let def_map = tcx.def_map.borrow();
+            let definition = match def_map.get().find(&place.id) {
+                Some(&def) => def,
+                None => fail!("no def for place"),
+            };
+            let def_id = ast_util::def_id_of_def(definition);
+            match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
+                Some(item_def_id) if def_id == item_def_id => RvalueDatumExpr,
+                Some(_) | None => RvalueDpsExpr,
+            }
+        }
+
         ast::ExprParen(e) => expr_kind(tcx, method_map, e),
 
         ast::ExprMac(..) => {
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 41757b1a634c5..cf7fe77f7b649 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -78,9 +78,11 @@ type parameter).
 
 
 use middle::const_eval;
+use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
+use middle::lang_items::{ManagedHeapLangItem};
+use middle::lint::unreachable_code;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
-use middle::lint::unreachable_code;
 use middle::subst::Subst;
 use middle::ty::{FnSig, VariantInfo};
 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
@@ -2679,6 +2681,73 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
         fcx.write_ty(id, typ);
       }
 
+      ast::ExprBox(place, subexpr) => {
+          check_expr(fcx, place);
+          check_expr(fcx, subexpr);
+
+          let mut checked = false;
+          match place.node {
+              ast::ExprPath(ref path) => {
+                  // XXX(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 def_id = ast_util::def_id_of_def(definition);
+                  match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
+                      Some(item_def_id) if def_id == item_def_id => {
+                          fcx.write_ty(id, ty::mk_uniq(tcx, ty::mt {
+                              ty: fcx.expr_ty(subexpr),
+                              mutbl: ast::MutImmutable,
+                          }));
+                          checked = true
+                      }
+                      Some(_) | None => {}
+                  }
+                  if !checked {
+                      match tcx.lang_items
+                               .items[ManagedHeapLangItem as uint] {
+                          Some(item_def_id) if def_id == item_def_id => {
+                              // Assign the magic `Gc<T>` struct.
+                              let gc_struct_id =
+                                  match tcx.lang_items
+                                           .require(GcLangItem) {
+                                      Ok(id) => id,
+                                      Err(msg) => {
+                                          tcx.sess.span_err(expr.span, msg);
+                                          ast::DefId {
+                                              crate: ast::CRATE_NODE_ID,
+                                              node: ast::DUMMY_NODE_ID,
+                                          }
+                                      }
+                                  };
+                              let regions =
+                                  ty::NonerasedRegions(opt_vec::Empty);
+                              let sty = ty::mk_struct(tcx,
+                                                      gc_struct_id,
+                                                      substs {
+                                                        self_ty: None,
+                                                        tps: ~[
+                                                            fcx.expr_ty(
+                                                                subexpr)
+                                                        ],
+                                                        regions: regions,
+                                                      });
+                              fcx.write_ty(id, sty);
+                              checked = true
+                          }
+                          Some(_) | None => {}
+                      }
+                  }
+              }
+              _ => {}
+          }
+
+          if !checked {
+              tcx.sess.span_err(expr.span,
+                                "only the managed heap and exchange heap are \
+                                 currently supported")
+          }
+      }
+
       ast::ExprLit(lit) => {
         let typ = check_lit(fcx, lit);
         fcx.write_ty(id, typ);
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 2670a5d59a1c7..aea5111edee3d 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -1048,6 +1048,7 @@ pub mod guarantor {
             ast::ExprAddrOf(..) |
             ast::ExprBinary(..) |
             ast::ExprVstore(..) |
+            ast::ExprBox(..) |
             ast::ExprBreak(..) |
             ast::ExprAgain(..) |
             ast::ExprRet(..) |
diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs
index 1b53c70a9a1f2..4cbecc9b42f85 100644
--- a/src/libstd/gc.rs
+++ b/src/libstd/gc.rs
@@ -21,6 +21,14 @@ use clone::{Clone, DeepClone};
 use managed;
 
 /// Immutable garbage-collected pointer type
+#[lang="gc"]
+#[cfg(not(test))]
+#[no_send]
+pub struct Gc<T> {
+    priv ptr: @T
+}
+
+#[cfg(test)]
 #[no_send]
 pub struct Gc<T> {
     priv ptr: @T
@@ -54,6 +62,16 @@ impl<T> Clone for Gc<T> {
     }
 }
 
+/// An value that represents the task-local managed heap.
+///
+/// Use this like `let foo = box(GC) Bar::new(...);`
+#[lang="managed_heap"]
+#[cfg(not(test))]
+pub static GC: () = ();
+
+#[cfg(test)]
+pub static GC: () = ();
+
 /// The `Send` bound restricts this to acyclic graphs where it is well-defined.
 ///
 /// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.
diff --git a/src/libstd/owned.rs b/src/libstd/owned.rs
index 424c4fd6b2f44..dc8ea34c84bd3 100644
--- a/src/libstd/owned.rs
+++ b/src/libstd/owned.rs
@@ -12,6 +12,20 @@
 
 #[cfg(not(test))] use cmp::*;
 
+/// A value that represents the global exchange heap. This is the default
+/// place that the `box` keyword allocates into when no place is supplied.
+///
+/// The following two examples are equivalent:
+///
+///     let foo = box(HEAP) Bar::new(...);
+///     let foo = box Bar::new(...);
+#[lang="exchange_heap"]
+#[cfg(not(test))]
+pub static HEAP: () = ();
+
+#[cfg(test)]
+pub static HEAP: () = ();
+
 #[cfg(not(test))]
 impl<T:Eq> Eq for ~T {
     #[inline]
diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs
index afacc4e8c1761..36bcc81c06de9 100644
--- a/src/libstd/prelude.rs
+++ b/src/libstd/prelude.rs
@@ -86,6 +86,10 @@ pub use vec::{Vector, VectorVector, CopyableVector, ImmutableVector};
 pub use comm::{Port, Chan, SharedChan};
 pub use task::spawn;
 
+// Reexported statics
+#[cfg(not(test))]
+pub use gc::GC;
+
 /// Disposes of a value.
 #[inline]
 pub fn drop<T>(_x: T) { }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 8864c678b952a..bdc5c375bc445 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -547,6 +547,8 @@ pub enum CallSugar {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum Expr_ {
     ExprVstore(@Expr, ExprVstore),
+    // First expr is the place; second expr is the value.
+    ExprBox(@Expr, @Expr),
     ExprVec(~[@Expr], Mutability),
     ExprCall(@Expr, ~[@Expr], CallSugar),
     ExprMethodCall(NodeId, @Expr, Ident, ~[P<Ty>], ~[@Expr], CallSugar),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 8fab2df7a5dab..a681de65c7ab7 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -724,6 +724,9 @@ pub fn noop_fold_expr<T: ast_fold>(e: @Expr, folder: &mut T) -> @Expr {
         ExprVstore(e, v) => {
             ExprVstore(folder.fold_expr(e), v)
         }
+        ExprBox(p, e) => {
+            ExprBox(folder.fold_expr(p), folder.fold_expr(e))
+        }
         ExprVec(ref exprs, mutt) => {
             ExprVec(exprs.map(|&x| folder.fold_expr(x)), mutt)
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 26653fe4a1ef6..0847167267d56 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -23,7 +23,7 @@ use ast::{BlockCheckMode, UnBox};
 use ast::{Crate, CrateConfig, Decl, DeclItem};
 use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, enum_def, explicit_self};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
-use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock};
+use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
 use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
 use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
 use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
@@ -2325,6 +2325,20 @@ impl Parser {
           token::IDENT(_, _) if self.is_keyword(keywords::Box) => {
             self.bump();
 
+            // Check for a place: `box(PLACE) EXPR`.
+            if self.eat(&token::LPAREN) {
+                // Support `box() EXPR` as the default.
+                if !self.eat(&token::RPAREN) {
+                    let place = self.parse_expr();
+                    self.expect(&token::RPAREN);
+                    let subexpression = self.parse_prefix_expr();
+                    hi = subexpression.span.hi;
+                    ex = ExprBox(place, subexpression);
+                    return self.mk_expr(lo, hi, ex);
+                }
+            }
+
+            // Otherwise, we use the unique pointer default.
             let subexpression = self.parse_prefix_expr();
             hi = subexpression.span.hi;
             // HACK: turn `box [...]` into a boxed-evec
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 82a7d550f6403..f8b7720da7ba1 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1155,6 +1155,13 @@ pub fn print_expr(s: &mut ps, expr: &ast::Expr) {
             print_expr_vstore(s, v);
             print_expr(s, e);
         },
+        ast::ExprBox(p, e) => {
+            word(&mut s.s, "box");
+            word(&mut s.s, "(");
+            print_expr(s, p);
+            word_space(s, ")");
+            print_expr(s, e);
+        }
       ast::ExprVec(ref exprs, mutbl) => {
         ibox(s, indent_unit);
         word(&mut s.s, "[");
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6484855d9d942..b67e2e7d9fa19 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -618,6 +618,10 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
         ExprVstore(subexpression, _) => {
             visitor.visit_expr(subexpression, env.clone())
         }
+        ExprBox(place, subexpression) => {
+            visitor.visit_expr(place, env.clone());
+            visitor.visit_expr(subexpression, env.clone())
+        }
         ExprVec(ref subexpressions, _) => {
             walk_exprs(visitor, *subexpressions, env.clone())
         }
diff --git a/src/test/compile-fail/new-box-syntax-bad.rs b/src/test/compile-fail/new-box-syntax-bad.rs
new file mode 100644
index 0000000000000..942c862120792
--- /dev/null
+++ b/src/test/compile-fail/new-box-syntax-bad.rs
@@ -0,0 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the new `box` syntax works with unique pointers and GC pointers.
+
+use std::gc::Gc;
+use std::owned::HEAP;
+
+pub fn main() {
+    let x: Gc<int> = box(HEAP) 2;  //~ ERROR mismatched types
+    let y: Gc<int> = box(HEAP)(1 + 2);  //~ ERROR mismatched types
+    let z: ~int = box(GC)(4 + 5);   //~ ERROR mismatched types
+}
+
diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs
index 2d6e7a4ef0a13..d237c4d9a4e85 100644
--- a/src/test/run-pass/new-box-syntax.rs
+++ b/src/test/run-pass/new-box-syntax.rs
@@ -1,8 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+// Tests that the new `box` syntax works with unique pointers and GC pointers.
+
+use std::gc::Gc;
+use std::owned::HEAP;
+
+struct Structure {
+    x: int,
+    y: int,
+}
+
 pub fn main() {
-    let x: ~int = box 3;
-    println!("{}", *x);
+    let x: ~int = box(HEAP) 2;
+    let y: ~int = box 2;
+    let z: Gc<int> = box(GC) 2;
+    let a: Gc<Structure> = box(GC) Structure {
+        x: 10,
+        y: 20,
+    };
+    let b: ~int = box()(1 + 2);
+    let c = box()(3 + 4);
+    let d = box(GC)(5 + 6);
 }