about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-03-14 15:16:46 -0400
committerNiko Matsakis <niko@alum.mit.edu>2012-03-20 20:39:40 -0700
commitcfcbec3cc3bde0b8e811520e3bd842f53c2c9e26 (patch)
treef6b837b27e979fabfca3bc1df10a2b742d42d351 /src/rustc
parentba39e277e2c63909cb35a0dd68e9f3bab728c425 (diff)
downloadrust-cfcbec3cc3bde0b8e811520e3bd842f53c2c9e26.tar.gz
rust-cfcbec3cc3bde0b8e811520e3bd842f53c2c9e26.zip
Implement an initial version of placement new.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/resolve.rs3
-rw-r--r--src/rustc/middle/trans/base.rs104
-rw-r--r--src/rustc/middle/trans/native.rs23
-rw-r--r--src/rustc/middle/trans/type_use.rs3
-rw-r--r--src/rustc/middle/tstate/ann.rs8
-rw-r--r--src/rustc/middle/tstate/auxiliary.rs6
-rw-r--r--src/rustc/middle/tstate/pre_post_conditions.rs3
-rw-r--r--src/rustc/middle/tstate/states.rs3
-rw-r--r--src/rustc/middle/tstate/tritv.rs22
-rw-r--r--src/rustc/middle/typeck.rs51
-rw-r--r--src/rustc/syntax/ast.rs4
-rw-r--r--src/rustc/syntax/fold.rs5
-rw-r--r--src/rustc/syntax/parse/parser.rs9
-rw-r--r--src/rustc/syntax/print/pprust.rs7
-rw-r--r--src/rustc/syntax/visit.rs4
15 files changed, 199 insertions, 56 deletions
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index e2bb5494659..bfc6be48253 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -2308,6 +2308,9 @@ fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) {
       ast::expr_assign_op(_, _, _) | ast::expr_index(_, _) {
         e.impl_map.insert(x.id, sc);
       }
+      ast::expr_new(p, _, _) {
+        e.impl_map.insert(p.id, sc);
+      }
       _ {}
     }
     visit::visit_expr(x, sc, v);
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index a3b8dfd2154..c0dbdc96210 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1261,9 +1261,9 @@ fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr,
       some(origin) {
         let callee_id = ast_util::op_expr_callee_id(un_expr);
         let fty = node_id_type(bcx, callee_id);
-        ret trans_call_inner(bcx, fty, {|bcx|
+        ret trans_call_inner(bcx, fty, expr_ty(bcx, un_expr), {|bcx|
             impl::trans_method_callee(bcx, callee_id, e, origin)
-        }, [], un_expr.id, dest);
+        }, arg_exprs([]), dest);
       }
       _ {}
     }
@@ -1450,10 +1450,10 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
       some(origin) {
         let callee_id = ast_util::op_expr_callee_id(ex);
         let fty = node_id_type(bcx, callee_id);
-        ret trans_call_inner(bcx, fty, {|bcx|
+        ret trans_call_inner(bcx, fty, expr_ty(bcx, ex), {|bcx|
             // FIXME provide the already-computed address, not the expr
             impl::trans_method_callee(bcx, callee_id, dst, origin)
-        }, [src], ex.id, save_in(lhs_res.val));
+        }, arg_exprs([src]), save_in(lhs_res.val));
       }
       _ {}
     }
@@ -1561,9 +1561,9 @@ fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
       some(origin) {
         let callee_id = ast_util::op_expr_callee_id(ex);
         let fty = node_id_type(bcx, callee_id);
-        ret trans_call_inner(bcx, fty, {|bcx|
+        ret trans_call_inner(bcx, fty, expr_ty(bcx, ex), {|bcx|
             impl::trans_method_callee(bcx, callee_id, lhs, origin)
-        }, [rhs], ex.id, dest);
+        }, arg_exprs([rhs]), dest);
       }
       _ {}
     }
@@ -2498,6 +2498,10 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
     ret rslt(bcx, val);
 }
 
+enum call_args {
+    arg_exprs([@ast::expr]),
+    arg_vals([ValueRef])
+}
 
 // NB: must keep 4 fns in sync:
 //
@@ -2505,12 +2509,12 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
 //  - create_llargs_for_fn_args.
 //  - new_fn_ctxt
 //  - trans_args
-fn trans_args(cx: block, llenv: ValueRef, es: [@ast::expr], fn_ty: ty::t,
+fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
               dest: dest, generic_intrinsic: bool)
     -> {bcx: block, args: [ValueRef], retslot: ValueRef} {
 
     let temp_cleanups = [];
-    let args = ty::ty_fn_args(fn_ty);
+    let arg_tys = ty::ty_fn_args(fn_ty);
     let llargs: [ValueRef] = [];
 
     let ccx = cx.ccx();
@@ -2546,13 +2550,21 @@ fn trans_args(cx: block, llenv: ValueRef, es: [@ast::expr], fn_ty: ty::t,
     // First we figure out the caller's view of the types of the arguments.
     // This will be needed if this is a generic call, because the callee has
     // to cast her view of the arguments to the caller's view.
-    let arg_tys = type_of_explicit_args(ccx, args);
-    let i = 0u;
-    for e: @ast::expr in es {
-        let r = trans_arg_expr(bcx, args[i], arg_tys[i], e, temp_cleanups);
-        bcx = r.bcx;
-        llargs += [r.val];
-        i += 1u;
+    alt args {
+      arg_exprs(es) {
+        let llarg_tys = type_of_explicit_args(ccx, arg_tys);
+        let i = 0u;
+        for e: @ast::expr in es {
+            let r = trans_arg_expr(bcx, arg_tys[i], llarg_tys[i],
+                                   e, temp_cleanups);
+            bcx = r.bcx;
+            llargs += [r.val];
+            i += 1u;
+        }
+      }
+      arg_vals(vs) {
+        llargs += vs;
+      }
     }
 
     // now that all arguments have been successfully built, we can revoke any
@@ -2568,15 +2580,15 @@ fn trans_args(cx: block, llenv: ValueRef, es: [@ast::expr], fn_ty: ty::t,
 }
 
 fn trans_call(in_cx: block, f: @ast::expr,
-              args: [@ast::expr], id: ast::node_id, dest: dest)
+              args: call_args, id: ast::node_id, dest: dest)
     -> block {
-    trans_call_inner(in_cx, expr_ty(in_cx, f),
-                     {|cx| trans_callee(cx, f)}, args, id, dest)
+    trans_call_inner(in_cx, expr_ty(in_cx, f), node_id_type(in_cx, id),
+                     {|cx| trans_callee(cx, f)}, args, dest)
 }
 
-fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
+fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, ret_ty: ty::t,
                     get_callee: fn(block) -> lval_maybe_callee,
-                    args: [@ast::expr], id: ast::node_id, dest: dest)
+                    args: call_args, dest: dest)
     -> block {
     with_scope(in_cx, "call") {|cx|
         let f_res = get_callee(cx);
@@ -2603,9 +2615,10 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
           }
         };
 
-        let ret_ty = node_id_type(bcx, id);
-        let args_res = trans_args(bcx, llenv, args, fn_expr_ty, dest,
-                                  option::is_some(f_res.tds));
+        let args_res = {
+            trans_args(bcx, llenv, args, fn_expr_ty, dest,
+                       option::is_some(f_res.tds))
+        };
         bcx = args_res.bcx;
         let llargs = args_res.args;
         option::may(f_res.tds) {|vals|
@@ -2923,7 +2936,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
       }
       ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
       ast::expr_call(f, args, _) {
-        ret trans_call(bcx, f, args, e.id, dest);
+        ret trans_call(bcx, f, arg_exprs(args), e.id, dest);
       }
       ast::expr_field(base, _, _) {
         if dest == ignore { ret trans_expr(bcx, base, ignore); }
@@ -2937,9 +2950,9 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
         let origin = bcx.ccx().maps.method_map.get(e.id);
         let callee_id = ast_util::op_expr_callee_id(e);
         let fty = node_id_type(bcx, callee_id);
-        ret trans_call_inner(bcx, fty, {|bcx|
+        ret trans_call_inner(bcx, fty, expr_ty(bcx, e), {|bcx|
             impl::trans_method_callee(bcx, callee_id, base, origin)
-        }, [idx], e.id, dest);
+        }, arg_exprs([idx]), dest);
       }
 
       // These return nothing
@@ -3037,6 +3050,45 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
         assert dest == ignore;
         ret trans_assign_op(bcx, e, op, dst, src);
       }
+      ast::expr_new(pool, alloc_id, val) {
+        // First, call pool->alloc(sz, align) to get back a void*.  Then, cast
+        // this memory to the required type and evaluate value into it.
+        let ccx = bcx.ccx();
+
+        // Allocate space for the ptr that will be returned from
+        // `pool.alloc()`:
+        let ptr_ty = expr_ty(bcx, e);
+        let {bcx, val: ptr_ptr_val} = alloc_ty(bcx, ptr_ty);
+
+        #debug["ptr_ty = %s", ty_to_str(tcx, ptr_ty)];
+        #debug["ptr_ptr_val = %s", val_str(ccx.tn, ptr_ptr_val)];
+
+        let void_ty = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx),
+                                       mutbl: ast::m_imm});
+        let voidval = {
+            let llvoid_ty = type_of(ccx, void_ty);
+            PointerCast(bcx, ptr_ptr_val, T_ptr(llvoid_ty))
+        };
+
+        #debug["voidval = %s", val_str(ccx.tn, voidval)];
+
+        let llval_ty = type_of(ccx, expr_ty(bcx, val));
+        let args = [llsize_of(ccx, llval_ty), llalign_of(ccx, llval_ty)];
+        let origin = bcx.ccx().maps.method_map.get(alloc_id);
+        let bcx = trans_call_inner(
+            bcx,
+            node_id_type(bcx, alloc_id),
+            void_ty,
+            {|bcx| impl::trans_method_callee(bcx, alloc_id, pool, origin) },
+            arg_vals(args),
+            save_in(voidval));
+
+        #debug["dest = %s", dest_str(ccx, dest)];
+        let ptr_val = Load(bcx, ptr_ptr_val);
+        #debug["ptr_val = %s", val_str(ccx.tn, ptr_val)];
+        let bcx = trans_expr(bcx, val, save_in(ptr_val));
+        store_in_dest(bcx, ptr_val, dest)
+      }
       _ { bcx.tcx().sess.span_bug(e.span, "trans_expr reached \
              fall-through case"); }
 
diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs
index 938514c93b9..738879b8d8a 100644
--- a/src/rustc/middle/trans/native.rs
+++ b/src/rustc/middle/trans/native.rs
@@ -111,27 +111,28 @@ fn classify_ty(ty: TypeRef) -> [x86_64_reg_class] {
         }
     }
 
-    fn unify(cls: [mut x86_64_reg_class], i: uint,
-             new: x86_64_reg_class) {
-        if cls[i] == new {
+    fn unify(cls: [mut x86_64_reg_class],
+             i: uint,
+             newv: x86_64_reg_class) {
+        if cls[i] == newv {
             ret;
         } else if cls[i] == no_class {
-            cls[i] = new;
-        } else if new == no_class {
+            cls[i] = newv;
+        } else if newv == no_class {
             ret;
-        } else if cls[i] == memory_class || new == memory_class {
+        } else if cls[i] == memory_class || newv == memory_class {
             cls[i] = memory_class;
-        } else if cls[i] == integer_class || new == integer_class {
+        } else if cls[i] == integer_class || newv == integer_class {
             cls[i] = integer_class;
         } else if cls[i] == x87_class ||
                   cls[i] == x87up_class ||
                   cls[i] == complex_x87_class ||
-                  new == x87_class ||
-                  new == x87up_class ||
-                  new == complex_x87_class {
+                  newv == x87_class ||
+                  newv == x87up_class ||
+                  newv == complex_x87_class {
             cls[i] = memory_class;
         } else {
-            cls[i] = new;
+            cls[i] = newv;
         }
     }
 
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index 99ccdeeb70e..68779c7e71e 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -168,6 +168,9 @@ fn mark_for_expr(cx: ctx, e: @expr) {
       expr_log(_, _, val) {
         node_type_needs(cx, use_tydesc, val.id);
       }
+      expr_new(_, _, v) {
+        node_type_needs(cx, use_repr, v.id);
+      }
       expr_for(_, _, _) | expr_do_while(_, _) | expr_alt(_, _, _) |
       expr_block(_) | expr_if(_, _, _) | expr_while(_, _) |
       expr_fail(_) | expr_break | expr_cont | expr_unary(_, _) |
diff --git a/src/rustc/middle/tstate/ann.rs b/src/rustc/middle/tstate/ann.rs
index f3862e3d20f..82388f9b89f 100644
--- a/src/rustc/middle/tstate/ann.rs
+++ b/src/rustc/middle/tstate/ann.rs
@@ -183,14 +183,14 @@ fn set_poststate(a: ts_ann, p: poststate) -> bool {
 
 
 // Set all the bits in p that are set in new
-fn extend_prestate(p: prestate, new: poststate) -> bool {
-    ret tritv_union(p, new);
+fn extend_prestate(p: prestate, newv: poststate) -> bool {
+    ret tritv_union(p, newv);
 }
 
 
 // Set all the bits in p that are set in new
-fn extend_poststate(p: poststate, new: poststate) -> bool {
-    ret tritv_union(p, new);
+fn extend_poststate(p: poststate, newv: poststate) -> bool {
+    ret tritv_union(p, newv);
 }
 
 // Sets the given bit in p to "don't care"
diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs
index 38bfb1e4f71..e6f5ca1dd64 100644
--- a/src/rustc/middle/tstate/auxiliary.rs
+++ b/src/rustc/middle/tstate/auxiliary.rs
@@ -709,8 +709,8 @@ fn find_instances(_fcx: fn_ctxt, subst: subst, c: constraint) ->
         for d: pred_args in *descs {
             if args_mention(d.node.args, find_in_subst_bool, subst) {
                 let old_bit_num = d.node.bit_num;
-                let new = replace(subst, d);
-                alt find_instance_(new, *descs) {
+                let newv = replace(subst, d);
+                alt find_instance_(newv, *descs) {
                   some(d1) { rslt += [{from: old_bit_num, to: d1}]; }
                   _ { }
                 }
@@ -753,7 +753,7 @@ fn replace(subst: subst, d: pred_args) -> [constr_arg_general_<inst>] {
         alt c.node {
           carg_ident(p) {
             alt find_in_subst(p.node, subst) {
-              some(new) { rslt += [carg_ident(new)]; }
+              some(newv) { rslt += [carg_ident(newv)]; }
               _ { rslt += [c.node]; }
             }
           }
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index 5b6d5cc2911..89e7409ed96 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -325,6 +325,9 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
         clear_pp(rslt);
         handle_var(fcx, rslt, e.id, path_to_ident(p));
       }
+      expr_new(p, _, v) {
+        find_pre_post_exprs(fcx, [p, v], e.id);
+      }
       expr_log(_, lvl, arg) {
         find_pre_post_exprs(fcx, [lvl, arg], e.id);
       }
diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs
index d7148563d02..7bb16a5ec9e 100644
--- a/src/rustc/middle/tstate/states.rs
+++ b/src/rustc/middle/tstate/states.rs
@@ -355,6 +355,9 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
     let num_constrs = num_constraints(fcx.enclosing);
 
     alt e.node {
+      expr_new(p, _, v) {
+        ret find_pre_post_state_two(fcx, pres, p, v, e.id, oper_pure);
+      }
       expr_vec(elts, _) {
         ret find_pre_post_state_exprs(fcx, pres, e.id,
                                       vec::from_elem(vec::len(elts),
diff --git a/src/rustc/middle/tstate/tritv.rs b/src/rustc/middle/tstate/tritv.rs
index e9170033fb7..98b27e0e3ba 100644
--- a/src/rustc/middle/tstate/tritv.rs
+++ b/src/rustc/middle/tstate/tritv.rs
@@ -155,8 +155,8 @@ fn trit_and(a: trit, b: trit) -> trit {
     // a and b were both dont_care
 }
 
-fn change(changed: bool, old: trit, new: trit) -> bool {
-    changed || new != old
+fn change(changed: bool, old: trit, newv: trit) -> bool {
+    changed || newv != old
 }
 
 fn tritv_difference(p1: t, p2: t) -> bool {
@@ -166,9 +166,9 @@ fn tritv_difference(p1: t, p2: t) -> bool {
     let changed = false;
     while i < sz {
         let old = tritv_get(p1, i);
-        let new = trit_minus(old, tritv_get(p2, i));
-        changed = change(changed, old, new);
-        tritv_set(i, p1, new);
+        let newv = trit_minus(old, tritv_get(p2, i));
+        changed = change(changed, old, newv);
+        tritv_set(i, p1, newv);
         i += 1u;
     }
     ret changed;
@@ -181,9 +181,9 @@ fn tritv_union(p1: t, p2: t) -> bool {
     let changed = false;
     while i < sz {
         let old = tritv_get(p1, i);
-        let new = trit_or(old, tritv_get(p2, i));
-        changed = change(changed, old, new);
-        tritv_set(i, p1, new);
+        let newv = trit_or(old, tritv_get(p2, i));
+        changed = change(changed, old, newv);
+        tritv_set(i, p1, newv);
         i += 1u;
     }
     ret changed;
@@ -196,9 +196,9 @@ fn tritv_intersect(p1: t, p2: t) -> bool {
     let changed = false;
     while i < sz {
         let old = tritv_get(p1, i);
-        let new = trit_and(old, tritv_get(p2, i));
-        changed = change(changed, old, new);
-        tritv_set(i, p1, new);
+        let newv = trit_and(old, tritv_get(p2, i));
+        changed = change(changed, old, newv);
+        tritv_set(i, p1, newv);
         i += 1u;
     }
     ret changed;
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 87bb55e1b76..a6c23cdca58 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -1888,6 +1888,12 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
                   origin: method_origin,
                   self_sub: option<self_subst>}> {
     let tcx = fcx.ccx.tcx;
+
+    #debug["lookup_method_inner: expr=%s name=%s ty=%s",
+           expr_to_str(expr),
+           name,
+           ty_to_str(fcx.ccx.tcx, ty)];
+
     // First, see whether this is an interface-bounded parameter
     alt ty::get(ty).struct {
       ty::ty_param(n, did) {
@@ -2870,6 +2876,51 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
           }
         }
       }
+      ast::expr_new(p, alloc_id, v) {
+        bot |= check_expr(fcx, p);
+        bot |= check_expr(fcx, v);
+
+        let p_ty = expr_ty(tcx, p);
+
+        alt lookup_method(fcx, p, alloc_id, "alloc", p_ty, []) {
+          some(origin) {
+            fcx.ccx.method_map.insert(alloc_id, origin);
+
+            // Check that the alloc() method has the expected type, which
+            // should be fn(sz: uint, align: uint) -> *().
+            let expected_ty = {
+                let ty_uint = ty::mk_uint(tcx);
+                let ty_nilp = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx),
+                                              mutbl: ast::m_imm});
+                let m = ast::expl(ty::default_arg_mode_for_ty(ty_uint));
+                ty::mk_fn(tcx, {proto: ast::proto_any,
+                                inputs: [{mode: m, ty: ty_uint},
+                                         {mode: m, ty: ty_uint}],
+                                output: ty_nilp,
+                                ret_style: ast::return_val,
+                                constraints: []})
+            };
+
+            demand::simple(fcx, expr.span,
+                           expected_ty, node_id_to_type(tcx, alloc_id));
+          }
+
+          none {
+            let t_err = resolve_type_vars_if_possible(fcx, p_ty);
+            let msg = #fmt["no `alloc()` method found for type `%s`",
+                           ty_to_str(tcx, t_err)];
+            tcx.sess.span_err(expr.span, msg);
+          }
+        }
+
+        // The region value must have a type like &r.T.  The resulting
+        // memory will be allocated into the region `r`.
+        let pool_region = region_of(fcx, p);
+        let v_ty = expr_ty(tcx, v);
+        let res_ty = ty::mk_rptr(tcx, pool_region, {ty: v_ty,
+                                                    mutbl: ast::m_imm});
+        write_ty(tcx, expr.id, res_ty);
+      }
     }
     if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
 
diff --git a/src/rustc/syntax/ast.rs b/src/rustc/syntax/ast.rs
index db0f6a56d80..93f60519114 100644
--- a/src/rustc/syntax/ast.rs
+++ b/src/rustc/syntax/ast.rs
@@ -325,6 +325,10 @@ enum expr_ {
     expr_be(@expr),
     expr_log(int, @expr, @expr),
 
+    expr_new(/* arena */ @expr,
+             /* id for the alloc() call */ node_id,
+             /* value */ @expr),
+
     /* just an assert, no significance to typestate */
     expr_assert(@expr),
 
diff --git a/src/rustc/syntax/fold.rs b/src/rustc/syntax/fold.rs
index 9b80775343e..ab5659b1ff4 100644
--- a/src/rustc/syntax/fold.rs
+++ b/src/rustc/syntax/fold.rs
@@ -382,6 +382,11 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
     let fold_mac = bind fold_mac_(_, fld);
 
     ret alt e {
+          expr_new(p, i, v) {
+            expr_new(fld.fold_expr(p),
+                     fld.new_id(i),
+                     fld.fold_expr(v))
+          }
           expr_vec(exprs, mutt) {
             expr_vec(fld.map_exprs(fld.fold_expr, exprs), mutt)
           }
diff --git a/src/rustc/syntax/parse/parser.rs b/src/rustc/syntax/parse/parser.rs
index 4fe7aade41c..99746aed84a 100644
--- a/src/rustc/syntax/parse/parser.rs
+++ b/src/rustc/syntax/parse/parser.rs
@@ -150,7 +150,7 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
                  "enum", "export", "fail", "fn", "for", "if",  "iface",
                  "impl", "import", "let", "log", "loop", "mod", "mut",
                  "mutable", "native", "pure", "resource", "ret", "trait",
-                 "type", "unchecked", "unsafe", "while"] {
+                 "type", "unchecked", "unsafe", "while", "new"] {
         words.insert(word, ());
     }
     words
@@ -852,6 +852,13 @@ fn parse_bottom_expr(p: parser) -> pexpr {
             let blk = parse_block_tail(p, lo, ast::default_blk);
             ret mk_pexpr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk));
         }
+    } else if eat_word(p, "new") {
+        expect(p, token::LPAREN);
+        let r = parse_expr(p);
+        expect(p, token::RPAREN);
+        let v = parse_expr(p);
+        ret mk_pexpr(p, lo, p.span.hi,
+                     ast::expr_new(r, p.get_id(), v));
     } else if eat_word(p, "if") {
         ret pexpr(parse_if_expr(p));
     } else if eat_word(p, "for") {
diff --git a/src/rustc/syntax/print/pprust.rs b/src/rustc/syntax/print/pprust.rs
index e10262117a4..6bdd4d84306 100644
--- a/src/rustc/syntax/print/pprust.rs
+++ b/src/rustc/syntax/print/pprust.rs
@@ -1089,6 +1089,13 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         word_nbsp(s, "assert");
         print_expr(s, expr);
       }
+      ast::expr_new(p, _, v) {
+        word_nbsp(s, "new");
+        popen(s);
+        print_expr(s, p);
+        pclose(s);
+        print_expr(s, v);
+      }
       ast::expr_mac(m) { print_mac(s, m); }
     }
     s.ann.post(ann_node);
diff --git a/src/rustc/syntax/visit.rs b/src/rustc/syntax/visit.rs
index c0b7eea6ace..fa3c043d647 100644
--- a/src/rustc/syntax/visit.rs
+++ b/src/rustc/syntax/visit.rs
@@ -315,6 +315,10 @@ fn visit_mac<E>(m: mac, e: E, v: vt<E>) {
 
 fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
     alt ex.node {
+      expr_new(pool, _, val) {
+        v.visit_expr(pool, e, v);
+        v.visit_expr(val, e, v);
+      }
       expr_vec(es, _) { visit_exprs(es, e, v); }
       expr_rec(flds, base) {
         for f: field in flds { v.visit_expr(f.node.expr, e, v); }