about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2010-11-02 15:24:46 -0700
committerGraydon Hoare <graydon@mozilla.com>2010-11-02 15:24:46 -0700
commit7db115834f24eb9d9ccbd2468c9145fdf86be514 (patch)
tree5e5e1463ba1201524c6d10690c0982f4b168ba9f /src
parentda13c508d83032ca13679e1e122e96d25ac23283 (diff)
Split out stratum-checking pass, implement more-strict (overly aggressive) impure-effect checking.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/boot/driver/llvm/glue.ml1
-rw-r--r--src/boot/driver/main.ml4
-rw-r--r--src/boot/driver/session.ml1
-rw-r--r--src/boot/me/effect.ml127
-rw-r--r--src/boot/me/stratum.ml108
-rw-r--r--src/comp/middle/trans.rs32
-rw-r--r--src/lib/bitv.rs18
-rw-r--r--src/lib/map.rs20
-rw-r--r--src/test/run-pass/box-in-tup.rs2
-rw-r--r--src/test/run-pass/exterior.rs4
-rw-r--r--src/test/run-pass/foreach-nested-2.rs2
-rw-r--r--src/test/run-pass/foreach-nested.rs2
-rw-r--r--src/test/run-pass/lib-bitv.rs10
-rw-r--r--src/test/run-pass/vec-in-tup.rs2
-rw-r--r--src/test/run-pass/writealias.rs4
16 files changed, 198 insertions, 143 deletions
diff --git a/src/Makefile b/src/Makefile
index 8e4a40340a1..8406d307ec7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -261,8 +261,8 @@ BE_MLS := $(addprefix boot/be/, x86.ml ra.ml pe.ml elf.ml \
           macho.ml)
 IL_MLS := $(addprefix boot/be/, asm.ml il.ml abi.ml)
 ME_MLS := $(addprefix boot/me/, walk.ml semant.ml resolve.ml alias.ml \
-            simplify.ml type.ml dead.ml effect.ml typestate.ml loop.ml \
-            layout.ml transutil.ml trans.ml dwarf.ml)
+            simplify.ml type.ml dead.ml stratum.ml effect.ml typestate.ml \
+            loop.ml layout.ml transutil.ml trans.ml dwarf.ml)
 FE_MLS := $(addprefix boot/fe/, ast.ml token.ml lexer.ml parser.ml \
             extfmt.ml pexp.ml item.ml cexp.ml fuzz.ml)
 DRIVER_TOP_MLS := $(addprefix boot/driver/, lib.ml $(VARIANT)/glue.ml main.ml)
diff --git a/src/boot/driver/llvm/glue.ml b/src/boot/driver/llvm/glue.ml
index 03baf04d93a..da5e5b9dea9 100644
--- a/src/boot/driver/llvm/glue.ml
+++ b/src/boot/driver/llvm/glue.ml
@@ -18,6 +18,7 @@ let alt_pipeline sess sem_cx crate =
       Simplify.process_crate;
       Type.process_crate;
       Typestate.process_crate;
+      Stratum.process_crate;
       Effect.process_crate;
       Loop.process_crate;
       Alias.process_crate;
diff --git a/src/boot/driver/main.ml b/src/boot/driver/main.ml
index b37f5d936db..30310b100f0 100644
--- a/src/boot/driver/main.ml
+++ b/src/boot/driver/main.ml
@@ -37,6 +37,7 @@ let (sess:Session.sess) =
     Session.sess_log_resolve = false;
     Session.sess_log_type = false;
     Session.sess_log_simplify = false;
+    Session.sess_log_stratum = false;
     Session.sess_log_effect = false;
     Session.sess_log_typestate = false;
     Session.sess_log_loop = false;
@@ -175,6 +176,8 @@ let argspecs =
        "-ltype"     "log type checking");
     (flag (fun _ -> sess.Session.sess_log_simplify <- true)
        "-lsimplify" "log simplification");
+    (flag (fun _ -> sess.Session.sess_log_stratum <- true)
+       "-lstratum"  "log stratum checking");
     (flag (fun _ -> sess.Session.sess_log_effect <- true)
        "-leffect"   "log effect checking");
     (flag (fun _ -> sess.Session.sess_log_typestate <- true)
@@ -378,6 +381,7 @@ let main_pipeline _ =
          Simplify.process_crate;
          Type.process_crate;
          Typestate.process_crate;
+         Stratum.process_crate;
          Effect.process_crate;
          Loop.process_crate;
          Alias.process_crate;
diff --git a/src/boot/driver/session.ml b/src/boot/driver/session.ml
index 39848982ba9..49242ac6c26 100644
--- a/src/boot/driver/session.ml
+++ b/src/boot/driver/session.ml
@@ -23,6 +23,7 @@ type sess =
   mutable sess_log_resolve: bool;
   mutable sess_log_type: bool;
   mutable sess_log_simplify: bool;
+  mutable sess_log_stratum: bool;
   mutable sess_log_effect: bool;
   mutable sess_log_typestate: bool;
   mutable sess_log_dead: bool;
diff --git a/src/boot/me/effect.ml b/src/boot/me/effect.ml
index 3bb761efed1..238e3e5b0f1 100644
--- a/src/boot/me/effect.ml
+++ b/src/boot/me/effect.ml
@@ -12,78 +12,7 @@ let iflog cx thunk =
   else ()
 ;;
 
-let mutability_checking_visitor
-    (cx:ctxt)
-    (inner:Walk.visitor)
-    : Walk.visitor =
-  (* 
-   * This visitor enforces the following rules:
-   * 
-   * - A channel type carrying a mutable type is illegal.
-   * 
-   * - Writing to an immutable slot is illegal.
-   * 
-   * - Forming a mutable alias to an immutable slot is illegal.
-   * 
-   *)
-  let visit_ty_pre t =
-    match t with
-        Ast.TY_chan t' when type_has_state cx t' ->
-          err None "channel of mutable type: %a " Ast.sprintf_ty t'
-      | _ -> ()
-  in
-
-  let check_write s dst =
-    let is_init = Hashtbl.mem cx.ctxt_stmt_is_init s.id in
-    let dst_ty = lval_ty cx dst in
-    let is_mutable =
-      match dst_ty with
-          Ast.TY_mutable _ -> true
-        | _ -> false
-    in
-      iflog cx
-        (fun _ -> log cx "checking %swrite to %slval #%d = %a of type %a"
-           (if is_init then "initializing " else "")
-           (if is_mutable then "mutable " else "")
-           (int_of_node (lval_base_id dst))
-           Ast.sprintf_lval dst
-           Ast.sprintf_ty dst_ty);
-      if (is_mutable or is_init)
-      then ()
-      else err (Some s.id)
-        "writing to immutable type %a in statement %a"
-        Ast.sprintf_ty dst_ty Ast.sprintf_stmt s
-  in
-    (* FIXME (issue #75): enforce the no-write-alias-to-immutable-slot
-     * rule.
-     *)
-  let visit_stmt_pre s =
-    begin
-      match s.node with
-            Ast.STMT_copy (lv_dst, _)
-          | Ast.STMT_call (lv_dst, _, _)
-          | Ast.STMT_spawn (lv_dst, _, _, _, _)
-          | Ast.STMT_recv (lv_dst, _)
-          | Ast.STMT_bind (lv_dst, _, _)
-          | Ast.STMT_new_rec (lv_dst, _, _)
-          | Ast.STMT_new_tup (lv_dst, _)
-          | Ast.STMT_new_vec (lv_dst, _, _)
-          | Ast.STMT_new_str (lv_dst, _)
-          | Ast.STMT_new_port lv_dst
-          | Ast.STMT_new_chan (lv_dst, _)
-          | Ast.STMT_new_box (lv_dst, _, _) ->
-              check_write s lv_dst
-        | _ -> ()
-    end;
-    inner.Walk.visit_stmt_pre s
-  in
-
-    { inner with
-        Walk.visit_ty_pre = visit_ty_pre;
-        Walk.visit_stmt_pre = visit_stmt_pre }
-;;
-
-let function_effect_propagation_visitor
+let effect_calculating_visitor
     (item_effect:(node_id, Ast.effect) Hashtbl.t)
     (cx:ctxt)
     (inner:Walk.visitor)
@@ -93,6 +22,7 @@ let function_effect_propagation_visitor
    * its statements:
    * 
    *    - Communication statements lower to 'impure'
+   *    - Writing to anything other than a local slot lowers to 'impure'
    *    - Native calls lower to 'unsafe'
    *    - Calling a function with effect e lowers to e.
    *)
@@ -159,13 +89,27 @@ let function_effect_propagation_visitor
         end;
   in
 
+  let note_write s dst =
+    (* FIXME (issue #182): this is too aggressive; won't permit writes to
+     * interior components of records or tuples. It should at least do that,
+     * possibly handle escape analysis on the pointee for things like vecs as
+     * well.  *)
+    if lval_base_is_slot cx dst
+    then
+      let base_slot = lval_base_slot cx dst in
+        match dst, base_slot.Ast.slot_mode with
+            (Ast.LVAL_base _, Ast.MODE_local) -> ()
+          | _ -> lower_to s Ast.EFF_impure
+  in
+
   let visit_stmt_pre s =
     begin
       match s.node with
           Ast.STMT_send _
         | Ast.STMT_recv _ -> lower_to s Ast.EFF_impure
 
-        | Ast.STMT_call (_, fn, _) ->
+        | Ast.STMT_call (lv_dst, fn, _) ->
+            note_write s lv_dst;
             let lower_to_callee_ty t =
               match simplified_ty t with
                   Ast.TY_fn (_, taux) ->
@@ -185,6 +129,19 @@ let function_effect_propagation_visitor
                       | Some (REQUIRED_LIB_rust _, _) -> ()
                       | Some _ -> lower_to s Ast.EFF_unsafe
                 end
+
+        | Ast.STMT_copy (lv_dst, _)
+        | Ast.STMT_spawn (lv_dst, _, _, _, _)
+        | Ast.STMT_bind (lv_dst, _, _)
+        | Ast.STMT_new_rec (lv_dst, _, _)
+        | Ast.STMT_new_tup (lv_dst, _)
+        | Ast.STMT_new_vec (lv_dst, _, _)
+        | Ast.STMT_new_str (lv_dst, _)
+        | Ast.STMT_new_port lv_dst
+        | Ast.STMT_new_chan (lv_dst, _)
+        | Ast.STMT_new_box (lv_dst, _, _) ->
+            note_write s lv_dst
+
         | _ -> ()
     end;
     inner.Walk.visit_stmt_pre s
@@ -200,19 +157,6 @@ let function_effect_propagation_visitor
         Walk.visit_stmt_pre = visit_stmt_pre }
 ;;
 
-let binding_effect_propagation_visitor
-    ((*cx*)_:ctxt)
-    (inner:Walk.visitor)
-    : Walk.visitor =
-  (* This visitor lowers the effect of an object or binding according
-   * to its slots: holding a 'state' slot lowers any obj item, or
-   * bind-stmt LHS, to 'state'.
-   * 
-   * Binding (or implicitly just making a native 1st-class) makes the LHS
-   * unsafe.
-   *)
-  inner
-;;
 
 let effect_checking_visitor
     (item_auth:(node_id, Ast.effect) Hashtbl.t)
@@ -221,7 +165,7 @@ let effect_checking_visitor
     (inner:Walk.visitor)
     : Walk.visitor =
   (*
-   * This visitor checks that each type, item and obj declares
+   * This visitor checks that each fn declares
    * effects consistent with what we calculated.
    *)
   let auth_stack = Stack.create () in
@@ -250,7 +194,8 @@ let effect_checking_visitor
     end;
     begin
       match i.node.Ast.decl_item with
-          Ast.MOD_ITEM_fn f ->
+          Ast.MOD_ITEM_fn f
+            when htab_search cx.ctxt_required_items i.id = None ->
             let e =
               match htab_search item_effect i.id with
                 None -> Ast.EFF_pure
@@ -319,11 +264,7 @@ let process_crate
   let item_effect = Hashtbl.create 0 in
   let passes =
     [|
-      (mutability_checking_visitor cx
-         Walk.empty_visitor);
-      (function_effect_propagation_visitor item_effect cx
-         Walk.empty_visitor);
-      (binding_effect_propagation_visitor cx
+      (effect_calculating_visitor item_effect cx
          Walk.empty_visitor);
       (effect_checking_visitor item_auth item_effect cx
          Walk.empty_visitor);
diff --git a/src/boot/me/stratum.ml b/src/boot/me/stratum.ml
new file mode 100644
index 00000000000..21598d557ef
--- /dev/null
+++ b/src/boot/me/stratum.ml
@@ -0,0 +1,108 @@
+open Semant;;
+open Common;;
+
+let log cx = Session.log "stratum"
+  (should_log cx cx.ctxt_sess.Session.sess_log_stratum)
+  cx.ctxt_sess.Session.sess_log_out
+;;
+
+let iflog cx thunk =
+  if (should_log cx cx.ctxt_sess.Session.sess_log_stratum)
+  then thunk ()
+  else ()
+;;
+
+
+let state_stratum_checking_visitor
+    (cx:ctxt)
+    (inner:Walk.visitor)
+    : Walk.visitor =
+  (* 
+   * This visitor enforces the following rules:
+   * 
+   * - A channel type carrying a state type is illegal.
+   * 
+   * - Writing to an immutable slot is illegal.
+   * 
+   * - Forming a mutable alias to an immutable slot is illegal.
+   * 
+   *)
+  let visit_ty_pre t =
+    match t with
+        Ast.TY_chan t' when type_has_state cx t' ->
+          err None "channel of state type: %a " Ast.sprintf_ty t'
+      | _ -> ()
+  in
+
+  let check_write s dst =
+    let is_init = Hashtbl.mem cx.ctxt_stmt_is_init s.id in
+    let dst_ty = lval_ty cx dst in
+    let is_mutable =
+      match dst_ty with
+          Ast.TY_mutable _ -> true
+        | _ -> false
+    in
+      iflog cx
+        (fun _ -> log cx "checking %swrite to %slval #%d = %a of type %a"
+           (if is_init then "initializing " else "")
+           (if is_mutable then "mutable " else "")
+           (int_of_node (lval_base_id dst))
+           Ast.sprintf_lval dst
+           Ast.sprintf_ty dst_ty);
+      if (is_mutable or is_init)
+      then ()
+      else err (Some s.id)
+        "writing to immutable type %a in statement %a"
+        Ast.sprintf_ty dst_ty Ast.sprintf_stmt s
+  in
+    (* FIXME (issue #75): enforce the no-write-alias-to-immutable-slot
+     * rule.
+     *)
+  let visit_stmt_pre s =
+    begin
+      match s.node with
+            Ast.STMT_copy (lv_dst, _)
+          | Ast.STMT_call (lv_dst, _, _)
+          | Ast.STMT_spawn (lv_dst, _, _, _, _)
+          | Ast.STMT_recv (lv_dst, _)
+          | Ast.STMT_bind (lv_dst, _, _)
+          | Ast.STMT_new_rec (lv_dst, _, _)
+          | Ast.STMT_new_tup (lv_dst, _)
+          | Ast.STMT_new_vec (lv_dst, _, _)
+          | Ast.STMT_new_str (lv_dst, _)
+          | Ast.STMT_new_port lv_dst
+          | Ast.STMT_new_chan (lv_dst, _)
+          | Ast.STMT_new_box (lv_dst, _, _) ->
+              check_write s lv_dst
+        | _ -> ()
+    end;
+    inner.Walk.visit_stmt_pre s
+  in
+
+    { inner with
+        Walk.visit_ty_pre = visit_ty_pre;
+        Walk.visit_stmt_pre = visit_stmt_pre }
+;;
+
+let process_crate
+    (cx:ctxt)
+    (crate:Ast.crate)
+    : unit =
+  let passes =
+    [|
+      (state_stratum_checking_visitor cx
+         Walk.empty_visitor);
+    |]
+  in
+    run_passes cx "stratum" passes
+      cx.ctxt_sess.Session.sess_log_stratum log crate
+;;
+
+(*
+ * Local Variables:
+ * fill-column: 78;
+ * indent-tabs-mode: nil
+ * buffer-file-coding-system: utf-8-unix
+ * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+ * End:
+ *)
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 1a05f76e53c..9fefcf55981 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -408,7 +408,7 @@ fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
                                 T_int(), C_int(0));
 }
 
-fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
+impure fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
     alt (lit.node) {
         case (ast.lit_int(?i)) {
             ret res(cx, C_int(i));
@@ -438,7 +438,7 @@ fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
     }
 }
 
-fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {
+impure fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {
 
     auto sub = trans_expr(cx, e);
 
@@ -461,8 +461,8 @@ fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {
     fail;
 }
 
-fn trans_binary(@block_ctxt cx, ast.binop op,
-                &ast.expr a, &ast.expr b) -> result {
+impure fn trans_binary(@block_ctxt cx, ast.binop op,
+                       &ast.expr a, &ast.expr b) -> result {
 
     // First couple cases are lazy:
 
@@ -612,8 +612,8 @@ fn trans_binary(@block_ctxt cx, ast.binop op,
     fail;
 }
 
-fn trans_if(@block_ctxt cx, &ast.expr cond,
-            &ast.block thn, &option[ast.block] els) -> result {
+impure fn trans_if(@block_ctxt cx, &ast.expr cond,
+                   &ast.block thn, &option[ast.block] els) -> result {
 
     auto cond_res = trans_expr(cx, cond);
 
@@ -691,7 +691,7 @@ fn trans_lval(@block_ctxt cx, &ast.expr e)
     fail;
 }
 
-fn trans_exprs(@block_ctxt cx, &vec[@ast.expr] es)
+impure fn trans_exprs(@block_ctxt cx, &vec[@ast.expr] es)
     -> tup(@block_ctxt, vec[ValueRef]) {
     let vec[ValueRef] vs = vec();
     let @block_ctxt bcx = cx;
@@ -705,7 +705,7 @@ fn trans_exprs(@block_ctxt cx, &vec[@ast.expr] es)
     ret tup(bcx, vs);
 }
 
-fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
+impure fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
     alt (e.node) {
         case (ast.expr_lit(?lit, _)) {
             ret trans_lit(cx, *lit);
@@ -777,7 +777,7 @@ fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
     fail;
 }
 
-fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
+impure fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
     alt (e.node) {
         case (ast.expr_lit(?lit, _)) {
             alt (lit.node) {
@@ -805,7 +805,7 @@ fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
     }
 }
 
-fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
+impure fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
     auto cond_res = trans_expr(cx, e);
 
     // FIXME: need pretty-printer.
@@ -825,7 +825,7 @@ fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
     ret res(next_cx, C_nil());
 }
 
-fn trans_ret(@block_ctxt cx, &option[@ast.expr] e) -> result {
+impure fn trans_ret(@block_ctxt cx, &option[@ast.expr] e) -> result {
     auto r = res(cx, C_nil());
     alt (e) {
         case (some[@ast.expr](?x)) {
@@ -841,7 +841,7 @@ fn trans_ret(@block_ctxt cx, &option[@ast.expr] e) -> result {
     ret r;
 }
 
-fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
+impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
     auto sub = res(cx, C_nil());
     alt (s.node) {
         case (ast.stmt_log(?a)) {
@@ -957,7 +957,7 @@ iter block_locals(&ast.block b) -> @ast.local {
     }
 }
 
-fn trans_block(@block_ctxt cx, &ast.block b) -> result {
+impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
     auto bcx = cx;
 
     for each (@ast.local local in block_locals(b)) {
@@ -1011,14 +1011,14 @@ fn new_fn_ctxt(@trans_ctxt cx,
              tcx=cx);
 }
 
-fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
+impure fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
 
     auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
 
     trans_block(new_top_block_ctxt(fcx), f.body);
 }
 
-fn trans_item(@trans_ctxt cx, &ast.item item) {
+impure fn trans_item(@trans_ctxt cx, &ast.item item) {
     alt (item.node) {
         case (ast.item_fn(?name, ?f, ?fid)) {
             auto sub_cx = @rec(path=cx.path + "." + name with *cx);
@@ -1031,7 +1031,7 @@ fn trans_item(@trans_ctxt cx, &ast.item item) {
     }
 }
 
-fn trans_mod(@trans_ctxt cx, &ast._mod m) {
+impure fn trans_mod(@trans_ctxt cx, &ast._mod m) {
     for (@ast.item item in m.items) {
         trans_item(cx, *item);
     }
diff --git a/src/lib/bitv.rs b/src/lib/bitv.rs
index af90060aab8..2a8c7d0ee53 100644
--- a/src/lib/bitv.rs
+++ b/src/lib/bitv.rs
@@ -29,7 +29,7 @@ fn create(uint nbits, bool init) -> t {
     ret rec(storage = storage, nbits = nbits);
 }
 
-fn process(&fn(uint, uint) -> uint op, &t v0, &t v1) -> bool {
+impure fn process(&fn(uint, uint) -> uint op, &t v0, &t v1) -> bool {
     auto len = _vec.len[mutable uint](v1.storage);
 
     check (_vec.len[mutable uint](v0.storage) == len);
@@ -55,7 +55,7 @@ fn lor(uint w0, uint w1) -> uint {
     ret w0 | w1;
 }
 
-fn union(&t v0, &t v1) -> bool {
+impure fn union(&t v0, &t v1) -> bool {
     auto sub = lor;
     ret process(sub, v0, v1);
 }
@@ -64,7 +64,7 @@ fn land(uint w0, uint w1) -> uint {
     ret w0 & w1;
 }
 
-fn intersect(&t v0, &t v1) -> bool {
+impure fn intersect(&t v0, &t v1) -> bool {
     auto sub = land;
     ret process(sub, v0, v1);
 }
@@ -73,7 +73,7 @@ fn right(uint w0, uint w1) -> uint {
     ret w1;
 }
 
-fn copy(&t v0, t v1) -> bool {
+impure fn copy(&t v0, t v1) -> bool {
     auto sub = right;
     ret process(sub, v0, v1);
 }
@@ -103,27 +103,27 @@ fn equal(&t v0, &t v1) -> bool {
     ret true;
 }
 
-fn clear(&t v) {
+impure fn clear(&t v) {
     for each (uint i in _uint.range(0u, _vec.len[mutable uint](v.storage))) {
         v.storage.(i) = 0u;
     }
 }
 
-fn invert(&t v) {
+impure fn invert(&t v) {
     for each (uint i in _uint.range(0u, _vec.len[mutable uint](v.storage))) {
         v.storage.(i) = ~v.storage.(i);
     }
 }
 
 /* v0 = v0 - v1 */
-fn difference(&t v0, &t v1) -> bool {
+impure fn difference(&t v0, &t v1) -> bool {
     invert(v1);
     auto b = intersect(v0, v1);
     invert(v1);
     ret b;
 }
 
-fn set(&t v, uint i, bool x) {
+impure fn set(&t v, uint i, bool x) {
     check (i < v.nbits);
 
     auto bits = uint_bits();
@@ -175,6 +175,6 @@ fn eq_vec(&t v0, &vec[uint] v1) -> bool {
 // indent-tabs-mode: nil
 // c-basic-offset: 4
 // buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
 //
diff --git a/src/lib/map.rs b/src/lib/map.rs
index 4d7a6c03775..2693441bfa5 100644
--- a/src/lib/map.rs
+++ b/src/lib/map.rs
@@ -70,12 +70,12 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
      * We attempt to never call this with a full table.  If we do, it
      * will fail.
      */
-    fn insert_common[K, V](&hashfn[K] hasher,
-                           &eqfn[K] eqer,
-                           vec[mutable bucket[K, V]] bkts,
-                           uint nbkts,
-                           &K key,
-                           &V val)
+    impure fn insert_common[K, V](&hashfn[K] hasher,
+                                  &eqfn[K] eqer,
+                                  vec[mutable bucket[K, V]] bkts,
+                                  uint nbkts,
+                                  &K key,
+                                  &V val)
         -> bool
         {
             let uint i = 0u;
@@ -125,10 +125,10 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
         }
 
 
-    fn rehash[K, V](&hashfn[K] hasher,
-                    &eqfn[K] eqer,
-                    vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
-                    vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
+   impure fn rehash[K, V](&hashfn[K] hasher,
+                          &eqfn[K] eqer,
+                          vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
+                          vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
         {
             for (bucket[K, V] b in oldbkts) {
                 alt (b) {
diff --git a/src/test/run-pass/box-in-tup.rs b/src/test/run-pass/box-in-tup.rs
index 53f3dc0ffa2..b1ae7907d2e 100644
--- a/src/test/run-pass/box-in-tup.rs
+++ b/src/test/run-pass/box-in-tup.rs
@@ -1,4 +1,4 @@
-fn main() {
+impure fn main() {
   let tup(mutable @int) i = tup(mutable @10);
   i._0 = @11;
 }
\ No newline at end of file
diff --git a/src/test/run-pass/exterior.rs b/src/test/run-pass/exterior.rs
index f09ee8234e3..e131e38db13 100644
--- a/src/test/run-pass/exterior.rs
+++ b/src/test/run-pass/exterior.rs
@@ -2,13 +2,13 @@
 
 type point = rec(int x, int y, mutable int z);
 
-fn f(@point p) {
+impure fn f(@point p) {
   check (p.z == 12);
   p.z = 13;
   check (p.z == 13);
 }
 
-fn main() {
+impure fn main() {
   let point a = rec(x=10, y=11, mutable z=12);
   let @point b = @a;
   check (b.z == 12);
diff --git a/src/test/run-pass/foreach-nested-2.rs b/src/test/run-pass/foreach-nested-2.rs
index d8d67c141b0..f06474b35fd 100644
--- a/src/test/run-pass/foreach-nested-2.rs
+++ b/src/test/run-pass/foreach-nested-2.rs
@@ -13,7 +13,7 @@ iter range(int start, int stop) -> int {
     }
 }
 
-fn main() {
+impure fn main() {
     let vec[mutable int] a =
       vec[mutable](-1, -1, -1, -1, -1, -1, -1, -1);
     let int p = 0;
diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs
index 6287477ab93..1da1d05bdc2 100644
--- a/src/test/run-pass/foreach-nested.rs
+++ b/src/test/run-pass/foreach-nested.rs
@@ -5,7 +5,7 @@ iter two() -> int {
     put 1;
 }
 
-fn main() {
+impure fn main() {
     let vec[mutable int] a = vec[mutable](-1, -1, -1, -1);
     let int p = 0;
 
diff --git a/src/test/run-pass/lib-bitv.rs b/src/test/run-pass/lib-bitv.rs
index 162e8b13293..c3ffa8ea0ca 100644
--- a/src/test/run-pass/lib-bitv.rs
+++ b/src/test/run-pass/lib-bitv.rs
@@ -22,7 +22,7 @@ fn test_1_element() {
   check (bitv.eq_vec(act, vec(1u)));
 }
 
-fn test_10_elements() {
+impure fn test_10_elements() {
   auto act;
 
   // all 0
@@ -60,7 +60,7 @@ fn test_10_elements() {
   check (bitv.eq_vec(act, vec(1u, 0u, 0u, 1u, 0u, 0u, 1u, 0u, 0u, 1u)));
 }
 
-fn test_31_elements() {
+impure fn test_31_elements() {
   auto act;
 
   // all 0
@@ -132,7 +132,7 @@ fn test_31_elements() {
                               0u, 0u, 0u, 0u, 0u, 0u, 1u)));
 }
 
-fn test_32_elements() {
+impure fn test_32_elements() {
   auto act;
 
   // all 0
@@ -206,7 +206,7 @@ fn test_32_elements() {
                               0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u)));
 }
 
-fn test_33_elements() {
+impure fn test_33_elements() {
   auto act;
 
   // all 0
@@ -287,7 +287,7 @@ fn test_33_elements() {
                               1u)));
 }
 
-fn main() {
+impure fn main() {
   test_0_elements();
   test_1_element();
   test_10_elements();
diff --git a/src/test/run-pass/vec-in-tup.rs b/src/test/run-pass/vec-in-tup.rs
index 415554dd374..97eb222edaf 100644
--- a/src/test/run-pass/vec-in-tup.rs
+++ b/src/test/run-pass/vec-in-tup.rs
@@ -1,4 +1,4 @@
-fn main() {
+impure fn main() {
   let tup(mutable vec[int]) i = tup(mutable vec(1,2,3));
   i._0 = vec(4,5,6);
 }
diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs
index 8bf8140f315..551fb7d317d 100644
--- a/src/test/run-pass/writealias.rs
+++ b/src/test/run-pass/writealias.rs
@@ -2,11 +2,11 @@
 
 type point = rec(int x, int y, mutable int z);
 
-fn f(& mutable point p) {
+impure fn f(& mutable point p) {
   p.z = 13;
 }
 
-fn main() {
+impure fn main() {
   let point x = rec(x=10, y=11, mutable z=12);
   f(x);
   check (x.z == 13);