about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-01-21 07:58:16 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-01-21 07:59:56 -0800
commit8bc57fa85e6191117c8c27bf53f8e051e13783c3 (patch)
tree663f8d067457d0abe92e319e0b5c63a001fa1127
parent2c27feb76a4754faee6e997339826c6f2afc1432 (diff)
downloadrust-8bc57fa85e6191117c8c27bf53f8e051e13783c3.tar.gz
rust-8bc57fa85e6191117c8c27bf53f8e051e13783c3.zip
Tweak effect-checking rules in rustboot, remove/rewrite/re-auth impure cases in trans.rs
-rw-r--r--src/boot/me/effect.ml89
-rw-r--r--src/comp/middle/trans.rs313
-rw-r--r--src/comp/rustc.rc2
3 files changed, 221 insertions, 183 deletions
diff --git a/src/boot/me/effect.ml b/src/boot/me/effect.ml
index 3d52f23a1d9..fc4d03b17d3 100644
--- a/src/boot/me/effect.ml
+++ b/src/boot/me/effect.ml
@@ -179,8 +179,7 @@ let effect_checking_visitor
               then Ast.EFF_pure
               else Stack.top auth_stack
             in
-            let next = lower_effect_of e curr in
-              Stack.push next auth_stack;
+              Stack.push e auth_stack;
               iflog cx
                 begin
                   fun _ ->
@@ -189,40 +188,62 @@ let effect_checking_visitor
                         "entering '%a', adjusting auth effect: '%a' -> '%a'"
                         Ast.sprintf_name name
                         Ast.sprintf_effect curr
-                        Ast.sprintf_effect next
+                        Ast.sprintf_effect e
                 end
     end;
+    let report_mismatch declared_effect calculated_effect =
+      let name = Hashtbl.find cx.ctxt_all_item_names i.id in
+        err (Some i.id)
+          "%a claims effect '%a' but calculated effect is '%a'%s"
+          Ast.sprintf_name name
+          Ast.sprintf_effect declared_effect
+          Ast.sprintf_effect calculated_effect
+          begin
+            if Stack.is_empty auth_stack
+            then ""
+            else
+              Printf.sprintf " (auth effects are '%s')"
+                (stk_fold
+                   auth_stack
+                   (fun e s ->
+                      if s = ""
+                      then
+                        Printf.sprintf "%a"
+                          Ast.sprintf_effect e
+                      else
+                        Printf.sprintf "%s, %a" s
+                          Ast.sprintf_effect e) "")
+          end
+    in
     begin
       match i.node.Ast.decl_item with
           Ast.MOD_ITEM_fn f
             when htab_search cx.ctxt_required_items i.id = None ->
-            let e =
+            let calculated_effect =
               match htab_search item_effect i.id with
                 None -> Ast.EFF_pure
               | Some e -> e
             in
-            let fe = f.Ast.fn_aux.Ast.fn_effect in
-            let ae =
-              if Stack.is_empty auth_stack
-              then None
-              else Some (Stack.top auth_stack)
-            in
-              if e <> fe && (ae <> (Some e))
+            let declared_effect = f.Ast.fn_aux.Ast.fn_effect in
+              if calculated_effect <> declared_effect
               then
+                (* Something's fishy in this case. If the calculated effect
+                 * is equal to one auth'ed by an enclosing scope -- not just
+                 * a lower one -- we accept this mismatch; otherwise we
+                 * complain.
+                 * 
+                 * FIXME: this choice of "what constitutes an error" in
+                 * auth/effect mismatches is subjective and could do
+                 * with some discussion.  *)
                 begin
-                  let name = Hashtbl.find cx.ctxt_all_item_names i.id in
-                    err (Some i.id)
-                      "%a claims effect '%a' but calculated effect is '%a'%s"
-                      Ast.sprintf_name name
-                      Ast.sprintf_effect fe
-                      Ast.sprintf_effect e
-                      begin
-                        match ae with
-                            Some ae when ae <> fe ->
-                              Printf.sprintf " (auth effect is '%a')"
-                                Ast.sprintf_effect ae
-                          | _ -> ""
-                      end
+                  match
+                    stk_search auth_stack
+                      (fun e ->
+                         if e = calculated_effect then Some e else None)
+                  with
+                      Some _ -> ()
+                    | None ->
+                        report_mismatch declared_effect calculated_effect
                 end
         | _ -> ()
     end;
@@ -239,16 +260,16 @@ let effect_checking_visitor
             then Ast.EFF_pure
             else Stack.top auth_stack
           in
-          iflog cx
-            begin
-              fun _ ->
-                let name = Hashtbl.find cx.ctxt_all_item_names i.id in
-                  log cx
-                    "leaving '%a', restoring auth effect: '%a' -> '%a'"
-                    Ast.sprintf_name name
-                    Ast.sprintf_effect curr
-                    Ast.sprintf_effect next
-            end
+            iflog cx
+              begin
+                fun _ ->
+                  let name = Hashtbl.find cx.ctxt_all_item_names i.id in
+                    log cx
+                      "leaving '%a', restoring auth effect: '%a' -> '%a'"
+                      Ast.sprintf_name name
+                      Ast.sprintf_effect curr
+                      Ast.sprintf_effect next
+              end
   in
     { inner with
         Walk.visit_mod_item_pre = visit_mod_item_pre;
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 1b895193a56..a7770b942e2 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -1504,7 +1504,7 @@ fn copy_ty(@block_ctxt cx,
     fail;
 }
 
-impure fn trans_lit(@block_ctxt cx, &ast.lit lit, &ast.ann ann) -> result {
+fn trans_lit(@block_ctxt cx, &ast.lit lit, &ast.ann ann) -> result {
     alt (lit.node) {
         case (ast.lit_int(?i)) {
             ret res(cx, C_int(i));
@@ -1547,12 +1547,12 @@ impure fn trans_lit(@block_ctxt cx, &ast.lit lit, &ast.ann ann) -> result {
             auto sub = trans_upcall(cx, "upcall_new_str",
                                     vec(p2i(C_str(cx.fcx.ccx, s)),
                                         C_int(len)));
-            sub.val = sub.bcx.build.IntToPtr(sub.val,
-                                             T_ptr(T_str()));
+            auto val = sub.bcx.build.IntToPtr(sub.val,
+                                              T_ptr(T_str()));
             auto t = node_ann_type(cx.fcx.ccx, ann);
             find_scope_cx(cx).cleanups +=
-                clean(bind drop_ty(_, sub.val, t));
-            ret sub;
+                clean(bind drop_ty(_, val, t));
+            ret res(sub.bcx, val);
         }
     }
 }
@@ -1587,24 +1587,21 @@ fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
     ret type_of(cx, node_ann_type(cx, a));
 }
 
-impure fn trans_unary(@block_ctxt cx, ast.unop op,
-                      @ast.expr e, &ast.ann a) -> result {
+fn trans_unary(@block_ctxt cx, ast.unop op,
+               @ast.expr e, &ast.ann a) -> result {
 
     auto sub = trans_expr(cx, e);
 
     alt (op) {
         case (ast.bitnot) {
-            sub.val = cx.build.Not(sub.val);
-            ret sub;
+            ret res(sub.bcx, cx.build.Not(sub.val));
         }
         case (ast.not) {
-            sub.val = cx.build.Not(sub.val);
-            ret sub;
+            ret res(sub.bcx, cx.build.Not(sub.val));
         }
         case (ast.neg) {
             // FIXME: switch by signedness.
-            sub.val = cx.build.Neg(sub.val);
-            ret sub;
+            ret res(sub.bcx, cx.build.Neg(sub.val));
         }
         case (ast.box) {
             auto e_ty = ty.expr_ty(e);
@@ -1622,15 +1619,15 @@ impure fn trans_unary(@block_ctxt cx, ast.unop op,
             ret res(sub.bcx, box);
         }
         case (ast.deref) {
-            sub.val = sub.bcx.build.GEP(sub.val,
-                                        vec(C_int(0),
-                                            C_int(abi.box_rc_field_body)));
+            auto val = sub.bcx.build.GEP(sub.val,
+                                         vec(C_int(0),
+                                             C_int(abi.box_rc_field_body)));
             auto e_ty = node_ann_type(sub.bcx.fcx.ccx, a);
             if (ty.type_is_scalar(e_ty) ||
                 ty.type_is_nil(e_ty)) {
-                sub.val = sub.bcx.build.Load(sub.val);
+                val = sub.bcx.build.Load(val);
             }
-            ret sub;
+            ret res(sub.bcx, val);
         }
     }
     fail;
@@ -1672,8 +1669,8 @@ fn trans_eager_binop(@block_ctxt cx, ast.binop op,
     fail;
 }
 
-impure fn trans_binary(@block_ctxt cx, ast.binop op,
-                       @ast.expr a, @ast.expr b) -> result {
+fn trans_binary(@block_ctxt cx, ast.binop op,
+                @ast.expr a, @ast.expr b) -> result {
 
     // First couple cases are lazy:
 
@@ -1769,8 +1766,8 @@ fn join_results(@block_ctxt parent_cx,
     ret res(join_cx, phi);
 }
 
-impure fn trans_if(@block_ctxt cx, @ast.expr cond,
-                   &ast.block thn, &option.t[ast.block] els) -> result {
+fn trans_if(@block_ctxt cx, @ast.expr cond,
+            &ast.block thn, &option.t[ast.block] els) -> result {
 
     auto cond_res = trans_expr(cx, cond);
 
@@ -1796,8 +1793,8 @@ impure fn trans_if(@block_ctxt cx, @ast.expr cond,
                      vec(then_res, else_res));
 }
 
-impure fn trans_while(@block_ctxt cx, @ast.expr cond,
-                      &ast.block body) -> result {
+fn trans_while(@block_ctxt cx, @ast.expr cond,
+               &ast.block body) -> result {
 
     auto cond_cx = new_scope_block_ctxt(cx, "while cond");
     auto body_cx = new_scope_block_ctxt(cx, "while loop body");
@@ -1815,8 +1812,8 @@ impure fn trans_while(@block_ctxt cx, @ast.expr cond,
     ret res(next_cx, C_nil());
 }
 
-impure fn trans_do_while(@block_ctxt cx, &ast.block body,
-                         @ast.expr cond) -> result {
+fn trans_do_while(@block_ctxt cx, &ast.block body,
+                  @ast.expr cond) -> result {
 
     auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
     auto next_cx = new_sub_block_ctxt(cx, "next");
@@ -1850,8 +1847,8 @@ fn get_pat_union_ptr(@block_ctxt cx, vec[@ast.pat] subpats, ValueRef llval)
     ret cx.build.TruncOrBitCast(llblobptr, T_ptr(llunionty));
 }
 
-impure fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
-                          @block_ctxt next_cx) -> result {
+fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
+                   @block_ctxt next_cx) -> result {
     alt (pat.node) {
         case (ast.pat_wild(_)) { ret res(cx, llval); }
         case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
@@ -1903,8 +1900,8 @@ impure fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
     fail;
 }
 
-impure fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
-        -> result {
+fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
+    -> result {
     alt (pat.node) {
         case (ast.pat_wild(_)) { ret res(cx, llval); }
         case (ast.pat_bind(?id, ?def_id, ?ann)) {
@@ -1941,8 +1938,8 @@ impure fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
     }
 }
 
-impure fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
-        -> result {
+fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
+    -> result {
     auto expr_res = trans_expr(cx, expr);
 
     auto last_cx = new_sub_block_ctxt(expr_res.bcx, "last");
@@ -2068,8 +2065,8 @@ fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
     fail;
 }
 
-impure fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
-                      &ast.ident field, &ast.ann ann) -> lval_result {
+fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
+               &ast.ident field, &ast.ann ann) -> lval_result {
     auto lv = trans_lval(cx, base);
     auto r = lv.res;
     check (lv.is_mem);
@@ -2102,8 +2099,8 @@ impure fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
     fail;
 }
 
-impure fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
-                      @ast.expr idx, &ast.ann ann) -> lval_result {
+fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
+               @ast.expr idx, &ast.ann ann) -> lval_result {
 
     auto lv = trans_expr(cx, base);
     auto ix = trans_expr(lv.bcx, idx);
@@ -2140,7 +2137,7 @@ impure fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
 // represented as an alloca or heap, hence needs a 'load' to be used as an
 // immediate).
 
-impure fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
+fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
     alt (e.node) {
         case (ast.expr_path(?p, ?dopt, ?ann)) {
             ret trans_path(cx, p, dopt, ann);
@@ -2156,7 +2153,7 @@ impure fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
     fail;
 }
 
-impure fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
+fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
     auto e_res = trans_expr(cx, e);
     auto llsrctype = val_ty(e_res.val);
     auto t = node_ann_type(cx.fcx.ccx, ann);
@@ -2189,12 +2186,12 @@ impure fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
 
 
 // NB: this must match type_of_fn_full and create_llargs_for_fn_args.
-impure fn trans_args(@block_ctxt cx,
-                     ValueRef llclosure,
-                     option.t[ValueRef] llobj,
-                     option.t[generic_info] gen,
-                     &vec[@ast.expr] es,
-                     @ty.t fn_ty)
+fn trans_args(@block_ctxt cx,
+              ValueRef llclosure,
+              option.t[ValueRef] llobj,
+              option.t[generic_info] gen,
+              &vec[@ast.expr] es,
+              @ty.t fn_ty)
     -> tup(@block_ctxt, vec[ValueRef], option.t[ValueRef]) {
     let vec[ValueRef] vs = vec(cx.fcx.lltaskptr);
     let @block_ctxt bcx = cx;
@@ -2236,13 +2233,15 @@ impure fn trans_args(@block_ctxt cx,
     for (@ast.expr e in es) {
         auto mode = args.(i).mode;
 
-        auto re;
+        auto val;
         if (ty.type_is_structural(ty.expr_ty(e))) {
-            re = trans_expr(bcx, e);
+            auto re = trans_expr(bcx, e);
+            val = re.val;
+            bcx = re.bcx;
             if (mode == ast.val) {
                 // Until here we've been treating structures by pointer;
                 // we are now passing it as an arg, so need to load it.
-                re.val = re.bcx.build.Load(re.val);
+                val = bcx.build.Load(val);
             }
         } else if (mode == ast.alias) {
             let lval_result lv;
@@ -2252,42 +2251,42 @@ impure fn trans_args(@block_ctxt cx,
                 auto r = trans_expr(bcx, e);
                 lv = lval_val(r.bcx, r.val);
             }
+            bcx = lv.res.bcx;
 
-            if (!lv.is_mem) {
+            if (lv.is_mem) {
+                val = lv.res.val;
+            } else {
                 // Non-mem but we're trying to alias; synthesize an
                 // alloca, spill to it and pass its address.
                 auto llty = val_ty(lv.res.val);
                 auto llptr = lv.res.bcx.build.Alloca(llty);
                 lv.res.bcx.build.Store(lv.res.val, llptr);
-                re = res(lv.res.bcx, llptr);
-            } else {
-                re = lv.res;
+                val = llptr;
             }
 
         } else {
-            re = trans_expr(bcx, e);
+            auto re = trans_expr(bcx, e);
+            val = re.val;
+            bcx = re.bcx;
         }
 
         if (ty.type_has_dynamic_size(args.(i).ty)) {
-            re.val = re.bcx.build.PointerCast(re.val,
-                                              T_typaram_ptr());
+            val = bcx.build.PointerCast(val, T_typaram_ptr());
         }
 
-        vs += re.val;
-        bcx = re.bcx;
-
+        vs += val;
         i += 1u;
     }
 
     ret tup(bcx, vs, llretslot_opt);
 }
 
-impure fn trans_bind_thunk(@crate_ctxt cx,
-                           @ty.t incoming_fty,
-                           @ty.t outgoing_fty,
-                           vec[option.t[@ast.expr]] args,
-                           TypeRef llclosure_ty,
-                           vec[@ty.t] bound_tys) -> ValueRef {
+fn trans_bind_thunk(@crate_ctxt cx,
+                    @ty.t incoming_fty,
+                    @ty.t outgoing_fty,
+                    vec[option.t[@ast.expr]] args,
+                    TypeRef llclosure_ty,
+                    vec[@ty.t] bound_tys) -> ValueRef {
     // Construct a thunk-call with signature incoming_fty, and that copies
     // args forward into a call to outgoing_fty.
 
@@ -2371,9 +2370,9 @@ impure fn trans_bind_thunk(@crate_ctxt cx,
     ret llthunk;
 }
 
-impure fn trans_bind(@block_ctxt cx, @ast.expr f,
-                     vec[option.t[@ast.expr]] args,
-                     &ast.ann ann) -> result {
+fn trans_bind(@block_ctxt cx, @ast.expr f,
+              vec[option.t[@ast.expr]] args,
+              &ast.ann ann) -> result {
     auto f_res = trans_lval(cx, f);
     if (f_res.is_mem) {
         cx.fcx.ccx.sess.unimpl("re-binding existing function");
@@ -2483,8 +2482,8 @@ impure fn trans_bind(@block_ctxt cx, @ast.expr f,
     }
 }
 
-impure fn trans_call(@block_ctxt cx, @ast.expr f,
-                     vec[@ast.expr] args, &ast.ann ann) -> result {
+fn trans_call(@block_ctxt cx, @ast.expr f,
+              vec[@ast.expr] args, &ast.ann ann) -> result {
     auto f_res = trans_lval(cx, f);
     auto faddr = f_res.res.val;
     auto llclosure = C_null(T_opaque_closure_ptr());
@@ -2551,8 +2550,8 @@ impure fn trans_call(@block_ctxt cx, @ast.expr f,
     ret res(bcx, retval);
 }
 
-impure fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
-                    &ast.ann ann) -> result {
+fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
+             &ast.ann ann) -> result {
     auto t = node_ann_type(cx.fcx.ccx, ann);
     auto llty = type_of(cx.fcx.ccx, t);
     auto tup_val = cx.build.Alloca(llty);
@@ -2569,8 +2568,8 @@ impure fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
     ret res(r.bcx, tup_val);
 }
 
-impure fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
-                    &ast.ann ann) -> result {
+fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
+             &ast.ann ann) -> result {
     auto t = node_ann_type(cx.fcx.ccx, ann);
     auto unit_ty = t;
     alt (t.struct) {
@@ -2610,8 +2609,8 @@ impure fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
     ret res(sub.bcx, vec_val);
 }
 
-impure fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
-                    &ast.ann ann) -> result {
+fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
+             &ast.ann ann) -> result {
     auto t = node_ann_type(cx.fcx.ccx, ann);
     auto llty = type_of(cx.fcx.ccx, t);
     auto rec_val = cx.build.Alloca(llty);
@@ -2631,7 +2630,7 @@ impure fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
 
 
 
-impure fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
+fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
     alt (e.node) {
         case (ast.expr_lit(?lit, ?ann)) {
             ret trans_lit(cx, *lit, ann);
@@ -2745,7 +2744,7 @@ fn load_scalar_or_boxed(@block_ctxt cx,
     }
 }
 
-impure fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
+fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
 
     auto sub = trans_expr(cx, e);
     auto e_ty = ty.expr_ty(e);
@@ -2765,7 +2764,7 @@ impure fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
     fail;
 }
 
-impure fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
+fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
     auto cond_res = trans_expr(cx, e);
 
     // FIXME: need pretty-printer.
@@ -2785,23 +2784,27 @@ impure fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
     ret res(next_cx, C_nil());
 }
 
-impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
-    auto r = res(cx, C_nil());
+fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
+    auto bcx = cx;
+    auto val = C_nil();
+
     alt (e) {
         case (some[@ast.expr](?x)) {
             auto t = ty.expr_ty(x);
-            r = trans_expr(cx, x);
+            auto r = trans_expr(cx, x);
+            bcx = r.bcx;
+            val = r.val;
 
             // A return is an implicit copy into a newborn anonymous
             // 'return value' in the caller frame.
-            r.bcx = incr_all_refcnts(r.bcx, r.val, t).bcx;
+            bcx = incr_all_refcnts(bcx, val, t).bcx;
 
             if (ty.type_is_structural(t)) {
                 // We usually treat structurals by-pointer; in particular,
                 // trans_expr will have given us a structure pointer. But in
                 // this case we're about to return. LLVM wants a first-class
                 // value here (which makes sense; the frame is going away!)
-                r.val = r.bcx.build.Load(r.val);
+                val = r.bcx.build.Load(val);
             }
         }
         case (_) { /* fall through */  }
@@ -2811,7 +2814,7 @@ impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
     let bool more_cleanups = true;
     auto cleanup_cx = cx;
     while (more_cleanups) {
-        r.bcx = trans_block_cleanups(r.bcx, cleanup_cx);
+        bcx = trans_block_cleanups(bcx, cleanup_cx);
         alt (cleanup_cx.parent) {
             case (parent_some(?b)) {
                 cleanup_cx = b;
@@ -2827,80 +2830,87 @@ impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
             auto t = ty.expr_ty(ex);
 
             if (ty.type_is_nil(t)) {
-                r.bcx.build.RetVoid();
-                r.val = C_nil();
-                ret r;  // FIXME: early return needed due to typestate bug
+                bcx.build.RetVoid();
+                val = C_nil();
+                ret res(bcx, val);  // FIXME: early return needed due to
+                                    // typestate bug
             }
 
             alt (cx.fcx.llretptr) {
                 case (some[ValueRef](?llptr)) {
                     // Generic return via tydesc + retptr.
-                    r = copy_ty(r.bcx, true, llptr, r.val, t);
-                    r.bcx.build.RetVoid();
+                    bcx = copy_ty(bcx, true, llptr, val, t).bcx;
+                    bcx.build.RetVoid();
                 }
                 case (none[ValueRef]) {
-                    r.val = r.bcx.build.Ret(r.val);
+                    val = bcx.build.Ret(val);
                 }
             }
-            ret r;
+            ret res(bcx, val);
         }
         case (_) { /* fall through */  }
     }
 
     // FIXME: until LLVM has a unit type, we are moving around
     // C_nil values rather than their void type.
-    r.bcx.build.RetVoid();
-    r.val = C_nil();
-    ret r;
+    bcx.build.RetVoid();
+    ret res(bcx, C_nil());
+}
+
+fn init_local(@block_ctxt cx, @ast.local local) -> result {
+
+    // Make a note to drop this slot on the way out.
+    check (cx.fcx.lllocals.contains_key(local.id));
+    auto llptr = cx.fcx.lllocals.get(local.id);
+    auto ty = node_ann_type(cx.fcx.ccx, local.ann);
+    auto bcx = cx;
+
+    find_scope_cx(cx).cleanups +=
+        clean(bind drop_slot(_, llptr, ty));
+
+    alt (local.init) {
+        case (some[@ast.expr](?e)) {
+            auto sub = trans_expr(bcx, e);
+            bcx = copy_ty(sub.bcx, true, llptr, sub.val, ty).bcx;
+        }
+        case (_) {
+            if (middle.ty.type_has_dynamic_size(ty)) {
+                auto llsz = size_of(cx, ty);
+                bcx = call_bzero(cx, llptr, llsz).bcx;
+
+            } else {
+                auto llty = type_of(bcx.fcx.ccx, ty);
+                auto null = lib.llvm.llvm.LLVMConstNull(llty);
+                bcx.build.Store(null, llptr);
+            }
+        }
+    }
+    ret res(bcx, llptr);
 }
 
-impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
-    auto sub = res(cx, C_nil());
+fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
+    auto bcx = cx;
     alt (s.node) {
         case (ast.stmt_log(?a)) {
-            sub.bcx = trans_log(cx, a).bcx;
+            bcx = trans_log(cx, a).bcx;
         }
 
         case (ast.stmt_check_expr(?a)) {
-            sub.bcx = trans_check_expr(cx, a).bcx;
+            bcx = trans_check_expr(cx, a).bcx;
         }
 
         case (ast.stmt_ret(?e)) {
-            sub.bcx = trans_ret(cx, e).bcx;
+            bcx = trans_ret(cx, e).bcx;
         }
 
         case (ast.stmt_expr(?e)) {
-            sub.bcx = trans_expr(cx, e).bcx;
+            bcx = trans_expr(cx, e).bcx;
         }
 
         case (ast.stmt_decl(?d)) {
             alt (d.node) {
                 case (ast.decl_local(?local)) {
-
-                    // Make a note to drop this slot on the way out.
-                    check (cx.fcx.lllocals.contains_key(local.id));
-                    auto llptr = cx.fcx.lllocals.get(local.id);
-                    auto ty = node_ann_type(cx.fcx.ccx, local.ann);
-                    find_scope_cx(cx).cleanups +=
-                        clean(bind drop_slot(_, llptr, ty));
-
-                    alt (local.init) {
-                        case (some[@ast.expr](?e)) {
-                            sub = trans_expr(cx, e);
-                            sub = copy_ty(sub.bcx, true, llptr, sub.val, ty);
-                        }
-                        case (_) {
-                            if (middle.ty.type_has_dynamic_size(ty)) {
-                                auto llsz = size_of(cx, ty);
-                                sub = call_bzero(cx, llptr, llsz);
-
-                            } else {
-                                auto llty = type_of(cx.fcx.ccx, ty);
-                                auto null = lib.llvm.llvm.LLVMConstNull(llty);
-                                sub = res(cx, cx.build.Store(null, llptr));
-                            }
-                        }
-                    }
+                    bcx = init_local(bcx, local).bcx;
                 }
                 case (ast.decl_item(?i)) {
                     trans_item(cx.fcx.ccx, *i);
@@ -2911,7 +2921,7 @@ impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
             cx.fcx.ccx.sess.unimpl("stmt variant");
         }
     }
-    ret sub;
+    ret res(bcx, C_nil());
 }
 
 fn new_builder(BasicBlockRef llbb) -> builder {
@@ -2990,19 +3000,24 @@ iter block_locals(&ast.block b) -> @ast.local {
     }
 }
 
-impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
+fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
+    auto t = node_ann_type(cx.fcx.ccx, local.ann);
+    auto val = C_int(0);
+    if (ty.type_has_dynamic_size(t)) {
+        auto n = size_of(cx, t);
+        val = cx.build.ArrayAlloca(T_i8(), n);
+    } else {
+        val = cx.build.Alloca(type_of(cx.fcx.ccx, t));
+    }
+    cx.fcx.lllocals.insert(local.id, val);
+    ret res(cx, val);
+}
+
+fn trans_block(@block_ctxt cx, &ast.block b) -> result {
     auto bcx = cx;
 
     for each (@ast.local local in block_locals(b)) {
-        auto t = node_ann_type(cx.fcx.ccx, local.ann);
-        auto val = C_int(0);
-        if (ty.type_has_dynamic_size(t)) {
-            auto n = size_of(bcx, t);
-            val = bcx.build.ArrayAlloca(T_i8(), n);
-        } else {
-            val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
-        }
-        cx.fcx.lllocals.insert(local.id, val);
+        bcx = alloc_local(bcx, local).bcx;
     }
     auto r = res(bcx, C_nil());
 
@@ -3102,10 +3117,10 @@ fn create_llargs_for_fn_args(&@fn_ctxt cx,
 // allocas immediately upon entry; this permits us to GEP into structures we
 // were passed and whatnot. Apparently mem2reg will mop up.
 
-impure fn copy_args_to_allocas(@block_ctxt cx,
-                               option.t[TypeRef] ty_self,
-                               vec[ast.arg] args,
-                               vec[ty.arg] arg_tys) {
+fn copy_args_to_allocas(@block_ctxt cx,
+                        option.t[TypeRef] ty_self,
+                        vec[ast.arg] args,
+                        vec[ty.arg] arg_tys) {
 
     let uint arg_n = 0u;
 
@@ -3203,9 +3218,9 @@ fn create_llobjfields_for_fields(@block_ctxt cx, ValueRef llself) {
     }
 }
 
-impure fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
-                   option.t[TypeRef] ty_self,
-                   &vec[ast.ty_param] ty_params, &ast.ann ann) {
+fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
+            option.t[TypeRef] ty_self,
+            &vec[ast.ty_param] ty_params, &ast.ann ann) {
 
     auto llfndecl = cx.item_ids.get(fid);
     cx.item_names.insert(cx.path, llfndecl);
@@ -3234,9 +3249,9 @@ impure fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
     }
 }
 
-impure fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
-                     &ast._obj ob,
-                     &vec[ast.ty_param] ty_params) -> ValueRef {
+fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
+              &ast._obj ob,
+              &vec[ast.ty_param] ty_params) -> ValueRef {
     let vec[ValueRef] methods = vec();
 
     fn meth_lteq(&@ast.method a, &@ast.method b) -> bool {
@@ -3279,8 +3294,8 @@ impure fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
     ret gvar;
 }
 
-impure fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
-                    &vec[ast.ty_param] ty_params, &ast.ann ann) {
+fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
+             &vec[ast.ty_param] ty_params, &ast.ann ann) {
 
     auto llctor_decl = cx.item_ids.get(oid);
     cx.item_names.insert(cx.path, llctor_decl);
@@ -3442,7 +3457,7 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
     bcx.build.Ret(lltagval);
 }
 
-impure fn trans_item(@crate_ctxt cx, &ast.item item) {
+fn trans_item(@crate_ctxt cx, &ast.item item) {
     alt (item.node) {
         case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
             auto sub_cx = @rec(path=cx.path + "." + name with *cx);
@@ -3469,7 +3484,7 @@ impure fn trans_item(@crate_ctxt cx, &ast.item item) {
     }
 }
 
-impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
+fn trans_mod(@crate_ctxt cx, &ast._mod m) {
     for (@ast.item item in m.items) {
         trans_item(cx, *item);
     }
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 8f5414158f9..b439632cfbc 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -34,6 +34,8 @@ mod util {
 
 auth driver.rustc.main = impure;
 auth middle.trans = unsafe;
+auth middle.trans.copy_args_to_allocas = impure;
+auth middle.trans.trans_block = impure;
 auth lib.llvm = unsafe;