about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-08-19 14:34:45 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-08-22 10:16:09 +0200
commitb24f97801138cb675fbb9e9151d189b6527c4ef5 (patch)
treeba9c5a3fe56dd18c5e14a742b150cf240037eb67
parent35c962e9a18e1fc73939990865bfc799e485c23b (diff)
downloadrust-b24f97801138cb675fbb9e9151d189b6527c4ef5.tar.gz
rust-b24f97801138cb675fbb9e9151d189b6527c4ef5.zip
Drop arguments on the caller side, not the callee
This makes it easier for the caller to optimize the take/drop away for
temporary values, and opens up new possibilities for alias handling.

Breaks tail calls.
-rw-r--r--src/comp/driver/rustc.rs28
-rw-r--r--src/comp/middle/alias.rs24
-rw-r--r--src/comp/middle/trans.rs201
-rw-r--r--src/comp/middle/trans_common.rs1
-rw-r--r--src/comp/middle/trans_objects.rs12
-rw-r--r--src/comp/syntax/fold.rs1
-rw-r--r--src/comp/syntax/parse/parser.rs3
-rw-r--r--src/test/run-pass/export-unexported-dep.rs2
8 files changed, 125 insertions, 147 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index a75a46e64c7..a1981e1d283 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -148,26 +148,24 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
         time(time_passes, "freevar finding",
              bind freevars::annotate_freevars(sess, def_map, crate));
     let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
-    time::<()>(time_passes, "typechecking",
-               bind typeck::check_crate(ty_cx, crate));
-    time::<()>(time_passes, "alt checking",
-               bind middle::check_alt::check_crate(ty_cx, crate));
+    time(time_passes, "typechecking",
+         bind typeck::check_crate(ty_cx, crate));
+    time(time_passes, "alt checking",
+         bind middle::check_alt::check_crate(ty_cx, crate));
     if sess.get_opts().run_typestate {
         time(time_passes, "typestate checking",
              bind middle::tstate::ck::check_crate(ty_cx, crate));
     }
-    time(time_passes, "alias checking",
-         bind middle::alias::check_crate(ty_cx, crate));
-    time::<()>(time_passes, "kind checking",
-               bind kind::check_crate(ty_cx, crate));
+    let mut_map = time(time_passes, "alias checking",
+                       bind middle::alias::check_crate(ty_cx, crate));
+    time(time_passes, "kind checking",
+         bind kind::check_crate(ty_cx, crate));
     if sess.get_opts().no_trans { ret; }
-    let llmod =
-        time::<llvm::llvm::ModuleRef>(time_passes, "translation",
-                                      bind trans::trans_crate(sess, crate,
-                                                              ty_cx, output,
-                                                              ast_map));
-    time::<()>(time_passes, "LLVM passes",
-               bind link::write::run_passes(sess, llmod, output));
+    let llmod = time(time_passes, "translation",
+                     bind trans::trans_crate(sess, crate, ty_cx, output,
+                                             ast_map, mut_map));
+    time(time_passes, "LLVM passes",
+         bind link::write::run_passes(sess, llmod, output));
 }
 
 fn pretty_print_input(sess: session::session, cfg: ast::crate_cfg, input: str,
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index 738489bb400..e29c06c9239 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -36,20 +36,25 @@ type scope = @[restrict];
 
 tag local_info { arg(ast::mode); objfield(ast::mutability); }
 
-type ctx = {tcx: ty::ctxt, local_map: std::map::hashmap<node_id, local_info>};
+type mut_map = std::map::hashmap<node_id, ()>;
+type ctx = {tcx: ty::ctxt,
+            local_map: std::map::hashmap<node_id, local_info>,
+            mut_map: mut_map};
 
-fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) {
+fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) -> mut_map {
     // Stores information about object fields and function
     // arguments that's otherwise not easily available.
-    let cx = @{tcx: tcx, local_map: std::map::new_int_hash()};
-    let v =
-        @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
-          visit_item: bind visit_item(cx, _, _, _),
-          visit_expr: bind visit_expr(cx, _, _, _),
-          visit_decl: bind visit_decl(cx, _, _, _)
-             with *visit::default_visitor::<scope>()};
+    let cx = @{tcx: tcx,
+               local_map: std::map::new_int_hash(),
+               mut_map: std::map::new_int_hash()};
+    let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
+              visit_item: bind visit_item(cx, _, _, _),
+              visit_expr: bind visit_expr(cx, _, _, _),
+              visit_decl: bind visit_decl(cx, _, _, _)
+              with *visit::default_visitor::<scope>()};
     visit::visit_crate(*crate, @[], visit::mk_vt(v));
     tcx.sess.abort_if_errors();
+    ret cx.mut_map;
 }
 
 fn visit_fn(cx: &@ctx, f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span,
@@ -425,6 +430,7 @@ fn check_lval(cx: &@ctx, dest: &@ast::expr, sc: &scope, v: &vt<scope>) {
     alt dest.node {
       ast::expr_path(p) {
         let dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id)).node;
+        cx.mut_map.insert(dnum, ());
         if is_immutable_alias(*cx, sc, dnum) {
             cx.tcx.sess.span_err(dest.span, "assigning to immutable alias");
         } else if is_immutable_objfield(*cx, dnum) {
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index aecbe6a05f6..8932300257c 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3443,7 +3443,7 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef],
 
     // First, synthesize a tuple type containing the types of all the
     // bound expressions.
-    // bindings_ty = ~[bound_ty1, bound_ty2, ...]
+    // bindings_ty = [bound_ty1, bound_ty2, ...]
     let bindings_ty: ty::t = ty::mk_tup(bcx_tcx(bcx), bound_tys);
 
     // NB: keep this in sync with T_closure_ptr; we're making
@@ -4323,16 +4323,8 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
                     if is_val { T_ptr(llout_arg_ty) } else { llout_arg_ty };
                 val = bcx.build.PointerCast(val, ty);
             }
-            if is_val {
-                if type_is_immediate(cx.ccx, e_ty) {
-                    val = bcx.build.Load(val);
-                    bcx = copy_ty(bcx, val, e_ty).bcx;
-                } else {
-                    bcx = copy_ty(bcx, val, e_ty).bcx;
-                    if !ty::type_is_structural(cx.ccx.tcx, e_ty) {
-                        val = bcx.build.Load(val);
-                    }
-                }
+            if is_val && type_is_immediate(cx.ccx, e_ty) {
+                val = bcx.build.Load(val);
             }
             llargs += [val];
             b += 1;
@@ -4343,15 +4335,7 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
           none. {
             let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
             if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
-
-                // If the argument was passed by value and isn't a
-                // pointer type, we need to spill it to an alloca in
-                // order to do a pointer cast. Argh.
-                if is_val && !ty::type_is_boxed(cx.ccx.tcx, out_arg.ty) {
-                    let argp = do_spill(bcx, arg);
-                    argp = bcx.build.PointerCast(argp, T_ptr(llout_arg_ty));
-                    arg = bcx.build.Load(argp);
-                } else { arg = bcx.build.PointerCast(arg, llout_arg_ty); }
+                arg = bcx.build.PointerCast(arg, llout_arg_ty);
             }
             llargs += [arg];
             a += 1u;
@@ -4371,7 +4355,7 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
         type_of_fn_from_ty(bcx_ccx(bcx), sp, outgoing_fty, ty_param_count);
     lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
     lltargetfn = bcx.build.Load(lltargetfn);
-    llvm::LLVMSetTailCall(bcx.build.FastCall(lltargetfn, llargs), 1);
+    bcx.build.FastCall(lltargetfn, llargs);
     build_return(bcx);
     finish_fn(fcx, lltop);
     ret {val: llthunk, ty: llthunk_ty};
@@ -4468,29 +4452,30 @@ fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef,
         // to have type lldestty0 (the callee's expected type).
         val = llvm::LLVMGetUndef(lldestty0);
     } else if arg.mode == ty::mo_val {
-        if ty::type_owns_heap_mem(ccx.tcx, e_ty) {
+        // Eliding take/drop for appending of external vectors currently
+        // corrupts memory. I can't figure out why, and external vectors
+        // are on the way out anyway, so this simply turns off the
+        // optimization for that case.
+        let is_ext_vec_plus = alt e.node {
+          ast::expr_binary(_, _, _) {
+            ty::type_is_sequence(ccx.tcx, e_ty) &&
+                !ty::sequence_is_interior(ccx.tcx, e_ty)
+          }
+          _ { false }
+        };
+        if !lv.is_mem && !is_ext_vec_plus {
+            // Do nothing for temporaries, just give them to callee
+        } else if ty::type_is_structural(ccx.tcx, e_ty) {
             let dst = alloc_ty(bcx, e_ty);
+            bcx = copy_val(dst.bcx, INIT, dst.val, val, e_ty).bcx;
             val = dst.val;
-            bcx = move_val_if_temp(dst.bcx, INIT, val, lv, e_ty).bcx;
-        } else if lv.is_mem {
-            val = load_if_immediate(bcx, val, e_ty);
-            bcx = copy_ty(bcx, val, e_ty).bcx;
+            add_clean_temp(bcx, val, e_ty);
         } else {
-            // Eliding take/drop for appending of external vectors currently
-            // corrupts memory. I can't figure out why, and external vectors
-            // are on the way out anyway, so this simply turns off the
-            // optimization for that case.
-            let is_ext_vec_plus =
-                alt e.node {
-                  ast::expr_binary(_, _, _) {
-                    ty::type_is_sequence(ccx.tcx, e_ty) &&
-                        !ty::sequence_is_interior(ccx.tcx, e_ty)
-                  }
-                  _ { false }
-                };
-            if is_ext_vec_plus {
-                bcx = copy_ty(bcx, val, e_ty).bcx;
-            } else { revoke_clean(bcx, val); }
+            if lv.is_mem {
+                val = load_if_immediate(bcx, val, e_ty);
+            }
+            bcx = copy_ty(bcx, val, e_ty).bcx;
+            add_clean_temp(bcx, val, e_ty);
         }
     } else if type_is_immediate(ccx, e_ty) && !lv.is_mem {
         val = do_spill(bcx, val);
@@ -4620,13 +4605,14 @@ fn trans_args(cx: &@block_ctxt, llenv: ValueRef,
          to_revoke: to_revoke};
 }
 
-fn trans_call(cx: &@block_ctxt, f: &@ast::expr,
+fn trans_call(in_cx: &@block_ctxt, f: &@ast::expr,
               lliterbody: &option::t<ValueRef>, args: &[@ast::expr],
               id: ast::node_id) -> result {
     // NB: 'f' isn't necessarily a function; it might be an entire self-call
     // expression because of the hack that allows us to process self-calls
     // with trans_call.
-
+    let cx = new_scope_block_ctxt(in_cx, "call");
+    in_cx.build.Br(cx.llbb);
     let f_res = trans_lval_gen(cx, f);
     let fn_ty: ty::t;
     alt f_res.method_ty {
@@ -4691,7 +4677,7 @@ fn trans_call(cx: &@block_ctxt, f: &@ast::expr,
                 // Retval doesn't correspond to anything really tangible
                 // in the frame, but it's a ref all the same, so we put a
                 // note here to drop it when we're done in this scope.
-                add_clean_temp(cx, retval, ret_ty);
+                add_clean_temp(in_cx, retval, ret_ty);
             }
           }
           some(_) {
@@ -4705,7 +4691,13 @@ fn trans_call(cx: &@block_ctxt, f: &@ast::expr,
         for {v: v, t: t}: {v: ValueRef, t: ty::t} in args_res.to_zero {
             zero_alloca(bcx, v, t)
         }
-        for v: ValueRef in args_res.to_revoke { revoke_clean(bcx, v) }
+        for v: ValueRef in args_res.to_revoke {
+            revoke_clean(bcx, v)
+        }
+        bcx = trans_block_cleanups(bcx, cx);
+        let next_cx = new_sub_block_ctxt(in_cx, "next");
+        bcx.build.Br(next_cx.llbb);
+        bcx = next_cx;
     }
     ret rslt(bcx, retval);
 }
@@ -5230,7 +5222,9 @@ fn trans_fail_value(cx: &@block_ctxt, sp_opt: &option::t<span>,
     ret rslt(cx, C_nil());
 }
 
-fn trans_put(cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result {
+fn trans_put(in_cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result {
+    let cx = new_scope_block_ctxt(in_cx, "put");
+    in_cx.build.Br(cx.llbb);
     let llcallee = C_nil();
     let llenv = C_nil();
     alt { cx.fcx.lliterbody } {
@@ -5260,7 +5254,10 @@ fn trans_put(cx: &@block_ctxt, e: &option::t<@ast::expr>) -> result {
       }
     }
     bcx.build.FastCall(llcallee, llargs);
-    ret rslt(bcx, C_nil());
+    bcx = trans_block_cleanups(bcx, cx);
+    let next_cx = new_sub_block_ctxt(in_cx, "next");
+    bcx.build.Br(next_cx.llbb);
+    ret rslt(next_cx, C_nil());
 }
 
 fn trans_uniq(cx: &@block_ctxt, contents: &@ast::expr) -> lval_result {
@@ -5817,57 +5814,40 @@ fn create_llargs_for_fn_args(cx: &@fn_ctxt, proto: ast::proto,
     }
 }
 
-fn copy_args_to_allocas(fcx: @fn_ctxt, args: &[ast::arg],
-                        arg_tys: &[ty::arg]) {
+fn copy_args_to_allocas(fcx: @fn_ctxt, scope: @block_ctxt,
+                        args: &[ast::arg], arg_tys: &[ty::arg]) {
     let bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
     let arg_n: uint = 0u;
     for aarg: ast::arg in args {
-        if aarg.mode == ast::val {
-            let argval, arg_ty = arg_tys.(arg_n).ty;
-            alt bcx.fcx.llargs.find(aarg.id) {
-              some(x) { argval = x; }
-              _ {
-                bcx_ccx(bcx).sess.span_fatal(
-                    aarg.ty.span,
-                    "unbound arg ID in copy_args_to_allocas");
-              }
-            }
-            let a;
-            if ty::type_is_structural(fcx_tcx(fcx), arg_ty) {
-                a = alloca(bcx, llvm::LLVMGetElementType(val_ty(argval)));
-                bcx = memmove_ty(bcx, a, argval, arg_ty).bcx;
-            } else {
-                a = do_spill(bcx, argval);
+        let arg_ty = arg_tys[arg_n].ty;
+        alt aarg.mode {
+          ast::val. {
+            // Structural types are passed by pointer, and we use the
+            // pointed-to memory for the local.
+            if !ty::type_is_structural(fcx_tcx(fcx), arg_ty) {
+                // Overwrite the llargs entry for this arg with its alloca.
+                let aval = bcx.fcx.llargs.get(aarg.id);
+                let addr = do_spill(bcx, aval);
+                bcx.fcx.llargs.insert(aarg.id, addr);
+
+                // Args that are locally assigned to need to do a local
+                // take/drop
+                if fcx.lcx.ccx.mut_map.contains_key(aarg.id) {
+                    bcx = copy_ty(bcx, aval, arg_ty).bcx;
+                    add_clean(scope, addr, arg_ty);
+                }
             }
-
-            // Overwrite the llargs entry for this arg with its alloca.
-            bcx.fcx.llargs.insert(aarg.id, a);
+          }
+          ast::move. {
+            add_clean(scope, bcx.fcx.llargs.get(aarg.id), arg_ty);
+          }
+          _ {}
         }
         arg_n += 1u;
     }
     fcx.llcopyargs = bcx.llbb;
 }
 
-fn add_cleanups_for_args(bcx: &@block_ctxt, args: &[ast::arg],
-                         arg_tys: &[ty::arg]) {
-    let arg_n: uint = 0u;
-    for aarg: ast::arg in args {
-        if aarg.mode == ast::val || aarg.mode == ast::move {
-            let argval;
-            alt bcx.fcx.llargs.find(aarg.id) {
-              some(x) { argval = x; }
-              _ {
-                bcx_ccx(bcx).sess.span_fatal(
-                    aarg.ty.span,
-                    "unbound arg ID in add_cleanups_for_args");
-              }
-            }
-            add_clean(bcx, argval, arg_tys[arg_n].ty);
-        }
-        arg_n += 1u;
-    }
-}
-
 fn is_terminated(cx: &@block_ctxt) -> bool {
     let inst = llvm::LLVMGetLastInstruction(cx.llbb);
     ret llvm::LLVMIsATerminatorInst(inst) as int != 0;
@@ -5964,8 +5944,15 @@ fn trans_closure(bcx_maybe: &option::t<@block_ctxt>,
       some(llself) { populate_fn_ctxt_from_llself(fcx, llself); }
       _ { }
     }
+
+    // Create the first basic block in the function and keep a handle on it to
+    //  pass to finish_fn later.
+    let bcx = new_top_block_ctxt(fcx);
+    let lltop = bcx.llbb;
+    let block_ty = node_id_type(cx.ccx, f.body.node.id);
+
     let arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id);
-    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
+    copy_args_to_allocas(fcx, bcx, f.decl.inputs, arg_tys);
 
     // Figure out if we need to build a closure and act accordingly
     let res =
@@ -5989,12 +5976,6 @@ fn trans_closure(bcx_maybe: &option::t<@block_ctxt>,
           _ { none }
         };
 
-    // Create the first basic block in the function and keep a handle on it to
-    //  pass to finish_fn later.
-    let bcx = new_top_block_ctxt(fcx);
-    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
-    let lltop = bcx.llbb;
-    let block_ty = node_id_type(cx.ccx, f.body.node.id);
 
     // This call to trans_block is the place where we bridge between
     // translation calls that don't have a return value (trans_crate,
@@ -6119,8 +6100,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
         i += 1u;
     }
     let arg_tys = arg_tys_of_fn(cx.ccx, variant.node.id);
-    copy_args_to_allocas(fcx, fn_args, arg_tys);
     let bcx = new_top_block_ctxt(fcx);
+    copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
     let lltop = bcx.llbb;
 
     // Cast the tag to a type we can GEP into.
@@ -6333,16 +6314,12 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span, main_llfn: ValueRef,
         let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
         let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
         let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
-        let args = if takes_ivec {
-            ~[lloutputarg, lltaskarg, llenvarg, llargvarg]
-        } else {
-            // If the crate's main function doesn't take the args vector then
-            // we're responsible for freeing it
-            bcx = maybe_free_ivec_heap_part(bcx, llargvarg,
-                                            ty::mk_str(ccx.tcx)).bcx;
-            ~[lloutputarg, lltaskarg, llenvarg]
-        };
+        let args = [lloutputarg, lltaskarg, llenvarg];
+        if takes_ivec { args += [llargvarg]; }
         bcx.build.FastCall(main_llfn, args);
+        // We're responsible for freeing the arg vector
+        bcx = maybe_free_ivec_heap_part(bcx, llargvarg,
+                                        ty::mk_str(ccx.tcx)).bcx;
         build_return(bcx);
 
         finish_fn(fcx, lltop);
@@ -6555,7 +6532,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str],
     let args = ty::ty_fn_args(ccx.tcx, fn_type);
     // Build up the list of arguments.
 
-    let drop_args: [{val: ValueRef, ty: ty::t}] = [];
     let i = arg_n;
     for arg: ty::arg in args {
         let llarg = llvm::LLVMGetParam(fcx.llfn, i);
@@ -6564,7 +6540,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str],
             let llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
             call_args += [llarg_i32];
         } else { call_args += [llarg]; }
-        if arg.mode == ty::mo_val { drop_args += [{val: llarg, ty: arg.ty}]; }
         i += 1u;
     }
     let r;
@@ -6594,9 +6569,8 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str],
         rptr = result.rptr;
       }
       _ {
-        r =
-            trans_native_call(bcx.build, ccx.externs, ccx.llmod, name,
-                              call_args);
+        r = trans_native_call(bcx.build, ccx.externs,
+                              ccx.llmod, name, call_args);
         rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
       }
     }
@@ -6606,9 +6580,6 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str],
 
     if !rty_is_nil && !uses_retptr { bcx.build.Store(r, rptr); }
 
-    for d: {val: ValueRef, ty: ty::t} in drop_args {
-        bcx = drop_ty(bcx, d.val, d.ty).bcx;
-    }
     build_return(bcx);
     finish_fn(fcx, lltop);
 }
@@ -6927,7 +6898,8 @@ fn write_abi_version(ccx: &@crate_ctxt) {
 }
 
 fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt,
-               output: &str, amap: &ast_map::map) -> ModuleRef {
+               output: &str, amap: &ast_map::map, mut_map: alias::mut_map)
+    -> ModuleRef {
     let llmod =
         llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
                                                 llvm::LLVMGetGlobalContext());
@@ -6979,6 +6951,7 @@ fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt,
           type_sha1s: sha1s,
           type_short_names: short_names,
           tcx: tcx,
+          mut_map: mut_map,
           stats:
               {mutable n_static_tydescs: 0u,
                mutable n_derived_tydescs: 0u,
diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs
index e53f4a47b27..bf7a03cdbf1 100644
--- a/src/comp/middle/trans_common.rs
+++ b/src/comp/middle/trans_common.rs
@@ -142,6 +142,7 @@ type crate_ctxt =
      type_sha1s: hashmap<ty::t, str>,
      type_short_names: hashmap<ty::t, str>,
      tcx: ty::ctxt,
+     mut_map: alias::mut_map,
      stats: stats,
      upcalls: @upcall::upcalls,
      rust_object_type: TypeRef,
diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs
index 06094808fad..5bbd281ef48 100644
--- a/src/comp/middle/trans_objects.rs
+++ b/src/comp/middle/trans_objects.rs
@@ -50,17 +50,17 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
     }
     let fcx = new_fn_ctxt(cx, sp, llctor_decl);
 
+    //  Create the first block context in the function and keep a handle on it
+    //  to pass to finish_fn later.
+    let bcx = new_top_block_ctxt(fcx);
+    let lltop = bcx.llbb;
+
     // Both regular arguments and type parameters are handled here.
     create_llargs_for_fn_args(fcx, ast::proto_fn, none::<ty::t>,
                               ty::ret_ty_of_fn(ccx.tcx, ctor_id), fn_args,
                               ty_params);
     let arg_tys: [ty::arg] = arg_tys_of_fn(ccx, ctor_id);
-    copy_args_to_allocas(fcx, fn_args, arg_tys);
-
-    //  Create the first block context in the function and keep a handle on it
-    //  to pass to finish_fn later.
-    let bcx = new_top_block_ctxt(fcx);
-    let lltop = bcx.llbb;
+    copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
 
     // Pick up the type of this object by looking at our own output type, that
     // is, the output type of the object constructor we're building.
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index b781a2481c2..ef04e66d756 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -334,7 +334,6 @@ fn noop_fold_expr(e: &expr_, fld: ast_fold) -> expr_ {
 
     let fold_mac = bind fold_mac_(_, fld);
 
-
     ret alt e {
           expr_vec(exprs, mut) {
             expr_vec(fld.map_exprs(fld.fold_expr, exprs), mut)
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 8cf53edbc9d..d20f345b3af 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1081,7 +1081,8 @@ fn parse_dot_or_call_expr_with(p: &parser, e: @ast::expr) -> @ast::expr {
                     parse_seq(token::LPAREN, token::RPAREN,
                               some(token::COMMA), parse_expr, p);
                 hi = es.span.hi;
-                e = mk_expr(p, lo, hi, ast::expr_call(e, es.node));
+                let nd = ast::expr_call(e, es.node);
+                e = mk_expr(p, lo, hi, nd);
             }
           }
           token::LBRACKET. {
diff --git a/src/test/run-pass/export-unexported-dep.rs b/src/test/run-pass/export-unexported-dep.rs
index bc8451a4854..357821ac34e 100644
--- a/src/test/run-pass/export-unexported-dep.rs
+++ b/src/test/run-pass/export-unexported-dep.rs
@@ -6,7 +6,7 @@ mod foo {
     export g;
 
     // not exported
-    tag t { t1; }
+    tag t { t1; t2; }
 
     fn f() -> t { ret t1; }