From e7ce32310b90a4738452f2331e25d4815f2ab81f Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Mon, 18 Jun 2012 13:33:07 -0700
Subject: [PATCH 01/50] Change map::get to map::find in ppaux

---
 src/rustc/util/ppaux.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 431eb8b0aea..83167597bb8 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -28,12 +28,12 @@ fn bound_region_to_str(cx: ctxt, br: bound_region) -> str {
 }
 
 fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> str {
-    alt cx.items.get(node_id) {
-      ast_map::node_block(blk) {
+    alt cx.items.find(node_id) {
+      some(ast_map::node_block(blk)) {
         #fmt("<block at %s>",
              codemap::span_to_str(blk.span, cx.sess.codemap))
       }
-      ast_map::node_expr(expr) {
+      some(ast_map::node_expr(expr)) {
         alt expr.node {
           ast::expr_call(*) {
             #fmt("<call at %s>",

From 1b4dcbecac824796bf7cd49a1fbadc20e63c99ea Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Mon, 18 Jun 2012 13:34:15 -0700
Subject: [PATCH 02/50] Comments only: typos

---
 src/libcore/str.rs             | 2 +-
 src/libstd/par.rs              | 2 +-
 src/test/bench/graph500-bfs.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index 8f68ff8d4da..f1136fde5e2 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -566,7 +566,7 @@ pure fn to_upper(s: str/&) -> str {
 }
 
 #[doc = "
-Replace all occurances of one string with another
+Replace all occurrences of one string with another
 
 # Arguments
 
diff --git a/src/libstd/par.rs b/src/libstd/par.rs
index ffca5989857..e621fd78724 100644
--- a/src/libstd/par.rs
+++ b/src/libstd/par.rs
@@ -7,7 +7,7 @@ import future::future;
 export map, mapi, alli, any, mapi_factory;
 
 #[doc="The maximum number of tasks this module will spawn for a single
-operationg."]
+operation."]
 const max_tasks : uint = 32u;
 
 #[doc="The minimum number of elements each task will process."]
diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs
index e51cb6c98b2..6c6466017ef 100644
--- a/src/test/bench/graph500-bfs.rs
+++ b/src/test/bench/graph500-bfs.rs
@@ -1,6 +1,6 @@
 /**
 
-An implementation of the Graph500 Bread First Search problem in Rust.
+An implementation of the Graph500 Breadth First Search problem in Rust.
 
 */
 

From 6db7843f46afd5cd905b2e3a4266a23c4bb41ef1 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Mon, 18 Jun 2012 13:34:50 -0700
Subject: [PATCH 03/50] Monomorphize dtors correctly

The same dtor was getting re-used for different instances, which
didn't always work right. Fixed.
---
 src/rustc/middle/trans/base.rs | 62 ++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 21 deletions(-)

diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 44bb515393e..8eab69b1133 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2304,14 +2304,14 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
         }
       }
       ast_map::node_dtor(_, dtor, _, pt) {
-          let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
-                                     dtor.node.self_id)) {
-                  some(did) { did }
-                  none      { ccx.sess.span_bug(dtor.span, "Bad self ty in \
+        let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
+                                              dtor.node.self_id)) {
+                some(did) { did }
+                none      { ccx.sess.span_bug(dtor.span, "Bad self ty in \
                                dtor"); }
-          };
-          trans_class_dtor(ccx, *pt, dtor.node.body,
-                           dtor.node.id, psubsts, some(hash_id), parent_id)
+        };
+        trans_class_dtor(ccx, *pt, dtor.node.body,
+          dtor.node.id, psubsts, some(hash_id), parent_id)
       }
       // Ugh -- but this ensures any new variants won't be forgotten
       ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
@@ -4930,15 +4930,15 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
 }
 
 fn trans_class_dtor(ccx: @crate_ctxt, path: path,
-    body: ast::blk,
-    dtor_id: ast::node_id, substs: option<param_substs>,
-                    hash_id: option<mono_id>, parent_id: ast::def_id)
+    body: ast::blk, dtor_id: ast::node_id,
+    psubsts: option<param_substs>,
+    hash_id: option<mono_id>, parent_id: ast::def_id)
     -> ValueRef {
   let tcx = ccx.tcx;
   /* Look up the parent class's def_id */
   let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty;
   /* Substitute in the class type if necessary */
-  option::iter(substs) {|ss|
+  option::iter(psubsts) {|ss|
     class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
   }
 
@@ -4947,7 +4947,9 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
   let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
                     T_ptr(type_of(ccx, class_ty))],
                    llvm::LLVMVoidType());
-  let s = get_dtor_symbol(ccx, path, dtor_id);
+
+  let s = get_dtor_symbol(ccx, path, dtor_id, psubsts);
+
   /* Register the dtor as a function. It has external linkage */
   let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
   lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage);
@@ -4959,7 +4961,7 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
   }
   /* Translate the dtor body */
   trans_fn(ccx, path, ast_util::dtor_dec(),
-           body, lldecl, impl_self(class_ty), substs, dtor_id);
+           body, lldecl, impl_self(class_ty), psubsts, dtor_id);
   lldecl
 }
 
@@ -5196,16 +5198,34 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
     } + [path_name(i.ident)]
 }
 
-/* If there's already a symbol for the dtor with <id>, return it;
-   otherwise, create one and register it, returning it as well */
-fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id) -> str {
+/* If there's already a symbol for the dtor with <id> and substs <substs>,
+   return it; otherwise, create one and register it, returning it as well */
+fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id,
+                   substs: option<param_substs>) -> str {
+  let t = ty::node_id_to_type(ccx.tcx, id);
   alt ccx.item_symbols.find(id) {
      some(s) { s }
+     none if is_none(substs) {
+       let s = mangle_exported_name(ccx,
+                               path + [path_name(@ccx.names("dtor"))],
+                               t);
+       ccx.item_symbols.insert(id, s);
+       s
+     }
      none    {
-         let s = mangle_exported_name(ccx, path +
-           [path_name(@ccx.names("dtor"))], ty::node_id_to_type(ccx.tcx, id));
-         ccx.item_symbols.insert(id, s);
-         s
+       // Monomorphizing, so just make a symbol, don't add
+       // this to item_symbols
+       alt substs {
+         some(ss) {
+           let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, t);
+           mangle_exported_name(ccx, path +
+                           [path_name(@ccx.names("dtor"))], mono_ty)
+         }
+         none {
+             ccx.sess.bug(#fmt("get_dtor_symbol: not monomorphizing and \
+               couldn't find a symbol for dtor %?", path));
+         }
+       }
      }
   }
 }
@@ -5289,7 +5309,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
             let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
                     T_ptr(type_of(ccx, class_ty))],
                                    llvm::LLVMVoidType());
-            let s = get_dtor_symbol(ccx, *pt, dt.node.id);
+            let s = get_dtor_symbol(ccx, *pt, dt.node.id, none);
 
             /* Make the declaration for the dtor */
             let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty);

From 76d6120e521b6546c54722e0dabfe8e73a5d6e73 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Tue, 19 Jun 2012 12:00:09 -0700
Subject: [PATCH 04/50] Fix resolve bug that made nested classes not work

It wasn't possible to refer to the constructor for a class nested inside
an item from the class's outer scope. Fixed.
---
 src/rustc/middle/resolve.rs       | 35 +++++++++++++++----------------
 src/test/run-pass/nested-class.rs | 15 +++++++++++++
 2 files changed, 32 insertions(+), 18 deletions(-)
 create mode 100644 src/test/run-pass/nested-class.rs

diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index fd0ecaa4fd5..78a0f1bfef7 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -573,7 +573,6 @@ fn visit_item_with_scope(e: @env, i: @ast::item,
       }
       ast::item_class(tps, ifaces, members, ctor, m_dtor, _) {
         v.visit_ty_params(tps, sc, v);
-        // Can maybe skip this now that we require self on class fields
         let class_scope = @cons(scope_item(i), sc);
         /* visit the constructor... */
         let ctor_scope = @cons(scope_method(ctor.node.self_id, tps),
@@ -1061,7 +1060,7 @@ fn lookup_in_scope(e: env, &&sc: scopes, sp: span, name: ident, ns: namespace,
               }
               ast::item_class(tps, _, members, ctor, _, _) {
                   if ns == ns_type {
-                    ret lookup_in_ty_params(e, name, tps);
+                      ret lookup_in_ty_params(e, name, tps);
                   }
                   if ns == ns_val && name == it.ident {
                       ret some(ast::def_fn(local_def(ctor.node.id),
@@ -1317,13 +1316,14 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
     alt i.node {
       ast::item_const(*) {
         if ns == ns_val {
-            ret some(ast::def_const(local_def(i.id))); }
-      }
-      ast::item_fn(decl, _, _) {
-        if ns == ns_val {
-            ret some(ast::def_fn(local_def(i.id), decl.purity));
+            ret some(ast::def_const(local_def(i.id)));
         }
       }
+      ast::item_fn(decl, _, _) {
+          if ns == ns_val {
+            ret some(ast::def_fn(local_def(i.id), decl.purity));
+           }
+       }
       ast::item_mod(_) {
         if ns == ns_module { ret some(ast::def_mod(local_def(i.id))); }
       }
@@ -1342,9 +1342,16 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
           _ { }
         }
       }
-      ast::item_class(*) {
-          if ns == ns_type {
-            ret some(ast::def_class(local_def(i.id)));
+      ast::item_class(_, _, _members, ct, _, _) {
+          alt ns {
+             ns_type {
+               ret some(ast::def_class(local_def(i.id)));
+             }
+             ns_val {
+               ret some(ast::def_fn(local_def(ct.node.id),
+                                    ast::impure_fn));
+             }
+             ns_module { }
           }
       }
       ast::item_impl(*) { /* ??? */ }
@@ -1653,14 +1660,6 @@ fn index_mod(md: ast::_mod) -> mod_index {
           ast::item_class(tps, _, items, ctor, _, _) {
               // add the class name itself
               add_to_index(index, it.ident, mie_item(it));
-              // add the constructor decl
-              add_to_index(index, it.ident,
-                           mie_item(@{ident: it.ident, attrs: [],
-                            id: ctor.node.id,
-                            node:
-                              item_fn(ctor.node.dec, tps, ctor.node.body),
-                            vis: ast::public,
-                            span: ctor.node.body.span}));
           }
         }
     }
diff --git a/src/test/run-pass/nested-class.rs b/src/test/run-pass/nested-class.rs
new file mode 100644
index 00000000000..b0f62cc3ea9
--- /dev/null
+++ b/src/test/run-pass/nested-class.rs
@@ -0,0 +1,15 @@
+fn main() {
+  
+  class b {
+    let i: int;
+    fn do_stuff() -> int { ret 37; }
+    new(i:int) { self.i = i; }
+  }
+
+  //  fn b(x:int) -> int { fail; }
+
+  let z = b(42);
+  assert(z.i == 42);
+  assert(z.do_stuff() == 37);
+  
+}
\ No newline at end of file

From 00171165205a1d5222563d0e2bdf7f970758b388 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Tue, 19 Jun 2012 12:01:02 -0700
Subject: [PATCH 05/50] Don't shadow a class name with a local

The fix in 208621 means you now can't shadow a class name with a local,
which is consistent with other behavior. But stackwalk was doing that.
Fixed it.
---
 src/libcore/stackwalk.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs
index 321fa605f48..0041dde319d 100644
--- a/src/libcore/stackwalk.rs
+++ b/src/libcore/stackwalk.rs
@@ -23,10 +23,10 @@ fn walk_stack(visit: fn(frame) -> bool) {
             reinterpret_cast(frame_pointer)
         };
         loop {
-            let frame = frame(frame_address);
+            let fr = frame(frame_address);
 
-            #debug("frame: %x", unsafe { reinterpret_cast(frame.fp) });
-            visit(frame);
+            #debug("frame: %x", unsafe { reinterpret_cast(fr.fp) });
+            visit(fr);
 
             unsafe {
                 let next_fp: **word = reinterpret_cast(frame_address);
@@ -44,7 +44,7 @@ fn walk_stack(visit: fn(frame) -> bool) {
 
 #[test]
 fn test_simple() {
-    for walk_stack { |frame|
+    for walk_stack { |_frame|
     }
 }
 
@@ -53,7 +53,7 @@ fn test_simple_deep() {
     fn run(i: int) {
         if i == 0 { ret }
 
-        for walk_stack { |frame|
+        for walk_stack { |_frame|
             unsafe {
                 breakpoint();
             }

From b02172971fa658f2e6d3cdb3cbf3bf663801d656 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Tue, 19 Jun 2012 14:44:38 -0700
Subject: [PATCH 06/50] Make trans give correct types to monomorphic dtors

Irritatingly, class dtors have a different type from resource
dtors (because class dtors have a self argument), and the monomorphic
case wasn't reflecting that. Fixed.
---
 src/rustc/middle/trans/base.rs    | 32 ++++++++++++++++++++++++-------
 src/rustc/middle/trans/shape.rs   | 15 +++++++++------
 src/rustc/middle/trans/type_of.rs |  7 +++++++
 3 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 8eab69b1133..47baa8aebca 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -754,7 +754,8 @@ fn trans_class_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id,
       // We have to cast v0
      let classptr = GEPi(bcx, v0, [0u, 1u]);
      // Find and call the actual destructor
-     let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, substs.tps);
+     let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, some(class_did),
+                                  substs.tps);
      // The second argument is the "self" argument for drop
      let params = lib::llvm::fn_ty_param_tys
          (llvm::LLVMGetElementType
@@ -829,7 +830,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
     build_return(bcx);
 }
 
-fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, substs: [ty::t])
+fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id,
+                // Parent ID is an option because resources don't
+                // have one. We can make this a def_id when
+                // resources get removed.
+                opt_id: option<ast::def_id>, substs: [ty::t])
    -> ValueRef {
     let _icx = ccx.insn_ctxt("trans_res_dtor");
     if (substs.len() > 0u) {
@@ -841,14 +846,27 @@ fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, substs: [ty::t])
     } else if did.crate == ast::local_crate {
         get_item_val(ccx, did.node)
     } else {
-        let fty = ty::mk_fn(ccx.tcx, {purity: ast::impure_fn,
-                                      proto: ast::proto_bare,
-                                      inputs: [{mode: ast::expl(ast::by_ref),
+        alt opt_id {
+           some(parent_id) {
+             let tcx = ccx.tcx;
+             let name = csearch::get_symbol(ccx.sess.cstore, did);
+             let class_ty = ty::subst_tps(tcx, substs,
+                              ty::lookup_item_type(tcx, parent_id).ty);
+             let llty = type_of_dtor(ccx, class_ty);
+             get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv,
+                           llty)
+           }
+           none {
+             let fty = ty::mk_fn(ccx.tcx, {purity: ast::impure_fn,
+                                       proto: ast::proto_bare,
+                                     inputs: [{mode: ast::expl(ast::by_ref),
                                                 ty: ty::mk_nil_ptr(ccx.tcx)}],
                                       output: ty::mk_nil(ccx.tcx),
                                       ret_style: ast::return_val,
                                       constraints: []});
-        trans_external_path(ccx, did, fty)
+             trans_external_path(ccx, did, fty)
+           }
+      }
     }
 }
 
@@ -862,7 +880,7 @@ fn trans_res_drop(bcx: block, rs: ValueRef, did: ast::def_id,
     with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|bcx|
         let valptr = GEPi(bcx, rs, [0u, 1u]);
         // Find and call the actual destructor.
-        let dtor_addr = get_res_dtor(ccx, did, tps);
+        let dtor_addr = get_res_dtor(ccx, did, none, tps);
         let args = [bcx.fcx.llretptr, null_env_ptr(bcx)];
         // Kludge to work around the fact that we know the precise type of the
         // value here, but the dtor expects a type that might have opaque
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index 61f82997e93..f0d98da5adb 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -21,12 +21,14 @@ import std::map::hashmap;
 
 import ty_ctxt = middle::ty::ctxt;
 
-type nominal_id = @{did: ast::def_id, tps: [ty::t]};
+type nominal_id = @{did: ast::def_id, parent_id: option<ast::def_id>,
+                    tps: [ty::t]};
 
 fn mk_nominal_id(tcx: ty::ctxt, did: ast::def_id,
+                 parent_id: option<ast::def_id>,
                  tps: [ty::t]) -> nominal_id {
     let tps_norm = tps.map { |t| ty::normalize_ty(tcx, t) };
-    @{did: did, tps: tps_norm}
+    @{did: did, parent_id: parent_id, tps: tps_norm}
 }
 
 fn hash_nominal_id(&&ri: nominal_id) -> uint {
@@ -233,7 +235,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
           tk_enum { [s_variant_enum_t(ccx.tcx)] }
           tk_newtype | tk_complex {
             let mut s = [shape_enum], id;
-            let nom_id = mk_nominal_id(ccx.tcx, did, substs.tps);
+            let nom_id = mk_nominal_id(ccx.tcx, did, none, substs.tps);
             alt ccx.shape_cx.tag_id_to_index.find(nom_id) {
               none {
                 id = ccx.shape_cx.next_tag_id;
@@ -335,7 +337,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
           else { [shape_struct] };
         let mut sub = [];
         option::iter(m_dtor_did) {|dtor_did|
-          let ri = @{did: dtor_did, tps: tps};
+          let ri = @{did: dtor_did, parent_id: some(did), tps: tps};
           let id = interner::intern(ccx.shape_cx.resources, ri);
           add_u16(s, id as u16);
 
@@ -362,7 +364,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
         for substs.tps.each() {|t| assert !ty::type_has_params(t); }
         let subt = ty::subst(ccx.tcx, substs, raw_subt);
         let tps = substs.tps;
-        let ri = @{did: did, tps: tps};
+        let ri = @{did: did, parent_id: none, tps: tps};
         let id = interner::intern(ccx.shape_cx.resources, ri);
 
         let mut s = [shape_res];
@@ -597,7 +599,8 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
     for uint::range(0u, len) {|i|
         let ri = interner::get(ccx.shape_cx.resources, i);
         for ri.tps.each() {|s| assert !ty::type_has_params(s); }
-        dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.tps)];
+        dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.parent_id,
+                                            ri.tps)];
     }
     ret mk_global(ccx, "resource_shapes", C_struct(dtors), true);
 }
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index c0f3014cf96..dc8dc1b92cf 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -8,6 +8,7 @@ import std::map::hashmap;
 import ty::*;
 
 export type_of;
+export type_of_dtor;
 export type_of_explicit_args;
 export type_of_fn_from_ty;
 export type_of_fn;
@@ -251,3 +252,9 @@ fn llvm_type_name(cx: @crate_ctxt, t: ty::t) -> str {
     );
 }
 
+fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
+    T_fn([T_ptr(type_of(ccx, ty::mk_nil(ccx.tcx))),
+          T_ptr(type_of(ccx, self_ty))],
+         llvm::LLVMVoidType())
+}
+

From 1b642bf02f23d48c93047ae2fca9ebd7c2bdc518 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Mon, 18 Jun 2012 13:49:20 -0700
Subject: [PATCH 07/50] Change core::comm to use classes instead of resources

Ports now are represented internally as classes.
---
 src/libcore/comm.rs | 51 ++++++++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 21 deletions(-)

diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs
index 7c2a9737f04..7f43f6f308c 100644
--- a/src/libcore/comm.rs
+++ b/src/libcore/comm.rs
@@ -94,27 +94,31 @@ fn listen<T: send, U>(f: fn(chan<T>) -> U) -> U {
     f(po.chan())
 }
 
-resource port_ptr<T: send>(po: *rust_port) unsafe {
+class port_ptr<T:send> {
+  let po: *rust_port;
+  new(po: *rust_port) { self.po = po; }
+  drop unsafe {
     task::unkillable {||
         // Once the port is detached it's guaranteed not to receive further
         // messages
         let yield = 0u;
         let yieldp = ptr::addr_of(yield);
-        rustrt::rust_port_begin_detach(po, yieldp);
+        rustrt::rust_port_begin_detach(self.po, yieldp);
         if yield != 0u {
             // Need to wait for the port to be detached
             // FIXME: If this fails then we're going to leave our port
             // in a bogus state. (Issue #1988)
             task::yield();
         }
-        rustrt::rust_port_end_detach(po);
+        rustrt::rust_port_end_detach(self.po);
 
         // Drain the port so that all the still-enqueued items get dropped
-        while rustrt::rust_port_size(po) > 0u as size_t {
-            recv_::<T>(po);
+        while rustrt::rust_port_size(self.po) > 0u as size_t {
+            recv_::<T>(self.po);
         }
-        rustrt::del_port(po);
+        rustrt::del_port(self.po);
     }
+  }
 }
 
 #[doc = "
@@ -126,21 +130,26 @@ Fails if the port is detached or dead. Fails if the port
 is owned by a different task.
 "]
 fn as_raw_port<T: send, U>(ch: comm::chan<T>, f: fn(*rust_port) -> U) -> U {
-    resource portref(p: *rust_port) {
-        if !ptr::is_null(p) {
-            rustrt::rust_port_drop(p);
-        }
+
+    class portref {
+       let p: *rust_port;
+       new(p: *rust_port) { self.p = p; }
+       drop {
+         if !ptr::is_null(self.p) {
+           rustrt::rust_port_drop(self.p);
+         }
+       }
     }
 
     let p = portref(rustrt::rust_port_take(*ch));
 
-    if ptr::is_null(*p) {
+    if ptr::is_null(p.p) {
         fail "unable to locate port for channel"
-    } else if rustrt::get_task_id() != rustrt::rust_port_task(*p) {
+    } else if rustrt::get_task_id() != rustrt::rust_port_task(p.p) {
         fail "unable to access unowned port"
     }
 
-    f(*p)
+    f(p.p)
 }
 
 #[doc = "
@@ -148,7 +157,7 @@ Constructs a channel. The channel is bound to the port used to
 construct it.
 "]
 fn chan<T: send>(p: port<T>) -> chan<T> {
-    chan_t(rustrt::get_port_id(***p))
+    chan_t(rustrt::get_port_id((**p).po))
 }
 
 #[doc = "
@@ -170,10 +179,10 @@ fn send<T: send>(ch: chan<T>, -data: T) {
 Receive from a port.  If no data is available on the port then the
 task will block until data becomes available.
 "]
-fn recv<T: send>(p: port<T>) -> T { recv_(***p) }
+fn recv<T: send>(p: port<T>) -> T { recv_((**p).po) }
 
 #[doc = "Returns true if there are messages available"]
-fn peek<T: send>(p: port<T>) -> bool { peek_(***p) }
+fn peek<T: send>(p: port<T>) -> bool { peek_((**p).po) }
 
 #[doc(hidden)]
 fn recv_chan<T: send>(ch: comm::chan<T>) -> T {
@@ -196,7 +205,7 @@ fn recv_<T: send>(p: *rust_port) -> T {
         // Data isn't available yet, so res has not been initialized.
         task::yield();
     } else {
-        // In the absense of compiler-generated preemption points
+        // In the absence of compiler-generated preemption points
         // this is a good place to yield
         task::yield();
     }
@@ -210,7 +219,7 @@ fn peek_(p: *rust_port) -> bool unsafe {
 #[doc = "Receive on one of two ports"]
 fn select2<A: send, B: send>(p_a: port<A>, p_b: port<B>)
     -> either<A, B> unsafe {
-    let ports = [***p_a, ***p_b];
+    let ports = [(**p_a).po, (**p_b).po];
     let n_ports = 2 as libc::size_t;
     let yield = 0u, yieldp = ptr::addr_of(yield);
 
@@ -233,9 +242,9 @@ fn select2<A: send, B: send>(p_a: port<A>, p_b: port<B>)
     // Now we know the port we're supposed to receive from
     assert resport != ptr::null();
 
-    if resport == ***p_a {
+    if resport == (**p_a).po {
         either::left(recv(p_a))
-    } else if resport == ***p_b {
+    } else if resport == (**p_b).po {
         either::right(recv(p_b))
     } else {
         fail "unexpected result from rust_port_select";
@@ -482,4 +491,4 @@ fn test_port_detach_fail() {
             }
         }
     }
-}
\ No newline at end of file
+}

From 0865170f1ac0167f244617a15ec3bdeb438b9ce3 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Wed, 20 Jun 2012 19:23:02 -0700
Subject: [PATCH 08/50] Register snapshots

---
 src/snapshots.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/snapshots.txt b/src/snapshots.txt
index e2f0c151889..1220958b80a 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -1,3 +1,11 @@
+S 2012-06-20 c891dec
+  macos-x86_64 cd7b3213a05e11dbf7440db016c9f7db16598501
+  macos-i386 eba609b4c815c415ca9485cac749c08ede5bf9ff
+  freebsd-x86_64 c93d3297bf68d12a55af04fecab5c1792394fcca
+  linux-x86_64 eb0e614c6f463fdbf3f40953ff122eb7cd829b85
+  linux-i386 6d858ef6915517135e633043115ab51d677010c5
+  winnt-i386  ffc26150a21aac3c5b023070c0e52d3c01b188c1
+
 S 2012-06-19 de491ea
   freebsd-x86_64 b5c1080df70136bb316286e1973fa2b5734c9a01
   winnt-i386 fa1c7b2295dbde00269f859b8cb637a59a8deec4

From 419c335faaf94cd0bdc3470eff06bed7ae53e993 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Wed, 20 Jun 2012 21:25:39 -0700
Subject: [PATCH 09/50] Apparently an extra space in the snapshot file breaks
 Windows completely?

---
 src/snapshots.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/snapshots.txt b/src/snapshots.txt
index 1220958b80a..a6ec99f2850 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -4,7 +4,7 @@ S 2012-06-20 c891dec
   freebsd-x86_64 c93d3297bf68d12a55af04fecab5c1792394fcca
   linux-x86_64 eb0e614c6f463fdbf3f40953ff122eb7cd829b85
   linux-i386 6d858ef6915517135e633043115ab51d677010c5
-  winnt-i386  ffc26150a21aac3c5b023070c0e52d3c01b188c1
+  winnt-i386 ffc26150a21aac3c5b023070c0e52d3c01b188c1
 
 S 2012-06-19 de491ea
   freebsd-x86_64 b5c1080df70136bb316286e1973fa2b5734c9a01

From f9afce319a1df2cc5c0098ea52e13dd9a54a05c9 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Wed, 20 Jun 2012 21:42:36 -0700
Subject: [PATCH 10/50] Fix typo in Windows snapshot hash

---
 src/snapshots.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/snapshots.txt b/src/snapshots.txt
index a6ec99f2850..169a8667316 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -4,7 +4,7 @@ S 2012-06-20 c891dec
   freebsd-x86_64 c93d3297bf68d12a55af04fecab5c1792394fcca
   linux-x86_64 eb0e614c6f463fdbf3f40953ff122eb7cd829b85
   linux-i386 6d858ef6915517135e633043115ab51d677010c5
-  winnt-i386 ffc26150a21aac3c5b023070c0e52d3c01b188c1
+  winnt-i386 ffc26150a21aac3c5b023070c0e52d3c01b1881c
 
 S 2012-06-19 de491ea
   freebsd-x86_64 b5c1080df70136bb316286e1973fa2b5734c9a01

From 60603703eaec6944341608f54f46661099a2423b Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 20 Jun 2012 20:08:25 -0700
Subject: [PATCH 11/50] handle moves in let initializers and allow moves from
 unsafe ptrs

Related to issue #2657, but this is not a complete fix.
---
 src/rustc/middle/borrowck/check_loans.rs         | 16 ++++++++++++++++
 src/test/compile-fail/borrowck-issue-2657-1.rs   |  9 +++++++++
 src/test/compile-fail/borrowck-issue-2657-2.rs   | 14 ++++++++++++++
 .../borrowck-move-from-unsafe-ptr.rs             |  7 +++++++
 .../run-pass/borrowck-move-from-unsafe-ptr-ok.rs | 11 +++++++++++
 5 files changed, 57 insertions(+)
 create mode 100644 src/test/compile-fail/borrowck-issue-2657-1.rs
 create mode 100644 src/test/compile-fail/borrowck-issue-2657-2.rs
 create mode 100644 src/test/compile-fail/borrowck-move-from-unsafe-ptr.rs
 create mode 100644 src/test/run-pass/borrowck-move-from-unsafe-ptr-ok.rs

diff --git a/src/rustc/middle/borrowck/check_loans.rs b/src/rustc/middle/borrowck/check_loans.rs
index 572be4f2ac7..bae0f4648d2 100644
--- a/src/rustc/middle/borrowck/check_loans.rs
+++ b/src/rustc/middle/borrowck/check_loans.rs
@@ -47,6 +47,7 @@ fn check_loans(bccx: borrowck_ctxt,
                                  mut declared_purity: ast::impure_fn,
                                  mut fn_args: @[]});
     let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
+                            visit_local: check_loans_in_local,
                             visit_block: check_loans_in_block,
                             visit_fn: check_loans_in_fn
                             with *visit::default_visitor()});
@@ -419,6 +420,9 @@ impl methods for check_loan_ctxt {
           // rvalues, I guess.
           cat_special(sk_static_item) { }
 
+          cat_deref(_, _, unsafe_ptr) {
+          }
+
           // Nothing else.
           _ {
             self.bccx.span_err(
@@ -542,6 +546,18 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
     #debug["purity on exit=%?", copy self.declared_purity];
 }
 
+fn check_loans_in_local(local: @ast::local,
+                        &&self: check_loan_ctxt,
+                        vt: visit::vt<check_loan_ctxt>) {
+    alt local.node.init {
+      some({op: ast::init_move, expr: expr}) {
+        self.check_move_out(expr);
+      }
+      some({op: ast::init_assign, _}) | none {}
+    }
+    visit::visit_local(local, self, vt);
+}
+
 fn check_loans_in_expr(expr: @ast::expr,
                        &&self: check_loan_ctxt,
                        vt: visit::vt<check_loan_ctxt>) {
diff --git a/src/test/compile-fail/borrowck-issue-2657-1.rs b/src/test/compile-fail/borrowck-issue-2657-1.rs
new file mode 100644
index 00000000000..00c579dc45e
--- /dev/null
+++ b/src/test/compile-fail/borrowck-issue-2657-1.rs
@@ -0,0 +1,9 @@
+fn main() {
+let x = some(~1);
+alt x { //! NOTE loan of immutable local variable granted here
+  some(y) {
+    let _a <- x; //! ERROR moving out of immutable local variable prohibited due to outstanding loan
+  }
+  _ {}
+}
+}
diff --git a/src/test/compile-fail/borrowck-issue-2657-2.rs b/src/test/compile-fail/borrowck-issue-2657-2.rs
new file mode 100644
index 00000000000..c9e94331ab0
--- /dev/null
+++ b/src/test/compile-fail/borrowck-issue-2657-2.rs
@@ -0,0 +1,14 @@
+//xfail-test
+
+// this should be illegal but borrowck is not handling 
+// pattern bindings correctly right now
+
+fn main() {
+let x = some(~1);
+alt x {
+  some(y) {
+    let b <- y;
+  }
+  _ {}
+}
+}
diff --git a/src/test/compile-fail/borrowck-move-from-unsafe-ptr.rs b/src/test/compile-fail/borrowck-move-from-unsafe-ptr.rs
new file mode 100644
index 00000000000..03fbb6b975c
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-from-unsafe-ptr.rs
@@ -0,0 +1,7 @@
+fn foo(x: *~int) -> ~int {
+    let y <- *x; //! ERROR dereference of unsafe pointer requires unsafe function or block
+    ret y;
+}
+
+fn main() {
+}
\ No newline at end of file
diff --git a/src/test/run-pass/borrowck-move-from-unsafe-ptr-ok.rs b/src/test/run-pass/borrowck-move-from-unsafe-ptr-ok.rs
new file mode 100644
index 00000000000..ef0803c00d0
--- /dev/null
+++ b/src/test/run-pass/borrowck-move-from-unsafe-ptr-ok.rs
@@ -0,0 +1,11 @@
+// just make sure this compiles:
+
+fn bar(x: *~int) -> ~int {
+    unsafe {
+        let y <- *x;
+        ret y;
+    }
+}
+
+fn main() {
+}
\ No newline at end of file

From 29330b5bdad47766fd36c1cc6352034724363ea1 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 08:51:26 -0700
Subject: [PATCH 12/50] Comments only: annotate FIXMEs in cargo

---
 src/cargo/cargo.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs
index a8fea66b192..fcb599fd9ef 100644
--- a/src/cargo/cargo.rs
+++ b/src/cargo/cargo.rs
@@ -166,6 +166,7 @@ fn test_is_uuid() {
 }
 
 // FIXME: implement url/URL parsing so we don't have to resort to weak checks
+// (#2661)
 
 fn has_archive_extension(p: str) -> bool {
     str::ends_with(p, ".tar") ||
@@ -189,7 +190,7 @@ fn is_archive_path(u: str) -> bool {
 
 fn is_archive_url(u: str) -> bool {
     // FIXME: this requires the protocol bit - if we had proper url parsing,
-    // we wouldn't need it
+    // we wouldn't need it (#2661)
 
     alt str::find_str(u, "://") {
         option::some(i) { has_archive_extension(u) }
@@ -958,7 +959,7 @@ fn cmd_uninstall(c: cargo) {
 
     // FIXME: needs stronger pattern matching
     // FIXME: needs to uninstall from a specified location in a cache instead
-    // of looking for it (binaries can be uninstalled by name only)
+    // of looking for it (binaries can be uninstalled by name only) (#2662)
     if is_uuid(target) {
         for os::list_dir(lib).each { |file|
             alt str::find_str(file, "-" + target + "-") {
@@ -1061,7 +1062,7 @@ fn install_query(c: cargo, wd: str, target: str) {
 
     // FIXME: This whole dep_cache and current_install
     // thing is a bit of a hack. It should be cleaned up in the future.
-
+    // #2662
     if target == c.current_install {
         for c.dep_cache.each { |k, _v|
             c.dep_cache.remove(k);
@@ -1894,7 +1895,7 @@ fn main(argv: [str]) {
     if !first_time && o.free[1] != "init" {
         cmd_init(c);
 
-        // FIXME: shouldn't need to reconfigure
+        // FIXME: shouldn't need to reconfigure (#2662)
         c = configure(o);
     }
 

From c3d384b18f71c50c587c485d48b61977866901bf Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 08:59:17 -0700
Subject: [PATCH 13/50] Comment only: annotate FIXME

---
 src/compiletest/procsrv.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs
index 1d8096042b3..5d015ead4c5 100644
--- a/src/compiletest/procsrv.rs
+++ b/src/compiletest/procsrv.rs
@@ -32,7 +32,7 @@ fn target_env(_lib_path: str, _prog: str) -> [(str,str)] {
 }
 
 
-// FIXME: This code is duplicated in core::run::program_output
+// FIXME: This code is duplicated in core::run::program_output (#2659)
 fn run(lib_path: str,
        prog: str,
        args: [str],

From 287f163136b2527504162012b94d346f5523eac9 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 21 Jun 2012 09:41:33 -0700
Subject: [PATCH 14/50] Issue #2657: track mutability of bindings, also prevent
 move from bindings

---
 src/libsyntax/parse/lexer.rs                    |  2 +-
 src/rustc/middle/borrowck.rs                    |  9 +++++++++
 src/rustc/middle/borrowck/categorization.rs     | 14 +++++++++-----
 src/rustc/middle/borrowck/gather_loans.rs       | 10 ++++++++++
 src/rustc/middle/borrowck/loan.rs               |  2 +-
 src/rustc/middle/borrowck/preserve.rs           |  6 ++++++
 src/rustc/middle/trans/base.rs                  |  2 +-
 src/test/compile-fail/borrowck-binding-mutbl.rs | 13 +++++++++++++
 8 files changed, 50 insertions(+), 8 deletions(-)
 create mode 100644 src/test/compile-fail/borrowck-binding-mutbl.rs

diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index 14cb8b41473..bbf5330c18a 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -154,7 +154,7 @@ fn tt_next_token(&&r: tt_reader) -> {tok: token::token, sp: span} {
             ret ret_val;
           }
           tt_frame_up(option::some(tt_f)) {
-            r.cur <- tt_f;
+            r.cur = tt_f;
             /* the above `if` would need to be a `while` if we didn't know
             that the last thing in a `tt_delim` is always a `tt_flat` */
             r.cur.idx += 1u;
diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs
index 2208409ab50..9818c1c648b 100644
--- a/src/rustc/middle/borrowck.rs
+++ b/src/rustc/middle/borrowck.rs
@@ -175,6 +175,7 @@ fn check_crate(tcx: ty::ctxt,
     let bccx = @{tcx: tcx,
                  method_map: method_map,
                  last_use_map: last_use_map,
+                 binding_map: int_hash(),
                  root_map: root_map(),
                  mutbl_map: int_hash()};
 
@@ -189,6 +190,7 @@ fn check_crate(tcx: ty::ctxt,
 type borrowck_ctxt = @{tcx: ty::ctxt,
                        method_map: typeck::method_map,
                        last_use_map: liveness::last_use_map,
+                       binding_map: binding_map,
                        root_map: root_map,
                        mutbl_map: mutbl_map};
 
@@ -208,6 +210,10 @@ type root_map_key = {id: ast::node_id, derefs: uint};
 // this is used in trans for optimization purposes.
 type mutbl_map = std::map::hashmap<ast::node_id, ()>;
 
+// maps from each binding's id to the mutability of the location it
+// points at.  See gather_loan.rs for more detail (search for binding_map)
+type binding_map = std::map::hashmap<ast::node_id, ast::mutability>;
+
 // Errors that can occur"]
 enum bckerr_code {
     err_mut_uniq,
@@ -228,6 +234,7 @@ enum categorization {
     cat_rvalue,                     // result of eval'ing some misc expr
     cat_special(special_kind),      //
     cat_local(ast::node_id),        // local variable
+    cat_binding(ast::node_id),      // pattern binding
     cat_arg(ast::node_id),          // formal argument
     cat_stack_upvar(cmt),           // upvar in stack closure
     cat_deref(cmt, uint, ptr_kind), // deref of a ptr
@@ -381,6 +388,7 @@ impl to_str_methods for borrowck_ctxt {
           cat_stack_upvar(_) { "stack-upvar" }
           cat_rvalue { "rvalue" }
           cat_local(node_id) { #fmt["local(%d)", node_id] }
+          cat_binding(node_id) { #fmt["binding(%d)", node_id] }
           cat_arg(node_id) { #fmt["arg(%d)", node_id] }
           cat_deref(cmt, derefs, ptr) {
             #fmt["%s->(%s, %u)", self.cat_to_repr(cmt.cat),
@@ -466,6 +474,7 @@ impl to_str_methods for borrowck_ctxt {
           cat_special(sk_heap_upvar) { "variable declared in an outer block" }
           cat_rvalue { "non-lvalue" }
           cat_local(_) { mut_str + " local variable" }
+          cat_binding(_) { "pattern binding" }
           cat_arg(_) { "argument" }
           cat_deref(_, _, pk) { #fmt["dereference of %s %s pointer",
                                      mut_str, self.pk_to_sigil(pk)] }
diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs
index cdfb2a08c68..b7143706fc3 100644
--- a/src/rustc/middle/borrowck/categorization.rs
+++ b/src/rustc/middle/borrowck/categorization.rs
@@ -265,12 +265,16 @@ impl public_methods for borrowck_ctxt {
               mutbl:m, ty:expr_ty}
           }
 
-          ast::def_binding(vid) {
-            // no difference between a binding and any other local variable
-            // from out point of view, except that they are always immutable
+          ast::def_binding(pid) {
+            // bindings are "special" since they are implicit pointers.
+
+            // lookup the mutability for this binding that we found in
+            // gather_loans when we categorized it
+            let mutbl = self.binding_map.get(pid);
+
             @{id:id, span:span,
-              cat:cat_local(vid), lp:some(@lp_local(vid)),
-              mutbl:m_imm, ty:expr_ty}
+              cat:cat_binding(pid), lp:none,
+              mutbl:mutbl, ty:expr_ty}
           }
         }
     }
diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs
index 87980bf7248..1745757151c 100644
--- a/src/rustc/middle/borrowck/gather_loans.rs
+++ b/src/rustc/middle/borrowck/gather_loans.rs
@@ -364,6 +364,16 @@ impl methods for gather_loan_ctxt {
             // cat_discr in the method preserve():
             let cmt1 = self.bccx.cat_discr(cmt, alt_id);
             let arm_scope = ty::re_scope(arm_id);
+
+            // Remember the mutability of the location that this
+            // binding refers to.  This will be used later when
+            // categorizing the binding.  This is a bit of a hack that
+            // would be better fixed by #2329; in that case we could
+            // allow the user to specify if they want an imm, const,
+            // or mut binding, or else just reflect the mutability
+            // through the type of the region pointer.
+            self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
+
             self.guarantee_valid(cmt1, m_const, arm_scope);
 
             for o_pat.each { |p|
diff --git a/src/rustc/middle/borrowck/loan.rs b/src/rustc/middle/borrowck/loan.rs
index ee61dd9f0cf..bbeca851742 100644
--- a/src/rustc/middle/borrowck/loan.rs
+++ b/src/rustc/middle/borrowck/loan.rs
@@ -43,7 +43,7 @@ impl loan_methods for loan_ctxt {
         }
 
         alt cmt.cat {
-          cat_rvalue | cat_special(_) {
+          cat_binding(_) | cat_rvalue | cat_special(_) {
             // should never be loanable
             self.bccx.tcx.sess.span_bug(
                 cmt.span,
diff --git a/src/rustc/middle/borrowck/preserve.rs b/src/rustc/middle/borrowck/preserve.rs
index 98c9109fe8e..cbe9c4e3a4a 100644
--- a/src/rustc/middle/borrowck/preserve.rs
+++ b/src/rustc/middle/borrowck/preserve.rs
@@ -29,6 +29,12 @@ impl public_methods for borrowck_ctxt {
             }
             ok(())
           }
+          cat_binding(_) {
+            // Bindings are these kind of weird implicit pointers (cc
+            // #2329).  We require (in gather_loans) that they be
+            // rooted in an immutable location.
+            ok(())
+          }
           cat_arg(_) {
             // This can happen as not all args are lendable (e.g., &&
             // modes).  In that case, the caller guarantees stability.
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 47baa8aebca..c3ab41636a8 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -3335,7 +3335,7 @@ fn need_invoke(bcx: block) -> bool {
     loop {
         alt cur.kind {
           block_scope(inf) {
-            for inf.cleanups.each {|cleanup|
+            for vec::each(inf.cleanups) {|cleanup|
                 alt cleanup {
                   clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) {
                     if cleanup_type == normal_exit_and_unwind {
diff --git a/src/test/compile-fail/borrowck-binding-mutbl.rs b/src/test/compile-fail/borrowck-binding-mutbl.rs
new file mode 100644
index 00000000000..183106aa28e
--- /dev/null
+++ b/src/test/compile-fail/borrowck-binding-mutbl.rs
@@ -0,0 +1,13 @@
+fn impure(_v: [int]) {
+}
+
+fn main() {
+    let x = {mut f: [3]};
+
+    alt x {
+      {f: v} => {
+        impure(v); //! ERROR illegal borrow unless pure: unique value in aliasable, mutable location
+        //!^ NOTE impure due to access to impure function
+      }
+    }
+}
\ No newline at end of file

From 9a2b60dfce3ababb59eac53b7da083d7bd087e1d Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 21 Jun 2012 10:15:08 -0700
Subject: [PATCH 15/50] unxfail test for #2657

---
 src/test/compile-fail/borrowck-issue-2657-2.rs | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/src/test/compile-fail/borrowck-issue-2657-2.rs b/src/test/compile-fail/borrowck-issue-2657-2.rs
index c9e94331ab0..d8d068ee8fd 100644
--- a/src/test/compile-fail/borrowck-issue-2657-2.rs
+++ b/src/test/compile-fail/borrowck-issue-2657-2.rs
@@ -1,13 +1,8 @@
-//xfail-test
-
-// this should be illegal but borrowck is not handling 
-// pattern bindings correctly right now
-
 fn main() {
 let x = some(~1);
 alt x {
   some(y) {
-    let b <- y;
+    let _b <- y; //! ERROR moving out of pattern binding
   }
   _ {}
 }

From 393f739990240914a6b147d6b642adc7ab9a939b Mon Sep 17 00:00:00 2001
From: Michael Sullivan <sully@msully.net>
Date: Thu, 21 Jun 2012 10:47:27 -0700
Subject: [PATCH 16/50] Rename upcall_malloc_dyn to just upcall_malloc.

---
 src/rt/rust_upcall.cpp            | 142 +++++++++++-------------------
 src/rustc/back/upcall.rs          |  12 +--
 src/rustc/middle/trans/base.rs    |   4 +-
 src/rustc/middle/trans/closure.rs |   2 +-
 4 files changed, 60 insertions(+), 100 deletions(-)

diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 3bd705b6690..986bc713213 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -143,66 +143,46 @@ upcall_trace(char const *msg,
  * Allocate an object in the exchange heap
  */
 
-extern "C" CDECL uintptr_t
-exchange_malloc(rust_task *task, type_desc *td, uintptr_t size) {
-
-    LOG(task, mem, "upcall exchange malloc(0x%" PRIxPTR ")", td);
-
-    size_t total_size = get_box_size(size, td->align);
-    void *p = task->kernel->calloc(total_size, "exchange malloc");
-
-    rust_opaque_box *header = static_cast<rust_opaque_box*>(p);
-    header->ref_count = -1; // This is not ref counted
-    header->td = td;
-    header->prev = 0;
-    header->next = 0;
-
-    return (uintptr_t)header;
-}
-
-// FIXME: remove after snapshot (6/13/12)
 struct s_exchange_malloc_args {
     rust_task *task;
     uintptr_t retval;
     type_desc *td;
-};
-
-extern "C" CDECL void
-upcall_s_exchange_malloc(s_exchange_malloc_args *args) {
-    rust_task *task = args->task;
-    LOG_UPCALL_ENTRY(task);
-
-    args->retval = exchange_malloc(task, args->td, args->td->size);
-}
-
-extern "C" CDECL uintptr_t
-upcall_exchange_malloc(type_desc *td) {
-    rust_task *task = rust_get_current_task();
-    s_exchange_malloc_args args = {task, 0, td};
-    UPCALL_SWITCH_STACK(task, &args, upcall_s_exchange_malloc);
-    return args.retval;
-}
-
-struct s_exchange_malloc_dyn_args {
-    rust_task *task;
-    uintptr_t retval;
-    type_desc *td;
     uintptr_t size;
 };
 
 extern "C" CDECL void
-upcall_s_exchange_malloc_dyn(s_exchange_malloc_dyn_args *args) {
+upcall_s_exchange_malloc(s_exchange_malloc_args *args) {
     rust_task *task = args->task;
     LOG_UPCALL_ENTRY(task);
+    LOG(task, mem, "upcall exchange malloc(0x%" PRIxPTR ")", args->td);
 
-    args->retval = exchange_malloc(task, args->td, args->size);
+    size_t total_size = get_box_size(args->size, args->td->align);
+    // FIXME--does this have to be calloc? (Issue #2682)
+    void *p = task->kernel->calloc(total_size, "exchange malloc");
+
+    rust_opaque_box *header = static_cast<rust_opaque_box*>(p);
+    header->ref_count = -1; // This is not ref counted
+    header->td = args->td;
+    header->prev = 0;
+    header->next = 0;
+
+    args->retval = (uintptr_t)header;
 }
 
+extern "C" CDECL uintptr_t
+upcall_exchange_malloc(type_desc *td, uintptr_t size) {
+    rust_task *task = rust_get_current_task();
+    s_exchange_malloc_args args = {task, 0, td, size};
+    UPCALL_SWITCH_STACK(task, &args, upcall_s_exchange_malloc);
+    return args.retval;
+}
+
+// FIXME: remove after snapshot (6/21/12)
 extern "C" CDECL uintptr_t
 upcall_exchange_malloc_dyn(type_desc *td, uintptr_t size) {
     rust_task *task = rust_get_current_task();
-    s_exchange_malloc_dyn_args args = {task, 0, td, size};
-    UPCALL_SWITCH_STACK(task, &args, upcall_s_exchange_malloc_dyn);
+    s_exchange_malloc_args args = {task, 0, td, size};
+    UPCALL_SWITCH_STACK(task, &args, upcall_s_exchange_malloc);
     return args.retval;
 }
 
@@ -229,69 +209,49 @@ upcall_exchange_free(void *ptr) {
  * Allocate an object in the task-local heap.
  */
 
-extern "C" CDECL uintptr_t
-shared_malloc(rust_task *task, type_desc *td, uintptr_t size) {
-    LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", td);
-
-    cc::maybe_cc(task);
-
-    // FIXME--does this have to be calloc?
-    rust_opaque_box *box = task->boxed.calloc(td, size);
-    void *body = box_body(box);
-
-    debug::maybe_track_origin(task, box);
-
-    LOG(task, mem,
-        "upcall malloc(0x%" PRIxPTR ") = box 0x%" PRIxPTR
-        " with body 0x%" PRIxPTR,
-        td, (uintptr_t)box, (uintptr_t)body);
-
-    return (uintptr_t)box;
-}
-
-// FIXME: remove after snapshot (6/13/12)
 struct s_malloc_args {
     rust_task *task;
     uintptr_t retval;
     type_desc *td;
-};
-
-extern "C" CDECL void
-upcall_s_malloc(s_malloc_args *args) {
-    rust_task *task = args->task;
-    LOG_UPCALL_ENTRY(task);
-
-    args->retval = shared_malloc(task, args->td, args->td->size);
-}
-
-extern "C" CDECL uintptr_t
-upcall_malloc(type_desc *td) {
-    rust_task *task = rust_get_current_task();
-    s_malloc_args args = {task, 0, td};
-    UPCALL_SWITCH_STACK(task, &args, upcall_s_malloc);
-    return args.retval;
-}
-
-struct s_malloc_dyn_args {
-    rust_task *task;
-    uintptr_t retval;
-    type_desc *td;
     uintptr_t size;
 };
 
 extern "C" CDECL void
-upcall_s_malloc_dyn(s_malloc_dyn_args *args) {
+upcall_s_malloc(s_malloc_args *args) {
     rust_task *task = args->task;
     LOG_UPCALL_ENTRY(task);
+    LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", args->td);
 
-    args->retval = shared_malloc(task, args->td, args->size);
+    cc::maybe_cc(task);
+
+    // FIXME--does this have to be calloc? (Issue #2682)
+    rust_opaque_box *box = task->boxed.calloc(args->td, args->size);
+    void *body = box_body(box);
+
+    debug::maybe_track_origin(task, box);
+
+    LOG(task, mem,
+        "upcall malloc(0x%" PRIxPTR ") = box 0x%" PRIxPTR
+        " with body 0x%" PRIxPTR,
+        args->td, (uintptr_t)box, (uintptr_t)body);
+
+    args->retval = (uintptr_t)box;
 }
 
+extern "C" CDECL uintptr_t
+upcall_malloc(type_desc *td, uintptr_t size) {
+    rust_task *task = rust_get_current_task();
+    s_malloc_args args = {task, 0, td, size};
+    UPCALL_SWITCH_STACK(task, &args, upcall_s_malloc);
+    return args.retval;
+}
+
+// FIXME: remove after snapshot (6/21/12)
 extern "C" CDECL uintptr_t
 upcall_malloc_dyn(type_desc *td, uintptr_t size) {
     rust_task *task = rust_get_current_task();
-    s_malloc_dyn_args args = {task, 0, td, size};
-    UPCALL_SWITCH_STACK(task, &args, upcall_s_malloc_dyn);
+    s_malloc_args args = {task, 0, td, size};
+    UPCALL_SWITCH_STACK(task, &args, upcall_s_malloc);
     return args.retval;
 }
 
diff --git a/src/rustc/back/upcall.rs b/src/rustc/back/upcall.rs
index e6a61a1d078..2cae381431d 100644
--- a/src/rustc/back/upcall.rs
+++ b/src/rustc/back/upcall.rs
@@ -10,9 +10,9 @@ import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};
 type upcalls =
     {_fail: ValueRef,
      trace: ValueRef,
-     malloc_dyn: ValueRef,
+     malloc: ValueRef,
      free: ValueRef,
-     exchange_malloc_dyn: ValueRef,
+     exchange_malloc: ValueRef,
      exchange_free: ValueRef,
      validate_box: ValueRef,
      mark: ValueRef,
@@ -55,14 +55,14 @@ fn declare_upcalls(targ_cfg: @session::config,
           trace: dv("trace", [T_ptr(T_i8()),
                               T_ptr(T_i8()),
                               int_t]),
-          malloc_dyn:
-              nothrow(d("malloc_dyn",
+          malloc:
+              nothrow(d("malloc",
                         [T_ptr(tydesc_type), int_t],
                         T_ptr(T_i8()))),
           free:
               nothrow(dv("free", [T_ptr(T_i8())])),
-          exchange_malloc_dyn:
-              nothrow(d("exchange_malloc_dyn",
+          exchange_malloc:
+              nothrow(d("exchange_malloc",
                         [T_ptr(tydesc_type), int_t],
                         T_ptr(T_i8()))),
           exchange_free:
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index c3ab41636a8..b2c02c909c7 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -356,9 +356,9 @@ fn malloc_raw_dyn(bcx: block, t: ty::t, heap: heap,
     let ccx = bcx.ccx();
 
     let (mk_fn, upcall) = alt heap {
-      heap_shared { (ty::mk_imm_box, ccx.upcalls.malloc_dyn) }
+      heap_shared { (ty::mk_imm_box, ccx.upcalls.malloc) }
       heap_exchange {
-        (ty::mk_imm_uniq, ccx.upcalls.exchange_malloc_dyn )
+        (ty::mk_imm_uniq, ccx.upcalls.exchange_malloc )
       }
     };
 
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index fd66b34c816..745c25f6f79 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -545,7 +545,7 @@ fn make_opaque_cbox_take_glue(
         let sz = Add(bcx, sz, shape::llsize_of(ccx, T_box_header(ccx)));
 
         // Allocate memory, update original ptr, and copy existing data
-        let malloc = ccx.upcalls.exchange_malloc_dyn;
+        let malloc = ccx.upcalls.exchange_malloc;
         let cbox_out = Call(bcx, malloc, [tydesc, sz]);
         let cbox_out = PointerCast(bcx, cbox_out, llopaquecboxty);
         call_memmove(bcx, cbox_out, cbox_in, sz);

From e9d072ee89bb0b41c84801670ad02201b054d16b Mon Sep 17 00:00:00 2001
From: Lindsey Kuper <lindsey@rockstargirl.org>
Date: Wed, 20 Jun 2012 18:51:08 -0700
Subject: [PATCH 17/50] Consolidate "make sure types are the same" fns.  Issue
 #2644.

---
 src/rustc/middle/typeck.rs           | 30 ++++++++++++----------------
 src/rustc/middle/typeck/check.rs     | 16 +++++----------
 src/rustc/middle/typeck/check/alt.rs |  4 ++--
 src/rustc/middle/typeck/collect.rs   |  2 +-
 src/rustc/middle/typeck/infer.rs     | 11 ----------
 5 files changed, 21 insertions(+), 42 deletions(-)

diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 3d2dca700c2..3c7bddc9022 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -188,33 +188,29 @@ fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
 
 fn require_same_types(
     tcx: ty::ctxt,
+    maybe_infcx: option<infer::infer_ctxt>,
     span: span,
     t1: ty::t,
     t2: ty::t,
     msg: fn() -> str) -> bool {
 
-    alt infer::compare_tys(tcx, t1, t2) {
-      result::ok(()) { true }
-      result::err(terr) {
-        tcx.sess.span_err(span, msg() + ": " +
-            ty::type_err_to_str(tcx, terr));
-        false
+    let l_tcx, l_infcx;
+    alt maybe_infcx {
+      none {
+        l_tcx = tcx;
+        l_infcx = infer::new_infer_ctxt(tcx);
+      }
+      some(i) {
+        l_tcx = i.tcx;
+        l_infcx = i;
       }
     }
-}
 
-fn require_same_types_in_infcx(
-    infcx: infer::infer_ctxt,
-    span: span,
-    t1: ty::t,
-    t2: ty::t,
-    msg: fn() -> str) -> bool {
-
-    alt infer::compare_tys_in_infcx(infcx, t1, t2) {
+    alt infer::mk_eqty(l_infcx, t1, t2) {
       result::ok(()) { true }
       result::err(terr) {
-        infcx.tcx.sess.span_err(span, msg() + ": " +
-            ty::type_err_to_str(infcx.tcx, terr));
+        l_tcx.sess.span_err(span, msg() + ": " +
+            ty::type_err_to_str(l_tcx, terr));
         false
       }
     }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index de12fcb389a..93fcfca31ea 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -606,14 +606,6 @@ fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
     };
 }
 
-// Returns true if the two types unify and false if they don't.
-fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool {
-    alt fcx.mk_eqty(expected, actual) {
-      result::ok(_) { ret true; }
-      result::err(_) { ret false; }
-    }
-}
-
 // AST fragment checking
 fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t {
     let tcx = fcx.ccx.tcx;
@@ -1248,9 +1240,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         };
         alt expr_opt {
           none {
-            if !are_compatible(fcx, ret_ty, ty::mk_nil(tcx)) {
+            alt fcx.mk_eqty(ret_ty, ty::mk_nil(tcx)) {
+              result::ok(_) { /* fall through */ }
+              result::err(_) {
                 tcx.sess.span_err(expr.span,
-                                  "ret; in function returning non-nil");
+                                  "ret; in function returning non-nil"); }
             }
           }
           some(e) { check_expr_with(fcx, e, ret_ty); }
@@ -2305,7 +2299,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::native_item) {
                                          expected %u", i_n_tps, n_tps));
     } else {
         require_same_types(
-            tcx, it.span, i_ty.ty, fty,
+            tcx, none, it.span, i_ty.ty, fty,
             {|| #fmt["intrinsic has wrong type. \
                       expected %s",
                      ty_to_str(ccx.tcx, fty)]});
diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs
index bb9bc0a6653..7a1eca4fc25 100644
--- a/src/rustc/middle/typeck/check/alt.rs
+++ b/src/rustc/middle/typeck/check/alt.rs
@@ -141,8 +141,8 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
             fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(end));
         #debug["pat_range beginning type: %?", b_ty];
         #debug["pat_range ending type: %?", e_ty];
-        if !require_same_types_in_infcx(
-            fcx.infcx, pat.span, b_ty, e_ty,
+        if !require_same_types(
+            tcx, some(fcx.infcx), pat.span, b_ty, e_ty,
             {|| "mismatched types in range" }) {
             // no-op
         } else if !ty::type_is_numeric(b_ty) {
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 490656eccbe..249c0105bea 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -210,7 +210,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span,
         ty::subst(tcx, substs, if_fty)
     };
     require_same_types(
-        tcx, sp, impl_fty, if_fty,
+        tcx, none, sp, impl_fty, if_fty,
         {|| "method `" + *if_m.ident + "` has an incompatible type"});
     ret;
 
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index b188f990a68..2a1f1360487 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -193,8 +193,6 @@ export resolve_deep;
 export resolve_deep_var;
 export methods; // for infer_ctxt
 export unify_methods; // for infer_ctxt
-export compare_tys;
-export compare_tys_in_infcx;
 export fixup_err, fixup_err_to_str;
 export assignment;
 export root, to_str;
@@ -399,15 +397,6 @@ fn can_mk_assignty(cx: infer_ctxt, anmnt: assignment,
     } }.to_ures()
 }
 
-fn compare_tys(tcx: ty::ctxt, a: ty::t, b: ty::t) -> ures {
-    let infcx = new_infer_ctxt(tcx);
-    mk_eqty(infcx, a, b)
-}
-
-fn compare_tys_in_infcx(infcx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
-    mk_eqty(infcx, a, b)
-}
-
 // See comment on the type `resolve_state` below
 fn resolve_shallow(cx: infer_ctxt, a: ty::t,
                    force_vars: force_level) -> fres<ty::t> {

From c2222878c84e09a86633890ad72396ef97bddf33 Mon Sep 17 00:00:00 2001
From: Lindsey Kuper <lindsey@rockstargirl.org>
Date: Thu, 21 Jun 2012 12:08:10 -0700
Subject: [PATCH 18/50] A test to exercise suffix inference for unary minus a
 little more.

---
 .../run-pass/unary-minus-suffix-inference.rs  | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 src/test/run-pass/unary-minus-suffix-inference.rs

diff --git a/src/test/run-pass/unary-minus-suffix-inference.rs b/src/test/run-pass/unary-minus-suffix-inference.rs
new file mode 100644
index 00000000000..ce052203d4d
--- /dev/null
+++ b/src/test/run-pass/unary-minus-suffix-inference.rs
@@ -0,0 +1,43 @@
+fn main() {
+    let a = 1;
+    let a_neg: i8 = -a;
+    log(error, a_neg);
+
+    let b = 1;
+    let b_neg: i16 = -b;
+    log(error, b_neg);
+
+    let c = 1;
+    let c_neg: i32 = -c;
+    log(error, b_neg);
+
+    let d = 1;
+    let d_neg: i64 = -d;
+    log(error, b_neg);
+
+    let e = 1;
+    let e_neg: int = -e;
+    log(error, b_neg);
+
+    // intentional overflows
+
+    let f = 1;
+    let f_neg: u8 = -f;
+    log(error, f_neg);
+
+    let g = 1;
+    let g_neg: u16 = -g;
+    log(error, g_neg);
+
+    let h = 1;
+    let h_neg: u32 = -h;
+    log(error, h_neg);
+
+    let i = 1;
+    let i_neg: u64 = -i;
+    log(error, i_neg);
+
+    let j = 1;
+    let j_neg: uint = -j;
+    log(error, j_neg);
+}

From 453e29cc39de1d6e0126c4908c8b289ece28ab4e Mon Sep 17 00:00:00 2001
From: Brian Anderson <banderson@mozilla.com>
Date: Thu, 21 Jun 2012 13:41:56 -0700
Subject: [PATCH 19/50] core: Remove resolved FIXME around port destruction

---
 src/libcore/comm.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs
index 7f43f6f308c..722c485d72e 100644
--- a/src/libcore/comm.rs
+++ b/src/libcore/comm.rs
@@ -106,8 +106,6 @@ class port_ptr<T:send> {
         rustrt::rust_port_begin_detach(self.po, yieldp);
         if yield != 0u {
             // Need to wait for the port to be detached
-            // FIXME: If this fails then we're going to leave our port
-            // in a bogus state. (Issue #1988)
             task::yield();
         }
         rustrt::rust_port_end_detach(self.po);

From 2a53640aa13a68e7f9cd92bb7ba59c30dfb4b903 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 13:14:50 -0700
Subject: [PATCH 20/50] Test for issue 1896 (which appears to be fixed)

---
 src/test/compile-fail/issue-1896.rs | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 src/test/compile-fail/issue-1896.rs

diff --git a/src/test/compile-fail/issue-1896.rs b/src/test/compile-fail/issue-1896.rs
new file mode 100644
index 00000000000..eea82506061
--- /dev/null
+++ b/src/test/compile-fail/issue-1896.rs
@@ -0,0 +1,8 @@
+type t<T> = { f: fn() -> T };
+
+fn f<T>(_x: t<T>) {}
+
+fn main() {
+  let x: t<()> = { f: { || () } }; //! ERROR expressions with stack closure
+    f(x);
+}

From 290206b17890a76f96979ad629203d965ff35d1c Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 16:02:29 -0700
Subject: [PATCH 21/50] Add test for issue 2214

---
 src/test/run-pass/issue-2214.rs | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 src/test/run-pass/issue-2214.rs

diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs
new file mode 100644
index 00000000000..13be6c67dad
--- /dev/null
+++ b/src/test/run-pass/issue-2214.rs
@@ -0,0 +1,18 @@
+import libc::{c_double, c_int};
+
+fn lgamma(n: c_double, value: &mut int) -> c_double {
+  ret m::lgamma(n, value as &mut c_int);
+}
+
+#[link_name = "m"]
+#[abi = "cdecl"]
+native mod m {
+    #[link_name="lgamma_r"] fn lgamma(n: c_double, sign: &mut c_int)
+      -> c_double;
+}
+
+fn main() {
+  let mut y: int = 5;
+  let x: &mut int = &mut y;
+  assert (lgamma(1.0 as c_double, x) == 42.0 as c_double);
+}
\ No newline at end of file

From be8b09160bb6cefc239a8ede5e4ac01e1d61adf9 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 14:12:18 -0700
Subject: [PATCH 22/50] Try removing code marked with "I don't think this is
 necessary"

---
 src/rt/arch/i386/morestack.S   | 9 ---------
 src/rt/arch/x86_64/morestack.S | 7 +------
 2 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S
index d1433213b2d..7f2205b573a 100644
--- a/src/rt/arch/i386/morestack.S
+++ b/src/rt/arch/i386/morestack.S
@@ -213,15 +213,6 @@ MORESTACK:
 
 	popl %ebp
 
-	// FIXME: I don't think these rules are necessary
-	// since the unwinder should never encounter an instruction
-	// pointer pointing here.
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
-	// Restore the rule for how to find %ebp
-	.cfi_restore %ebp
-	// Tell the unwinder how to find the CFA in terms of %esp
-	.cfi_def_cfa %esp, 16
-#endif
 	retl $8
 
 .L$bail:
diff --git a/src/rt/arch/x86_64/morestack.S b/src/rt/arch/x86_64/morestack.S
index 84340d26791..4ae21a3c4f6 100644
--- a/src/rt/arch/x86_64/morestack.S
+++ b/src/rt/arch/x86_64/morestack.S
@@ -51,7 +51,7 @@ MORESTACK:
 
         subq $184, %rsp
 
-	// FIXME: libgcc also saves rax. not sure if we need to
+	// FIXME: libgcc also saves rax. not sure if we need to (#2685)
 
 	// Save argument registers of the original function
 	movq %rdi,       (%rsp)
@@ -133,11 +133,6 @@ MORESTACK:
 
 	popq %rax // Restore the return value
 	popq %rbp
-	// FIXME: I don't think these rules are necessary
-	// since the unwinder should never encounter an instruction
-	// pointer pointing here.
-	.cfi_restore %rbp
-	.cfi_def_cfa %rsp, 16
 	ret
 	
 	.cfi_endproc

From c814df0bd67ba52357074d9f9a56327f93fdfcda Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 14:17:54 -0700
Subject: [PATCH 23/50] Comments only: annotate FIXMEs

---
 src/rt/memory_region.h      | 2 +-
 src/rt/rust.cpp             | 4 ++--
 src/rt/rust_builtin.cpp     | 9 +++++----
 src/rt/rust_debug.h         | 2 +-
 src/rt/rust_kernel.cpp      | 2 +-
 src/rt/rust_log.cpp         | 4 ++--
 src/rt/rust_run_program.cpp | 4 ++--
 src/rt/rust_sched_loop.cpp  | 2 +-
 8 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/src/rt/memory_region.h b/src/rt/memory_region.h
index 145020e3cca..fbc439a92a6 100644
--- a/src/rt/memory_region.h
+++ b/src/rt/memory_region.h
@@ -3,7 +3,7 @@
  * memory management and isolation between tasks, and domains.
  *
  * FIXME: Implement a custom lock-free malloc / free instead of relying solely
- *       on the standard malloc / free.
+ *       on the standard malloc / free. (#2686)
  */
 
 #ifndef MEMORY_REGION_H
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index 7efc3b8839c..7a909c57348 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -67,8 +67,8 @@ command_line_args : public kernel_owned<command_line_args>
 };
 
 // A global that indicates whether Rust typestate claim statements should be
-// executed Generated code will read this variable directly (I think).
-// FIXME: This belongs somewhere else
+// executed. Generated code will read this variable directly (I think).
+// FIXME: This belongs somewhere else (#2670)
 int check_claims = 0;
 
 /**
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index bc215c4e7b2..3f754a44298 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -233,7 +233,7 @@ rand_free(randctx *rctx) {
 /* Debug helpers strictly to verify ABI conformance.
  *
  * FIXME: move these into a testcase when the testsuite
- * understands how to have explicit C files included.
+ * understands how to have explicit C files included. (#2688)
  */
 
 struct quad {
@@ -289,17 +289,18 @@ debug_opaque(type_desc *t, uint8_t *front) {
     LOG(task, stdlib, "debug_opaque");
     debug_tydesc_helper(t);
     // FIXME may want to actually account for alignment.  `front` may not
-    // indeed be the front byte of the passed-in argument.
+    // indeed be the front byte of the passed-in argument. (#2667)
     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
     }
 }
 
-// FIXME this no longer reflects the actual structure of boxes!
+// FIXME this no longer reflects the actual structure of boxes! (#2667)
 struct rust_box {
     RUST_REFCOUNTED(rust_box)
 
     // FIXME `data` could be aligned differently from the actual box body data
+    // (#2667)
     uint8_t data[];
 };
 
@@ -635,7 +636,7 @@ extern "C" CDECL rust_task*
 rust_new_task_in_sched(rust_sched_id id) {
     rust_task *task = rust_get_current_task();
     rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
-    // FIXME: What if we didn't get the scheduler?
+    // FIXME: What if we didn't get the scheduler? (#2668)
     return new_task_common(sched, task);
 }
 
diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h
index 40a4c28f052..f0a03665f75 100644
--- a/src/rt/rust_debug.h
+++ b/src/rt/rust_debug.h
@@ -34,7 +34,7 @@ public:
     flag(const char *in_name) : name(in_name), valid(false) {}
 
     bool operator*() {
-        // FIXME: We ought to lock this.
+        // FIXME: We ought to lock this. (#2689)
         if (!valid) {
             char *ev = getenv(name);
             value = ev && ev[0] != '\0' && ev[0] != '0';
diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp
index dc743aceef8..de08436cf3f 100644
--- a/src/rt/rust_kernel.cpp
+++ b/src/rt/rust_kernel.cpp
@@ -184,7 +184,7 @@ rust_kernel::run() {
     return rval;
 }
 
-// FIXME: Fix all these FIXMEs
+// FIXME: Fix all these FIXMEs (#2690)
 void
 rust_kernel::fail() {
     // FIXME: On windows we're getting "Application has requested the
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 774a549fe8b..6e29d873ed2 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -127,7 +127,7 @@ rust_log::trace_ln(rust_task *task, uint32_t level, char *message) {
     }
 
     // FIXME: The scheduler and task names used to have meaning,
-    // but they are always equal to 'main' currently
+    // but they are always equal to 'main' currently (#2672)
 #if 0
 
 #if defined(__WIN32__)
@@ -234,7 +234,7 @@ void update_crate_map(const cratemap* map, log_directive* dirs,
     update_module_map(map->entries, dirs, n_dirs, n_matches);
     // Then recurse on linked crates
     // FIXME this does double work in diamond-shaped deps. could keep
-    //   a set of visited addresses, if it turns out to be actually slow
+    // a set of visited addresses, if it turns out to be actually slow (#2673)
     for (size_t i = 0; map->children[i]; i++) {
         update_crate_map(map->children[i], dirs, n_dirs, n_matches);
     }
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
index 8d7396aab93..b089ac46934 100644
--- a/src/rt/rust_run_program.cpp
+++ b/src/rt/rust_run_program.cpp
@@ -160,7 +160,7 @@ rust_run_program(const char* argv[],
     for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd);
     if (dir) {
         int result = chdir(dir);
-        // FIXME: need error handling
+        // FIXME: need error handling (#2674)
         assert(!result && "chdir failed");
     }
 
@@ -178,7 +178,7 @@ rust_run_program(const char* argv[],
 
 extern "C" CDECL int
 rust_process_wait(int proc) {
-    // FIXME: stub; exists to placate linker.
+    // FIXME: stub; exists to placate linker. (#2692)
     return 0;
 }
 
diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp
index e6297ec475c..a69084fc3ad 100644
--- a/src/rt/rust_sched_loop.cpp
+++ b/src/rt/rust_sched_loop.cpp
@@ -134,7 +134,7 @@ rust_task *
 rust_sched_loop::schedule_task() {
     lock.must_have_lock();
     assert(this);
-    // FIXME: in the face of failing tasks, this is not always right.
+    // FIXME: in the face of failing tasks, this is not always right. (#2695)
     // assert(n_live_tasks() > 0);
     if (running_tasks.length() > 0) {
         size_t k = isaac_rand(&rctx);

From dc11396fda7097d049708a4f48c449ad8ea0db8d Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 14:25:15 -0700
Subject: [PATCH 24/50] Remove unneeded SHAPE_VEC const

---
 src/rt/rust_shape.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index 5c83c997e2d..699a26aa562 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -43,8 +43,6 @@ const uint8_t SHAPE_I64 = 7u;
 const uint8_t SHAPE_F32 = 8u;
 const uint8_t SHAPE_F64 = 9u;
 const uint8_t SHAPE_BOX = 10u;
-// FIXME: remove after snapshot (6/18/12)
-const uint8_t SHAPE_VEC = 11u;
 const uint8_t SHAPE_TAG = 12u;
 const uint8_t SHAPE_STRUCT = 17u;
 const uint8_t SHAPE_BOX_FN = 18u;
@@ -304,7 +302,6 @@ ctxt<T>::walk() {
     case SHAPE_I64:      WALK_NUMBER(int64_t);       break;
     case SHAPE_F32:      WALK_NUMBER(float);         break;
     case SHAPE_F64:      WALK_NUMBER(double);        break;
-    case SHAPE_VEC:      walk_vec0();             break;
     case SHAPE_TAG:      walk_tag0();             break;
     case SHAPE_BOX:      walk_box0();             break;
     case SHAPE_STRUCT:   walk_struct0();          break;

From f149ea0c689e903c2db1f2aee45a9fb60f168374 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 14:25:36 -0700
Subject: [PATCH 25/50] Remove unneeded field

---
 src/rt/rust_sched_loop.h | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h
index f8e52e0498b..be80a88c30d 100644
--- a/src/rt/rust_sched_loop.h
+++ b/src/rt/rust_sched_loop.h
@@ -87,11 +87,7 @@ public:
     memory_region local_region;
 
     randctx rctx;
-
-    // FIXME: Neither of these are used
-    int32_t list_index;
-    const char *const name;
-
+    const char *const name; // Used for debugging
     // Only a pointer to 'name' is kept, so it must live as long as this
     // domain.
     rust_sched_loop(rust_scheduler *sched, int id);

From 0b1675da16fc95ea3fc7a90632de088d6d7b99f9 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 14:37:55 -0700
Subject: [PATCH 26/50] Add and xfail test for 2101

---
 src/test/run-pass/issue-2101.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 src/test/run-pass/issue-2101.rs

diff --git a/src/test/run-pass/issue-2101.rs b/src/test/run-pass/issue-2101.rs
new file mode 100644
index 00000000000..35434e11f61
--- /dev/null
+++ b/src/test/run-pass/issue-2101.rs
@@ -0,0 +1,20 @@
+// xfail-test
+use std;
+import std::arena;
+import std::arena::arena;
+
+enum hold { s(str) }
+
+fn init(ar: &a.arena::arena, str: str) -> &a.hold {
+    new(*ar) s(str)
+}
+
+fn main(args: [str]) {
+    let ar = arena::arena();
+    let leak = init(&ar, args[0]);
+    alt *leak {
+        s(astr) {
+            io::println(#fmt("%?", astr));
+        }
+    };
+}

From f8fa0a243788e6b1028d254958cd19c6f10034fa Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Wed, 13 Jun 2012 13:45:12 -0700
Subject: [PATCH 27/50] Generate a temporary for assign_ops. Issue #2581

---
 src/rustc/middle/trans/base.rs                | 14 +++-
 .../run-pass/operator-overloading-leaks.rs    | 74 +++++++++++++++++++
 2 files changed, 86 insertions(+), 2 deletions(-)
 create mode 100644 src/test/run-pass/operator-overloading-leaks.rs

diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index b2c02c909c7..5fa7ddd12ac 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1444,6 +1444,7 @@ fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
 // doesn't need to be dropped. (Issue #839)
 fn move_val(cx: block, action: copy_action, dst: ValueRef,
             src: lval_result, t: ty::t) -> block {
+    assert !cx.terminated;
     let _icx = cx.insn_ctxt("move_val");
     let mut src_val = src.val;
     let tcx = cx.tcx();
@@ -1778,7 +1779,11 @@ 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(
+
+        let dty = expr_ty(bcx, dst);
+        let target = alloc_ty(bcx, dty);
+
+        let bcx = trans_call_inner(
             bcx, ex.info(), fty,
             expr_ty(bcx, ex),
             {|bcx|
@@ -1786,7 +1791,12 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
                 // #2528
                 impl::trans_method_callee(bcx, callee_id, dst, origin)
             },
-            arg_exprs([src]), save_in(lhs_res.val));
+            arg_exprs([src]), save_in(target));
+
+        ret move_val(bcx, DROP_EXISTING, lhs_res.val,
+                     // FIXME: should kind be owned?
+                     {bcx: bcx, val: target, kind: owned},
+                     dty);
       }
       _ {}
     }
diff --git a/src/test/run-pass/operator-overloading-leaks.rs b/src/test/run-pass/operator-overloading-leaks.rs
new file mode 100644
index 00000000000..a67bffa2e92
--- /dev/null
+++ b/src/test/run-pass/operator-overloading-leaks.rs
@@ -0,0 +1,74 @@
+// The cases commented as "Leaks" need to not leak. Issue #2581
+
+impl methods<T: copy> for [T] {
+    fn -(x: [T]/&) -> [T] {
+        [x[0], x[0], x[0]]
+    }
+
+    fn foo(x: [T]/&) -> [T] {
+        [x[0], x[0], x[0]]
+    }
+}
+
+impl methods<T: copy> for ~T {
+    fn +(rhs: ~T) -> ~T {
+        rhs
+    }
+}
+
+impl methods for ~int {
+    fn -(rhs: ~int) -> ~int {
+        ~(*self - *rhs)
+    }
+}
+
+impl methods for @int {
+    fn +(rhs: @int) -> @int {
+        @(*self + *rhs)
+    }
+}
+
+fn main() {
+    // leaks
+    let mut bar = [1, 2, 3];
+    bar -= [3, 2, 1];
+    bar -= [4, 5, 6];
+    
+    io::println(#fmt("%?", bar));
+
+    // okay
+    let mut bar = [1, 2, 3];
+    bar = bar.foo([3, 2, 1]);
+    bar = bar.foo([4, 5, 6]);
+
+    io::println(#fmt("%?", bar));
+
+    // okay
+    let mut bar = [1, 2, 3];
+    bar = bar - [3, 2, 1];
+    bar = bar - [4, 5, 6];
+
+    io::println(#fmt("%?", bar));
+
+    // Leaks
+    let mut bar = ~1;
+    bar += ~2;
+    bar += ~3;
+    
+    io:: println(#fmt("%?", bar));
+
+    // Leaks
+    let mut bar = ~1;
+    bar -= ~2;
+    bar -= ~3;
+    
+    io:: println(#fmt("%?", bar));
+
+    // Leaks
+    let mut bar = @1;
+    bar += @2;
+    bar += @3;
+    
+    io:: println(#fmt("%?", bar));
+
+}

From 0e5cfd9f339c78384ef3fbcb4d230fa0bb363d54 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Wed, 13 Jun 2012 16:14:01 -0700
Subject: [PATCH 28/50] Move vector addition out of trans and into libcore.

---
 src/libcore/dvec.rs                        |   6 +-
 src/libcore/ptr.rs                         |   9 +
 src/libcore/str.rs                         |   5 +-
 src/libcore/vec.rs                         | 105 +++++++++--
 src/libstd/deque.rs                        |   4 +-
 src/libstd/rope.rs                         |   2 +-
 src/libsyntax/ast_util.rs                  |  17 +-
 src/libsyntax/parse/common.rs              |   4 +-
 src/rustc/middle/astencode.rs              | 199 ++-------------------
 src/rustc/middle/trans/base.rs             |   5 +-
 src/rustc/middle/trans/tvec.rs             |   2 +-
 src/rustc/middle/tstate/annotate.rs        |   8 +-
 src/rustc/middle/typeck/check.rs           |  16 --
 src/rustc/middle/typeck/check/method.rs    |  13 +-
 src/test/bench/core-vec-append.rs          |   8 +-
 src/test/run-fail/zip-different-lengths.rs |   4 +-
 src/test/run-pass/import-glob-crate.rs     |   2 +-
 src/test/run-pass/vec-push.rs              |   6 +-
 src/test/run-pass/zip-same-length.rs       |   4 +-
 19 files changed, 172 insertions(+), 247 deletions(-)

diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs
index 3ea8de957a0..ef368fe7a8b 100644
--- a/src/libcore/dvec.rs
+++ b/src/libcore/dvec.rs
@@ -137,7 +137,9 @@ impl extensions<A:copy> for dvec<A> {
     #[doc = "Append a single item to the end of the list"]
     fn push(t: A) {
         self.swap { |v|
-            let mut v <- v; v += [t]; v // more efficient than v + [t]
+            let mut v <- v;
+            vec::push(v, t);
+            v
         }
     }
 
@@ -170,7 +172,7 @@ impl extensions<A:copy> for dvec<A> {
             vec::reserve(v, new_len);
             let mut i = from_idx;
             while i < to_idx {
-                v += [ts[i]];
+                vec::push(v, ts[i]);
                 i += 1u;
             }
             v
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 2ce5550d951..2a89abc040f 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -10,6 +10,7 @@ export is_null;
 export is_not_null;
 export memcpy;
 export memmove;
+export memset;
 export buf_len;
 export position;
 export extensions;
@@ -23,6 +24,8 @@ native mod libc_ {
     fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
     #[rust_stack]
     fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
+    #[rust_stack]
+    fn memset(dest: *c_void, c: libc::c_int, len: libc::size_t) -> *c_void;
 }
 
 #[abi = "rust-intrinsic"]
@@ -108,6 +111,12 @@ unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
     libc_::memmove(dst as *c_void, src as *c_void, n as size_t);
 }
 
+#[inline(always)]
+unsafe fn memset<T>(dst: *mut T, c: int, count: uint)  {
+    let n = count * sys::size_of::<T>();
+    libc_::memset(dst as *c_void, c as libc::c_int, n as size_t);
+}
+
 #[doc = "Extension methods for pointers"]
 impl extensions<T> for *T {
     #[doc = "Returns true if the pointer is equal to the null pointer."]
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index f1136fde5e2..078243dfaee 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -1743,8 +1743,9 @@ mod unsafe {
    Does not verify that the vector contains valid UTF-8.
    "]
    unsafe fn from_bytes(v: [const u8]) -> str unsafe {
-       let vcopy = v + [0u8];
-       ret ::unsafe::transmute(vcopy);
+       let mut vcopy : [u8] = ::unsafe::transmute(copy v);
+       vec::push(vcopy, 0u8);
+       ::unsafe::transmute(vcopy)
    }
 
    #[doc = "
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 1eab5b12ea0..a1b2ee23f0f 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -4,6 +4,7 @@ import option::{some, none};
 import ptr::addr_of;
 import libc::size_t;
 
+export append;
 export init_op;
 export is_empty;
 export is_not_empty;
@@ -187,7 +188,9 @@ pure fn from_elem<T: copy>(n_elts: uint, t: T) -> [T] {
     let mut v = [];
     unchecked{reserve(v, n_elts)}
     let mut i: uint = 0u;
-    while i < n_elts { v += [t]; i += 1u; }
+    unsafe { // because push is impure
+        while i < n_elts { push(v, t); i += 1u; }
+    }
     ret v;
 }
 
@@ -372,11 +375,8 @@ fn shift<T: copy>(&v: [T]) -> T {
 }
 
 #[doc = "Prepend an element to a vector"]
-fn unshift<T: copy>(&v: [const T], +t: T) {
-    // n.b.---for most callers, using unshift() ought not to type check, but
-    // it does. It's because the type system is unaware of the mutability of
-    // `v` and so allows the vector to be covariant.
-    v = [const t] + v;
+fn unshift<T: copy>(&v: [T], +t: T) {
+    v = [t] + v;
 }
 
 #[doc = "Remove the last element from a vector and return it"]
@@ -390,12 +390,69 @@ fn pop<T>(&v: [const T]) -> T unsafe {
 }
 
 #[doc = "Append an element to a vector"]
+#[inline(always)]
 fn push<T>(&v: [const T], +initval: T) {
-    v += [initval];
+    let ln = v.len();
+    unsafe {
+        reserve_at_least(v, ln + 1u);
+        unsafe::set_len(v, ln + 1u);
+        let p = ptr::mut_addr_of(v[ln]);
+
+        // FIXME: for performance, try replacing the memmove and <- with a
+        // memset and unsafe::forget.
+        ptr::memset(p, 0, 1u); // needed to stop drop glue from running on
+                               // garbage data.
+        *p = initval;
+    }
 }
 
+#[inline(always)]
+fn push_all<T: copy>(&v: [const T], rhs: [const T]/&) {
+    for uint::range(0u, rhs.len()) {|i|
+        push(v, rhs[i]);
+    }
+}
 
 // Appending
+#[inline(always)]
+pure fn append<T: copy>(lhs: [T]/&, rhs: [const T]/&) -> [T] {
+    let mut v = [];
+    let mut i = 0u;
+    while i < lhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, lhs[i]);
+        }
+        i += 1u;
+    }
+    i = 0u;
+    while i < rhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, rhs[i]);
+        }
+        i += 1u;
+    }
+    ret v;
+}
+
+#[inline(always)]
+pure fn append_mut<T: copy>(lhs: [mut T]/&, rhs: [const T]/&) -> [mut T] {
+    let mut v = [mut];
+    let mut i = 0u;
+    while i < lhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, lhs[i]);
+        }
+        i += 1u;
+    }
+    i = 0u;
+    while i < rhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, rhs[i]);
+        }
+        i += 1u;
+    }
+    ret v;
+}
 
 #[doc = "
 Expands a vector in place, initializing the new elements to a given value
@@ -409,7 +466,8 @@ Expands a vector in place, initializing the new elements to a given value
 fn grow<T: copy>(&v: [const T], n: uint, initval: T) {
     reserve_at_least(v, len(v) + n);
     let mut i: uint = 0u;
-    while i < n { v += [initval]; i += 1u; }
+
+    while i < n { push(v, initval); i += 1u; }
 }
 
 #[doc = "
@@ -428,7 +486,7 @@ Function `init_op` is called `n` times with the values [0..`n`)
 fn grow_fn<T>(&v: [const T], n: uint, op: init_op<T>) {
     reserve_at_least(v, len(v) + n);
     let mut i: uint = 0u;
-    while i < n { v += [op(i)]; i += 1u; }
+    while i < n { push(v, op(i)); i += 1u; }
 }
 
 #[doc = "
@@ -453,7 +511,7 @@ Apply a function to each element of a vector and return the results
 pure fn map<T, U>(v: [T]/&, f: fn(T) -> U) -> [U] {
     let mut result = [];
     unchecked{reserve(result, len(v));}
-    for each(v) {|elem| result += [f(elem)]; }
+    for each(v) {|elem| unsafe { push(result, f(elem)); } }
     ret result;
 }
 
@@ -486,7 +544,10 @@ pure fn map2<T: copy, U: copy, V>(v0: [T]/&, v1: [U]/&,
     if v0_len != len(v1) { fail; }
     let mut u: [V] = [];
     let mut i = 0u;
-    while i < v0_len { u += [f(copy v0[i], copy v1[i])]; i += 1u; }
+    while i < v0_len {
+        unsafe { push(u, f(copy v0[i], copy v1[i])) };
+        i += 1u;
+    }
     ret u;
 }
 
@@ -502,7 +563,7 @@ pure fn filter_map<T, U: copy>(v: [T]/&, f: fn(T) -> option<U>)
     for each(v) {|elem|
         alt f(elem) {
           none {/* no-op */ }
-          some(result_elem) { result += [result_elem]; }
+          some(result_elem) { unsafe { push(result, result_elem); } }
         }
     }
     ret result;
@@ -518,7 +579,7 @@ only those elements for which `f` returned true.
 pure fn filter<T: copy>(v: [T]/&, f: fn(T) -> bool) -> [T] {
     let mut result = [];
     for each(v) {|elem|
-        if f(elem) { result += [elem]; }
+        if f(elem) { unsafe { push(result, elem); } }
     }
     ret result;
 }
@@ -530,7 +591,7 @@ Flattens a vector of vectors of T into a single vector of T.
 "]
 pure fn concat<T: copy>(v: [[T]]/&) -> [T] {
     let mut r = [];
-    for each(v) {|inner| r += inner; }
+    for each(v) {|inner| unsafe { push_all(r, inner); } }
     ret r;
 }
 
@@ -541,7 +602,7 @@ pure fn connect<T: copy>(v: [[T]]/&, sep: T) -> [T] {
     let mut r: [T] = [];
     let mut first = true;
     for each(v) {|inner|
-        if first { first = false; } else { r += [sep]; }
+        if first { first = false; } else { unsafe { push(r, sep); } }
         r += inner;
     }
     ret r;
@@ -1025,6 +1086,20 @@ pure fn unpack_mut_slice<T,U>(s: [mut T]/&,
     f(buf, len / sys::size_of::<T>())
 }
 
+impl extensions<T: copy> for [T] {
+    #[inline(always)]
+    pure fn +(rhs: [T]/&) -> [T] {
+        append(self, rhs)
+    }
+}
+
+impl extensions<T: copy> for [mut T] {
+    #[inline(always)]
+    pure fn +(rhs: [mut T]/&) -> [mut T] {
+        append_mut(self, rhs)
+    }
+}
+
 #[doc = "Extension methods for vectors"]
 impl extensions/&<T> for [const T]/& {
     #[doc = "Returns true if a vector contains no elements"]
diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs
index 1e9b2224a63..eafd2776d19 100644
--- a/src/libstd/deque.rs
+++ b/src/libstd/deque.rs
@@ -33,8 +33,8 @@ fn create<T: copy>() -> t<T> {
         let nalloc = uint::next_power_of_two(nelts + 1u);
         while i < nalloc {
             if i < nelts {
-                rv += [mut elts[(lo + i) % nelts]];
-            } else { rv += [mut none]; }
+                vec::push(rv, elts[(lo + i) % nelts]);
+            } else { vec::push(rv, none); }
             i += 1u;
         }
 
diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs
index 945b23cc47a..a8cd3b65ef8 100644
--- a/src/libstd/rope.rs
+++ b/src/libstd/rope.rs
@@ -864,7 +864,7 @@ mod node {
         loop {
             alt (leaf_iterator::next(it)) {
               option::none   { break; }
-              option::some(x) { forest += [mut @leaf(x)]; }
+              option::some(x) { vec::push(forest, @leaf(x)); }
             }
         }
         //2. Rebuild tree from forest
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 09bb2cc5409..e56bb25e55d 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -480,12 +480,17 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
             vfn(id);
         },
 
-        visit_fn: fn@(fk: visit::fn_kind, d: fn_decl,
-                      _b: blk, _sp: span, id: node_id) {
+        visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl,
+                      _b: ast::blk, _sp: span, id: ast::node_id) {
             vfn(id);
 
             alt fk {
-              visit::fk_ctor(_, tps, self_id, parent_id) |
+              visit::fk_ctor(nm, tps, self_id, parent_id) {
+                vec::iter(tps) {|tp| vfn(tp.id)}
+                vfn(id);
+                vfn(self_id);
+                vfn(parent_id.node);
+              }
               visit::fk_dtor(tps, self_id, parent_id) {
                 vec::iter(tps) {|tp| vfn(tp.id)}
                 vfn(id);
@@ -500,7 +505,11 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
                 vfn(m.self_id);
                 vec::iter(tps) {|tp| vfn(tp.id)}
               }
-              visit::fk_anon(*) | visit::fk_fn_block(*) {
+              visit::fk_anon(_, capture_clause)
+              | visit::fk_fn_block(capture_clause) {
+                for vec::each(*capture_clause) {|clause|
+                    vfn(clause.id);
+                }
               }
             }
 
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index f8292be51fe..b8362eb8734 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -159,7 +159,7 @@ impl parser_common for parser {
                        else { self.expect(t); } }
               _ { }
             }
-            v += [f(self)];
+            vec::push(v, f(self));
         }
 
         ret v;
@@ -202,7 +202,7 @@ impl parser_common for parser {
               _ { }
             }
             if sep.trailing_sep_allowed && self.token == ket { break; }
-            v += [f(self)];
+            vec::push(v, f(self));
         }
         ret v;
     }
diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs
index b275ebcb3ae..2fae0850187 100644
--- a/src/rustc/middle/astencode.rs
+++ b/src/rustc/middle/astencode.rs
@@ -66,8 +66,8 @@ type decode_ctxt = @{
 
 type extended_decode_ctxt = @{
     dcx: decode_ctxt,
-    from_id_range: id_range,
-    to_id_range: id_range
+    from_id_range: ast_util::id_range,
+    to_id_range: ast_util::id_range
 };
 
 iface tr {
@@ -86,9 +86,9 @@ fn encode_inlined_item(ecx: @e::encode_ctxt,
            ast_map::path_to_str(path), *ii.ident(),
            ebml_w.writer.tell()];
 
-    let id_range = compute_id_range(ii);
+    let id_range = ast_util::compute_id_range_for_inlined_item(ii);
     ebml_w.wr_tag(c::tag_ast as uint) {||
-        encode_id_range(ebml_w, id_range);
+        ast_util::serialize_id_range(ebml_w, id_range);
         encode_ast(ebml_w, simplify_ast(ii));
         encode_side_tables_for_ii(ecx, maps, ebml_w, ii);
     }
@@ -108,7 +108,8 @@ fn decode_inlined_item(cdata: cstore::crate_metadata,
       none { none }
       some(ast_doc) {
         #debug["> Decoding inlined fn: %s::?", ast_map::path_to_str(path)];
-        let from_id_range = decode_id_range(ast_doc);
+        let ast_dsr = ebml::ebml_deserializer(ast_doc);
+        let from_id_range = ast_util::deserialize_id_range(ast_dsr);
         let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range);
         let xcx = @{dcx: dcx,
                     from_id_range: from_id_range,
@@ -136,178 +137,10 @@ fn decode_inlined_item(cdata: cstore::crate_metadata,
 // ______________________________________________________________________
 // Enumerating the IDs which appear in an AST
 
-type id_range = {min: ast::node_id, max: ast::node_id};
-
-fn empty(range: id_range) -> bool {
-    range.min >= range.max
-}
-
-fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
-    let visitor = visit::mk_simple_visitor(@{
-        visit_mod: fn@(_m: ast::_mod, _sp: span, id: ast::node_id) {
-            vfn(id)
-        },
-
-        visit_view_item: fn@(vi: @ast::view_item) {
-            alt vi.node {
-              ast::view_item_use(_, _, id) { vfn(id) }
-              ast::view_item_import(vps) | ast::view_item_export(vps) {
-                vec::iter(vps) {|vp|
-                    alt vp.node {
-                      ast::view_path_simple(_, _, id) { vfn(id) }
-                      ast::view_path_glob(_, id) { vfn(id) }
-                      ast::view_path_list(_, _, id) { vfn(id) }
-                    }
-                }
-              }
-            }
-        },
-
-        visit_native_item: fn@(ni: @ast::native_item) {
-            vfn(ni.id)
-        },
-
-        visit_item: fn@(i: @ast::item) {
-            vfn(i.id);
-            alt i.node {
-              ast::item_res(_, _, _, d_id, c_id, _) { vfn(d_id); vfn(c_id); }
-              ast::item_enum(vs, _, _) { for vs.each {|v| vfn(v.node.id); } }
-              _ {}
-            }
-        },
-
-        visit_local: fn@(l: @ast::local) {
-            vfn(l.node.id);
-        },
-
-        visit_block: fn@(b: ast::blk) {
-            vfn(b.node.id);
-        },
-
-        visit_stmt: fn@(s: @ast::stmt) {
-            vfn(ast_util::stmt_id(*s));
-        },
-
-        visit_arm: fn@(_a: ast::arm) { },
-
-        visit_pat: fn@(p: @ast::pat) {
-            vfn(p.id)
-        },
-
-        visit_decl: fn@(_d: @ast::decl) {
-        },
-
-        visit_expr: fn@(e: @ast::expr) {
-            vfn(e.id);
-            alt e.node {
-              ast::expr_unary(*) | ast::expr_binary(*) | ast::expr_index(*) {
-                vfn(ast_util::op_expr_callee_id(e));
-              }
-              _ { /* fallthrough */ }
-            }
-        },
-
-        visit_ty: fn@(t: @ast::ty) {
-            alt t.node {
-              ast::ty_path(_, id) {
-                vfn(id)
-              }
-              _ { /* fall through */ }
-            }
-        },
-
-        visit_ty_params: fn@(ps: [ast::ty_param]) {
-            vec::iter(ps) {|p| vfn(p.id) }
-        },
-
-        visit_constr: fn@(_p: @ast::path, _sp: span, id: ast::node_id) {
-            vfn(id);
-        },
-
-        visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl,
-                      _b: ast::blk, _sp: span, id: ast::node_id) {
-            vfn(id);
-
-            alt fk {
-              visit::fk_ctor(nm, tps, self_id, parent_id) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-                vfn(id);
-                vfn(self_id);
-                vfn(parent_id.node);
-              }
-              visit::fk_dtor(tps, self_id, parent_id) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-                vfn(id);
-                vfn(self_id);
-                vfn(parent_id.node);
-              }
-              visit::fk_item_fn(_, tps) |
-              visit::fk_res(_, tps, _) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-              }
-              visit::fk_method(_, tps, m) {
-                vfn(m.self_id);
-                vec::iter(tps) {|tp| vfn(tp.id)}
-              }
-              visit::fk_anon(_, capture_clause)
-              | visit::fk_fn_block(capture_clause) {
-                for vec::each(*capture_clause) {|clause|
-                    vfn(clause.id);
-                }
-              }
-            }
-
-            vec::iter(d.inputs) {|arg|
-                vfn(arg.id)
-            }
-        },
-
-        visit_class_item: fn@(c: @ast::class_member) {
-            alt c.node {
-              ast::instance_var(_, _, _, id,_) {
-                vfn(id)
-              }
-              ast::class_method(_) {
-              }
-            }
-        }
-    });
-
-    item.accept((), visitor)
-}
-
-fn compute_id_range(item: ast::inlined_item) -> id_range {
-    let min = @mut int::max_value;
-    let max = @mut int::min_value;
-    visit_ids(item) {|id|
-        *min = int::min(*min, id);
-        *max = int::max(*max, id + 1);
-    }
-    ret {min:*min, max:*max};
-}
-
-fn encode_id_range(ebml_w: ebml::writer, id_range: id_range) {
-    ebml_w.wr_tag(c::tag_id_range as uint) {||
-        ebml_w.emit_tup(2u) {||
-            ebml_w.emit_tup_elt(0u) {|| ebml_w.emit_int(id_range.min) }
-            ebml_w.emit_tup_elt(1u) {|| ebml_w.emit_int(id_range.max) }
-        }
-    }
-}
-
-fn decode_id_range(par_doc: ebml::doc) -> id_range {
-    let range_doc = par_doc[c::tag_id_range];
-    let dsr = ebml::ebml_deserializer(range_doc);
-    dsr.read_tup(2u) {||
-        {min: dsr.read_tup_elt(0u) {|| dsr.read_int() },
-         max: dsr.read_tup_elt(1u) {|| dsr.read_int() }}
-    }
-}
-
 fn reserve_id_range(sess: session,
-                    from_id_range: id_range) -> id_range {
+                    from_id_range: ast_util::id_range) -> ast_util::id_range {
     // Handle the case of an empty range:
-    if empty(from_id_range) { ret from_id_range; }
+    if ast_util::empty(from_id_range) { ret from_id_range; }
     let cnt = from_id_range.max - from_id_range.min;
     let to_id_min = sess.parse_sess.next_id;
     let to_id_max = sess.parse_sess.next_id + cnt;
@@ -318,7 +151,7 @@ fn reserve_id_range(sess: session,
 impl translation_routines for extended_decode_ctxt {
     fn tr_id(id: ast::node_id) -> ast::node_id {
         // from_id_range should be non-empty
-        assert !empty(self.from_id_range);
+        assert !ast_util::empty(self.from_id_range);
         (id - self.from_id_range.min + self.to_id_range.min)
     }
     fn tr_def_id(did: ast::def_id) -> ast::def_id {
@@ -749,12 +582,14 @@ fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
                              ebml_w: ebml::writer,
                              ii: ast::inlined_item) {
     ebml_w.wr_tag(c::tag_table as uint) {||
-        visit_ids(ii, fn@(id: ast::node_id, copy ebml_w) {
-            // Note: this will cause a copy of ebml_w, which is bad as
-            // it has mut fields.  But I believe it's harmless since
-            // we generate balanced EBML.
-            encode_side_tables_for_id(ecx, maps, ebml_w, id)
-        });
+        ast_util::visit_ids_for_inlined_item(
+            ii,
+            fn@(id: ast::node_id, copy ebml_w) {
+                // Note: this will cause a copy of ebml_w, which is bad as
+                // it has mut fields.  But I believe it's harmless since
+                // we generate balanced EBML.
+                encode_side_tables_for_id(ecx, maps, ebml_w, id)
+            });
     }
 }
 
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 5fa7ddd12ac..d308181d8c7 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1444,7 +1444,7 @@ fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
 // doesn't need to be dropped. (Issue #839)
 fn move_val(cx: block, action: copy_action, dst: ValueRef,
             src: lval_result, t: ty::t) -> block {
-    assert !cx.terminated;
+
     let _icx = cx.insn_ctxt("move_val");
     let mut src_val = src.val;
     let tcx = cx.tcx();
@@ -1777,7 +1777,10 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
     // A user-defined operator method
     alt bcx.ccx().maps.method_map.find(ex.id) {
       some(origin) {
+        let bcx = lhs_res.bcx;
         let callee_id = ast_util::op_expr_callee_id(ex);
+        #debug["user-defined method callee_id: %s",
+               ast_map::node_id_to_str(bcx.tcx().items, callee_id)];
         let fty = node_id_type(bcx, callee_id);
 
         let dty = expr_ty(bcx, dst);
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index 1eca2db5e7d..164a089dc88 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -190,7 +190,7 @@ fn trans_evec(bcx: block, args: [@ast::expr],
         let lleltptr = InBoundsGEP(bcx, dataptr, [C_uint(ccx, i)]);
         bcx = base::trans_expr_save_in(bcx, e, lleltptr);
         add_clean_temp_mem(bcx, lleltptr, unit_ty);
-        temp_cleanups += [lleltptr];
+        vec::push(temp_cleanups, lleltptr);
         i += 1u;
     }
 
diff --git a/src/rustc/middle/tstate/annotate.rs b/src/rustc/middle/tstate/annotate.rs
index be38692c49e..d20cbcfe4d4 100644
--- a/src/rustc/middle/tstate/annotate.rs
+++ b/src/rustc/middle/tstate/annotate.rs
@@ -7,16 +7,18 @@ import aux::{num_constraints, get_fn_info, crate_ctxt, add_node};
 import ann::empty_ann;
 import pat_util::pat_binding_ids;
 
-fn collect_ids_expr(e: @expr, rs: @mut [node_id]) { *rs += [e.id]; }
+fn collect_ids_expr(e: @expr, rs: @mut [node_id]) { vec::push(*rs, e.id); }
 
-fn collect_ids_block(b: blk, rs: @mut [node_id]) { *rs += [b.node.id]; }
+fn collect_ids_block(b: blk, rs: @mut [node_id]) {
+    vec::push(*rs, b.node.id);
+}
 
 fn collect_ids_stmt(s: @stmt, rs: @mut [node_id]) {
     alt s.node {
       stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) {
         #debug["node_id %s", int::str(id)];
         #debug["%s", stmt_to_str(*s)];
-        *rs += [id];
+        vec::push(*rs, id);
       }
     }
 }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 93fcfca31ea..16834c37919 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -921,22 +921,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         let lhs_t = fcx.expr_ty(lhs);
         let lhs_t = structurally_resolved_type(fcx, lhs.span, lhs_t);
         ret alt (op, ty::get(lhs_t).struct) {
-          (ast::add, ty::ty_vec(lhs_mt)) {
-            // For adding vectors with type L=[ML TL] and R=[MR TR], the the
-            // result [ML T] where TL <: T and TR <: T.  In other words, the
-            // result type is (generally) the LUB of (TL, TR) and takes the
-            // mutability from the LHS.
-            let t_var = fcx.infcx.next_ty_var();
-            let const_vec_t = ty::mk_vec(tcx, {ty: t_var,
-                                               mutbl: ast::m_const});
-            demand::suptype(fcx, lhs.span, const_vec_t, lhs_t);
-            let rhs_bot = check_expr_with(fcx, rhs, const_vec_t);
-            let result_vec_t = ty::mk_vec(tcx, {ty: t_var,
-                                                mutbl: lhs_mt.mutbl});
-            fcx.write_ty(expr.id, result_vec_t);
-            lhs_bot | rhs_bot
-          }
-
           (_, _) if ty::type_is_integral(lhs_t) &&
           ast_util::is_shift_binop(op) {
             // Shift is a special case: rhs can be any integral type
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 4af075e8b79..c1793477b2e 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -154,7 +154,6 @@ class lookup {
     }
 
     fn add_candidates_from_param(n: uint, did: ast::def_id) {
-
         let tcx = self.tcx();
         let mut iface_bnd_idx = 0u; // count only iface bounds
         let bounds = tcx.ty_param_bounds.get(did.node);
@@ -202,6 +201,8 @@ class lookup {
 
     fn add_candidates_from_iface(did: ast::def_id, iface_substs: ty::substs) {
 
+        #debug["method_from_iface"];
+
         let ms = *ty::iface_methods(self.tcx(), did);
         for ms.eachi {|i, m|
             if m.ident != self.m_name { cont; }
@@ -235,6 +236,8 @@ class lookup {
 
     fn add_candidates_from_class(did: ast::def_id, class_substs: ty::substs) {
 
+        #debug["method_from_class"];
+
         let ms = *ty::iface_methods(self.tcx(), did);
 
         for ms.each {|m|
@@ -285,6 +288,8 @@ class lookup {
         let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);
         let mut added_any = false;
 
+        #debug["method_from_scope"];
+
         for list::each(impls_vecs) {|impls|
             for vec::each(*impls) {|im|
                 // Check whether this impl has a method with the right name.
@@ -297,9 +302,11 @@ class lookup {
 
                     // if we can assign the caller to the callee, that's a
                     // potential match.  Collect those in the vector.
-                    alt self.fcx.can_mk_assignty(
+                    let can_assign = self.fcx.can_mk_assignty(
                         self.self_expr, self.borrow_scope,
-                        self.self_ty, impl_ty) {
+                        self.self_ty, impl_ty);
+                    #debug["can_assign = %?", can_assign];
+                    alt can_assign {
                       result::err(_) { /* keep looking */ }
                       result::ok(_) {
                         let fty = self.ty_from_did(m.did);
diff --git a/src/test/bench/core-vec-append.rs b/src/test/bench/core-vec-append.rs
index af522ca8bc3..9a29671e184 100644
--- a/src/test/bench/core-vec-append.rs
+++ b/src/test/bench/core-vec-append.rs
@@ -8,6 +8,8 @@ fn collect_raw(num: uint) -> [uint] {
     let mut result = [];
     for uint::range(0u, num) { |i|
         result += [i];
+        //vec::push(result, i);
+        //result = vec::append(result, [i]);
     }
     ret result;
 }
@@ -43,18 +45,18 @@ fn main(args: [str]) {
 
     let raw = mid - start;
     let dvec = end - mid;
-
+    
     let maxf = max as float;
     let rawf = raw as float;
     let dvecf = dvec as float;
-
+    
     io::stdout().write_str(#fmt("Raw     : %? seconds\n", raw));
     io::stdout().write_str(#fmt("        : %f op/sec\n", maxf/rawf));
     io::stdout().write_str(#fmt("\n"));
     io::stdout().write_str(#fmt("Dvec    : %? seconds\n", dvec));
     io::stdout().write_str(#fmt("        : %f op/sec\n", maxf/dvecf));
     io::stdout().write_str(#fmt("\n"));
-
+    
     if dvec < raw {
         io::stdout().write_str(#fmt("Dvec is %f%% faster than raw\n",
                                     (rawf - dvecf) / rawf * 100.0));
diff --git a/src/test/run-fail/zip-different-lengths.rs b/src/test/run-fail/zip-different-lengths.rs
index 4a5ac59efd2..736b61cb935 100644
--- a/src/test/run-fail/zip-different-lengths.rs
+++ b/src/test/run-fail/zip-different-lengths.rs
@@ -10,7 +10,7 @@ fn enum_chars(start: u8, end: u8) -> [char] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i as char]; i += 1u as u8; }
+    while i <= end { vec::push(r, i as char); i += 1u as u8; }
     ret r;
 }
 
@@ -18,7 +18,7 @@ fn enum_uints(start: uint, end: uint) -> [uint] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i]; i += 1u; }
+    while i <= end { vec::push(r, i); i += 1u; }
     ret r;
 }
 
diff --git a/src/test/run-pass/import-glob-crate.rs b/src/test/run-pass/import-glob-crate.rs
index 50e7257a6a0..c1473b1a0d4 100644
--- a/src/test/run-pass/import-glob-crate.rs
+++ b/src/test/run-pass/import-glob-crate.rs
@@ -4,6 +4,6 @@ import vec::*;
 
 fn main() {
     let mut v = from_elem(0u, 0);
-    v += [4, 2];
+    v = vec::append(v, [4, 2]);
     assert (reversed(v) == [2, 4]);
 }
diff --git a/src/test/run-pass/vec-push.rs b/src/test/run-pass/vec-push.rs
index 56661e13a32..15b9239c44b 100644
--- a/src/test/run-pass/vec-push.rs
+++ b/src/test/run-pass/vec-push.rs
@@ -1,5 +1 @@
-
-
-fn push<T: copy>(&v: [const T], t: T) { v += [t]; }
-
-fn main() { let mut v = [1, 2, 3]; push(v, 1); }
+fn main() { let mut v = [1, 2, 3]; vec::push(v, 1); }
diff --git a/src/test/run-pass/zip-same-length.rs b/src/test/run-pass/zip-same-length.rs
index 73a0f66d382..9ffb564ace6 100644
--- a/src/test/run-pass/zip-same-length.rs
+++ b/src/test/run-pass/zip-same-length.rs
@@ -10,7 +10,7 @@ fn enum_chars(start: u8, end: u8) -> [char] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i as char]; i += 1u as u8; }
+    while i <= end { vec::push(r, i as char); i += 1u as u8; }
     ret r;
 }
 
@@ -18,7 +18,7 @@ fn enum_uints(start: uint, end: uint) -> [uint] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i]; i += 1u; }
+    while i <= end { vec::push(r, i); i += 1u; }
     ret r;
 }
 

From 9bdb2c9e48cefc684b6163249ca816cd96350bde Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 14 Jun 2012 11:38:45 -0700
Subject: [PATCH 29/50] Library vecs are fast now.

---
 src/libcore/dvec.rs               |  8 +++----
 src/libcore/sys.rs                |  1 +
 src/libcore/uint-template/uint.rs |  1 +
 src/libcore/vec.rs                | 40 ++++++++++++++++++++++++-------
 src/libstd/smallintmap.rs         |  2 ++
 src/test/bench/core-vec-append.rs |  4 ++--
 6 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs
index ef368fe7a8b..d30179fd881 100644
--- a/src/libcore/dvec.rs
+++ b/src/libcore/dvec.rs
@@ -113,6 +113,7 @@ impl extensions<A> for dvec<A> {
     and return a new vector to replace it with.
 
     "]
+    #[inline(always)]
     fn swap(f: fn(-[mut A]) -> [mut A]) {
         self.borrow { |v| self.return(f(v)) }
     }
@@ -136,11 +137,8 @@ impl extensions<A> for dvec<A> {
 impl extensions<A:copy> for dvec<A> {
     #[doc = "Append a single item to the end of the list"]
     fn push(t: A) {
-        self.swap { |v|
-            let mut v <- v;
-            vec::push(v, t);
-            v
-        }
+        self.check_not_borrowed();
+        vec::push(self.data, t);
     }
 
     #[doc = "Remove and return the last element"]
diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs
index 1e4e5b17bb9..77207d8aebf 100644
--- a/src/libcore/sys.rs
+++ b/src/libcore/sys.rs
@@ -51,6 +51,7 @@ pure fn get_type_desc<T>() -> *type_desc {
 }
 
 #[doc = "Returns the size of a type"]
+#[inline(always)]
 pure fn size_of<T>() -> uint unsafe {
     unchecked { rusti::size_of::<T>() }
 }
diff --git a/src/libcore/uint-template/uint.rs b/src/libcore/uint-template/uint.rs
index e1bb89c27c4..843215bd4b9 100644
--- a/src/libcore/uint-template/uint.rs
+++ b/src/libcore/uint-template/uint.rs
@@ -81,6 +81,7 @@ fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
 }
 
 #[doc = "Returns the smallest power of 2 greater than or equal to `n`"]
+#[inline(always)]
 fn next_power_of_two(n: uint) -> uint {
     let halfbits: uint = sys::size_of::<uint>() * 4u;
     let mut tmp: uint = n - 1u;
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index a1b2ee23f0f..c029e9f2448 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -92,6 +92,11 @@ native mod rustrt {
                            ++count: libc::size_t) -> *unsafe::vec_repr;
 }
 
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn move_val_init<T>(&dst: T, -src: T);
+}
+
 #[doc = "A function used to initialize the elements of a vector"]
 type init_op<T> = fn(uint) -> T;
 
@@ -392,17 +397,33 @@ fn pop<T>(&v: [const T]) -> T unsafe {
 #[doc = "Append an element to a vector"]
 #[inline(always)]
 fn push<T>(&v: [const T], +initval: T) {
-    let ln = v.len();
     unsafe {
-        reserve_at_least(v, ln + 1u);
-        unsafe::set_len(v, ln + 1u);
-        let p = ptr::mut_addr_of(v[ln]);
+        let repr: **unsafe::vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
+        let fill = (**repr).fill;
+        if (**repr).alloc > fill {
+            let sz = sys::size_of::<T>();
+            (**repr).fill += sz;
+            let p = ptr::addr_of((**repr).data);
+            let p = ptr::offset(p, fill) as *mut T;
+            rusti::move_val_init(*p, initval);
+        }
+        else {
+            push_slow(v, initval);
+        }
+    }
+}
 
-        // FIXME: for performance, try replacing the memmove and <- with a
-        // memset and unsafe::forget.
-        ptr::memset(p, 0, 1u); // needed to stop drop glue from running on
-                               // garbage data.
-        *p = initval;
+fn push_slow<T>(&v: [const T], +initval: T) {
+    unsafe {
+        let ln = v.len();
+        reserve_at_least(v, ln + 1u);
+        let repr: **unsafe::vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
+        let fill = (**repr).fill;
+        let sz = sys::size_of::<T>();
+        (**repr).fill += sz;
+        let p = ptr::addr_of((**repr).data);
+        let p = ptr::offset(p, fill) as *mut T;
+        rusti::move_val_init(*p, initval);
     }
 }
 
@@ -497,6 +518,7 @@ Sets the element at position `index` to `val`. If `index` is past the end
 of the vector, expands the vector by replicating `initval` to fill the
 intervening space.
 "]
+#[inline(always)]
 fn grow_set<T: copy>(&v: [mut T], index: uint, initval: T, val: T) {
     if index >= len(v) { grow(v, index - len(v) + 1u, initval); }
     v[index] = val;
diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs
index 1abf54b438d..3a3b90d2513 100644
--- a/src/libstd/smallintmap.rs
+++ b/src/libstd/smallintmap.rs
@@ -19,6 +19,7 @@ fn mk<T: copy>() -> smallintmap<T> {
 Add a value to the map. If the map already contains a value for
 the specified key then the original value is replaced.
 "]
+#[inline(always)]
 fn insert<T: copy>(self: smallintmap<T>, key: uint, val: T) {
     self.v.grow_set_elt(key, none, some(val));
 }
@@ -62,6 +63,7 @@ impl <V: copy> of map::map<uint, V> for smallintmap<V> {
         }
         sz
     }
+    #[inline(always)]
     fn insert(+key: uint, +value: V) -> bool {
         let exists = contains_key(self, key);
         insert(self, key, value);
diff --git a/src/test/bench/core-vec-append.rs b/src/test/bench/core-vec-append.rs
index 9a29671e184..dec12c69aa6 100644
--- a/src/test/bench/core-vec-append.rs
+++ b/src/test/bench/core-vec-append.rs
@@ -7,8 +7,8 @@ import io::writer_util;
 fn collect_raw(num: uint) -> [uint] {
     let mut result = [];
     for uint::range(0u, num) { |i|
-        result += [i];
-        //vec::push(result, i);
+        //result += [i];
+        vec::push(result, i);
         //result = vec::append(result, [i]);
     }
     ret result;

From f21fbc23d28eebccb903540740212c6e191d1ecc Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 14 Jun 2012 22:02:50 -0700
Subject: [PATCH 30/50] Fixed another performance issue

---
 src/libsyntax/parse/comments.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs
index 69aa4775e43..f1415cb9e20 100644
--- a/src/libsyntax/parse/comments.rs
+++ b/src/libsyntax/parse/comments.rs
@@ -203,7 +203,7 @@ fn gather_comments_and_literals(span_diagnostic: diagnostic::span_handler,
         let {tok: tok, sp: sp} = rdr.next_token();
         if token::is_lit(tok) {
             let s = get_str_from(rdr, bstart);
-            literals += [{lit: s, pos: sp.lo}];
+            vec::push(literals, {lit: s, pos: sp.lo});
             log(debug, "tok lit: " + s);
         } else {
             log(debug, "tok: " + token::to_str(*rdr.interner, tok));

From bb572b4234df9c206ed97606c9e1c2dd40e06dab Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Fri, 15 Jun 2012 14:05:16 -0700
Subject: [PATCH 31/50] Updating errors in vec-add.rs

---
 src/test/compile-fail/vec-add.rs | 48 +++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/src/test/compile-fail/vec-add.rs b/src/test/compile-fail/vec-add.rs
index 2d96f0c6810..d4a0ce0cfed 100644
--- a/src/test/compile-fail/vec-add.rs
+++ b/src/test/compile-fail/vec-add.rs
@@ -6,23 +6,23 @@ fn add(i: [int], m: [mut int], c: [const int]) {
 
    add(i + [3],
        m + [3],
-       c + [3]);
+       [3]);
 
    add(i + [mut 3],
        m + [mut 3],
-       c + [mut 3]);
+       [mut 3]);
 
    add(i + i,
        m + i,
-       c + i);
+       i);
 
    add(i + m,
        m + m,
-       c + m);
+       m);
 
    add(i + c,
        m + c,
-       c + c);
+       c);
 
    add(m + [3], //! ERROR mismatched types
        m + [3],
@@ -33,8 +33,10 @@ fn add(i: [int], m: [mut int], c: [const int]) {
        i + [3]);
 
    add(c + [3], //! ERROR mismatched types
-       c + [3], //! ERROR mismatched types
-       c + [3]);
+                //!^ ERROR binary operation + cannot be applied
+       c + [3], //! ERROR binary operation + cannot be applied
+                //!^ mismatched types
+       [3]);
 
    add(m + [mut 3], //! ERROR mismatched types
        m + [mut 3],
@@ -44,9 +46,11 @@ fn add(i: [int], m: [mut int], c: [const int]) {
        i + [mut 3], //! ERROR mismatched types
        i + [mut 3]);
 
-   add(c + [mut 3], //! ERROR mismatched types
-       c + [mut 3], //! ERROR mismatched types
-       c + [mut 3]);
+   add(c + [mut 3], //! ERROR binary operation + cannot be applied
+                    //!^ mismatched types
+       c + [mut 3], //! ERROR binary operation + cannot be applied
+                    //!^ mismatched types
+       [mut 3]);
 
    add(m + i, //! ERROR mismatched types
        m + i,
@@ -56,9 +60,11 @@ fn add(i: [int], m: [mut int], c: [const int]) {
        i + i, //! ERROR mismatched types
        i + i);
 
-   add(c + i, //! ERROR mismatched types
-       c + i, //! ERROR mismatched types
-       c + i);
+   add(c + i, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       c + i, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       i);
 
    add(m + m, //! ERROR mismatched types
        m + m,
@@ -68,9 +74,11 @@ fn add(i: [int], m: [mut int], c: [const int]) {
        i + m, //! ERROR mismatched types
        i + m);
 
-   add(c + m, //! ERROR mismatched types
-       c + m, //! ERROR mismatched types
-       c + m);
+   add(c + m, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       c + m, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       m);
 
    add(m + c, //! ERROR mismatched types
        m + c,
@@ -80,9 +88,11 @@ fn add(i: [int], m: [mut int], c: [const int]) {
        i + c, //! ERROR mismatched types
        i + c);
 
-   add(c + c, //! ERROR mismatched types
-       c + c, //! ERROR mismatched types
-       c + c);
+   add(c + c, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       c + c, //! ERROR binary operation + cannot be applied
+              //!^ ERROR mismatched types
+       c);
 }
 
 fn main() {

From 4d1e41561128899d6c29cef81a85be4303298698 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Fri, 15 Jun 2012 20:13:45 -0400
Subject: [PATCH 32/50] Remove some commented out code so the pretty printer
 doesn't get confused.

---
 src/test/bench/core-vec-append.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/test/bench/core-vec-append.rs b/src/test/bench/core-vec-append.rs
index dec12c69aa6..cde1c76e344 100644
--- a/src/test/bench/core-vec-append.rs
+++ b/src/test/bench/core-vec-append.rs
@@ -7,9 +7,7 @@ import io::writer_util;
 fn collect_raw(num: uint) -> [uint] {
     let mut result = [];
     for uint::range(0u, num) { |i|
-        //result += [i];
         vec::push(result, i);
-        //result = vec::append(result, [i]);
     }
     ret result;
 }

From 51ba3518ec6bfe6b47c72bb33fc5b55e21f5ac7c Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Fri, 15 Jun 2012 21:16:42 -0400
Subject: [PATCH 33/50] Remove some singleton vector appends.

---
 src/cargo/cargo.rs             | 4 ++--
 src/compiletest/compiletest.rs | 2 +-
 src/compiletest/header.rs      | 6 +++---
 src/compiletest/procsrv.rs     | 2 +-
 src/compiletest/runtest.rs     | 2 +-
 src/fuzzer/cycles.rs           | 4 ++--
 src/fuzzer/fuzzer.rs           | 2 +-
 src/fuzzer/ivec_fuzz.rs        | 8 ++++----
 src/fuzzer/rand_util.rs        | 2 +-
 9 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs
index fcb599fd9ef..7c4ada9baa7 100644
--- a/src/cargo/cargo.rs
+++ b/src/cargo/cargo.rs
@@ -316,7 +316,7 @@ fn load_crate(filename: str) -> option<crate> {
 
                 alt *attr_name {
                     "std" | "core" { }
-                    _ { e.deps += [query]; }
+                    _ { vec::push(e.deps, query); }
                 }
             }
             _ { }
@@ -775,7 +775,7 @@ fn install_source(c: cargo, path: str) {
     let mut cratefiles = [];
     for os::walk_dir(".") {|p|
         if str::ends_with(p, ".rc") {
-            cratefiles += [p];
+            vec::push(cratefiles, p);
         }
     }
 
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index 079fba0ba65..06428a993d2 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -139,7 +139,7 @@ fn make_tests(config: config) -> [test::test_desc] {
         let file = file;
         #debug("inspecting file %s", file);
         if is_test(config, file) {
-            tests += [make_test(config, file)]
+            vec::push(tests, make_test(config, file))
         }
     }
     ret tests;
diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs
index 3c33aec270f..642e2073e6b 100644
--- a/src/compiletest/header.rs
+++ b/src/compiletest/header.rs
@@ -31,7 +31,7 @@ fn load_props(testfile: str) -> test_props {
     let mut pp_exact = option::none;
     for iter_header(testfile) {|ln|
         alt parse_error_pattern(ln) {
-          option::some(ep) { error_patterns += [ep]; }
+          option::some(ep) { vec::push(error_patterns, ep) }
           option::none { }
         };
 
@@ -44,11 +44,11 @@ fn load_props(testfile: str) -> test_props {
         }
 
         option::iter(parse_aux_build(ln)) {|ab|
-            aux_builds += [ab];
+            vec::push(aux_builds, ab);
         }
 
         option::iter(parse_exec_env(ln)) {|ee|
-            exec_env += [ee];
+            vec::push(exec_env, ee);
         }
     };
     ret {
diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs
index 5d015ead4c5..b3344bece7a 100644
--- a/src/compiletest/procsrv.rs
+++ b/src/compiletest/procsrv.rs
@@ -19,7 +19,7 @@ fn target_env(lib_path: str, prog: str) -> [(str,str)] {
         else { (k,v) }
     };
     if str::ends_with(prog, "rustc.exe") {
-        env += [("RUST_THREADS", "1")]
+        vec::push(env, ("RUST_THREADS", "1"));
     }
     ret env;
 }
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 5afe663f23b..749af7d9f73 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -104,7 +104,7 @@ fn run_pretty_test(config: config, props: test_props, testfile: str) {
                           procres);
         }
 
-        srcs += [procres.stdout];
+        vec::push(srcs, procres.stdout);
         round += 1;
     }
 
diff --git a/src/fuzzer/cycles.rs b/src/fuzzer/cycles.rs
index e604d4a2357..4773a331c13 100644
--- a/src/fuzzer/cycles.rs
+++ b/src/fuzzer/cycles.rs
@@ -62,7 +62,7 @@ fn test_cycles(r : rand::rng, k: uint, n: uint)
 
     // Create a graph with no edges
     range(0u, vlen) {|_i|
-        v += [mut empty_pointy()];
+        vec::push(v, empty_pointy());
     }
 
     // Fill in the graph with random edges, with density k/n
@@ -77,7 +77,7 @@ fn test_cycles(r : rand::rng, k: uint, n: uint)
           // https://github.com/mozilla/rust/issues/1899
 
         if (likelihood(r, k, n)) { v[i].m = [p(choice(r, v))]; }
-        if (likelihood(r, k, n)) { v[i].n += [mut p(choice(r, v))]; }
+        if (likelihood(r, k, n)) { vec::push(v[i].n, mut p(choice(r, v))); }
         if (likelihood(r, k, n)) { v[i].o = {x: 0, y: p(choice(r, v))}; }
     }
 
diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs
index 95abb6636a8..7c59ceeef00 100644
--- a/src/fuzzer/fuzzer.rs
+++ b/src/fuzzer/fuzzer.rs
@@ -129,7 +129,7 @@ fn stash_ty_if(c: fn@(@ast::ty, test_mode)->bool,
                e: @ast::ty,
                tm: test_mode) {
     if c(e, tm) {
-        *es += [*e];
+        vec::push(*es,*e);
     } else {/* now my indices are wrong :( */ }
 }
 
diff --git a/src/fuzzer/ivec_fuzz.rs b/src/fuzzer/ivec_fuzz.rs
index ed02550bb13..9ea4d888fb2 100644
--- a/src/fuzzer/ivec_fuzz.rs
+++ b/src/fuzzer/ivec_fuzz.rs
@@ -57,11 +57,11 @@ fn vec_edits<T: copy>(v: [T], xs: [T]) -> [[T]] {
 
     if Lv != 1u {
         // When Lv == 1u, this is redundant with omit.
-        edits += [[]];
+        vec::push(edits, []);
     }
     if Lv >= 3u {
         // When Lv == 2u, this is redundant with swap.
-        edits += [vec::reversed(v)];
+        vec::push(edits, vec::reversed(v));
     }
     ix(0u, 1u, Lv) {|i| edits += [vec_omit(v, i)]; }
     ix(0u, 1u, Lv) {|i| edits += [vec_dup(v, i)]; }
@@ -71,10 +71,10 @@ fn vec_edits<T: copy>(v: [T], xs: [T]) -> [[T]] {
 
     ix(0u, 1u, len(xs)) {|j|
         ix(0u, 1u, Lv) {|i|
-            edits += [vec_poke(v, i, xs[j])];
+            vec::push(edits, vec_poke(v, i, xs[j]));
         }
         ix(0u, 0u, Lv) {|i|
-            edits += [vec_insert(v, i, xs[j])];
+            vec::push(edits, vec_insert(v, i, xs[j]));
         }
     }
 
diff --git a/src/fuzzer/rand_util.rs b/src/fuzzer/rand_util.rs
index 1a51ab0cd41..3f5c00c313f 100644
--- a/src/fuzzer/rand_util.rs
+++ b/src/fuzzer/rand_util.rs
@@ -62,7 +62,7 @@ fn weighted_vec<T: copy>(v : [weighted<T>]) -> [T] {
     for {weight: weight, item: item} in v {
         let i = 0u;
         while i < weight {
-            r += [item];
+            vec::push(r, item);
             i += 1u;
         }
     }

From f54829cf13158e146114b090d40260823bf3a56a Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Wed, 13 Jun 2012 16:14:01 -0700
Subject: [PATCH 34/50] Move vector addition out of trans and into libcore.

---
 src/rustc/middle/typeck/check/method.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index c1793477b2e..1c2d1234118 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -154,6 +154,8 @@ class lookup {
     }
 
     fn add_candidates_from_param(n: uint, did: ast::def_id) {
+        #debug["candidates_from_param"];
+
         let tcx = self.tcx();
         let mut iface_bnd_idx = 0u; // count only iface bounds
         let bounds = tcx.ty_param_bounds.get(did.node);

From e4c291530e4cc160eca30811e17d614f236147a4 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 7 Jun 2012 12:18:34 -0700
Subject: [PATCH 35/50] Basic functionality for new ports and chans

The first benchmark shows about twice the throughput of the old system.
---
 src/libcore/arc.rs     | 17 +++++---
 src/libcore/core.rc    |  3 +-
 src/libcore/dvec.rs    | 50 +++++++++++++++---------
 src/libcore/newcomm.rs | 88 ++++++++++++++++++++++++++++++++++++++++++
 src/libcore/vec.rs     | 24 ++++++++----
 5 files changed, 149 insertions(+), 33 deletions(-)
 create mode 100644 src/libcore/newcomm.rs

diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs
index a6baae0d082..2fa656f3eeb 100644
--- a/src/libcore/arc.rs
+++ b/src/libcore/arc.rs
@@ -28,6 +28,7 @@ resource arc_destruct<T>(data: *libc::c_void) {
     unsafe {
         let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
         let new_count = rustrt::rust_atomic_decrement(&mut data.count);
+        let data_ptr : *() = unsafe::reinterpret_cast(data);
         assert new_count >= 0;
         if new_count == 0 {
             // drop glue takes over.
@@ -68,17 +69,19 @@ allowing them to share the underlying data."]
 fn clone<T: const>(rc: &arc<T>) -> arc<T> {
     unsafe {
         let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
-        rustrt::rust_atomic_increment(&mut ptr.count);
+        let new_count = rustrt::rust_atomic_increment(&mut ptr.count);
+        let data_ptr : *() = unsafe::reinterpret_cast(ptr);
+        assert new_count >= 2;
         unsafe::forget(ptr);
     }
     arc_destruct(**rc)
 }
 
 // An arc over mutable data that is protected by a lock.
-type ex_data<T> = {lock: sys::lock_and_signal, data: T};
-type exclusive<T> = arc_destruct<ex_data<T>>;
+type ex_data<T: send> = {lock: sys::lock_and_signal, data: T};
+type exclusive<T: send> = arc_destruct<ex_data<T>>;
 
-fn exclusive<T>(-data: T) -> exclusive<T> {
+fn exclusive<T:send >(-data: T) -> exclusive<T> {
     let data = ~{mut count: 1, data: {lock: sys::create_lock(),
                                       data: data}};
     unsafe {
@@ -88,12 +91,14 @@ fn exclusive<T>(-data: T) -> exclusive<T> {
     }
 }
 
-impl methods<T> for exclusive<T> {
+impl methods<T: send> for exclusive<T> {
     fn clone() -> exclusive<T> {
         unsafe {
             // this makes me nervous...
             let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
-            rustrt::rust_atomic_increment(&mut ptr.count);
+            let new_count = rustrt::rust_atomic_increment(&mut ptr.count);
+            let data_ptr : *() = unsafe::reinterpret_cast(ptr);
+            assert new_count > 1;
             unsafe::forget(ptr);
         }
         arc_destruct(*self)
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index 913832a7f07..3185d8e30c0 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -39,7 +39,7 @@ export float, f32, f64;
 export box, char, str, ptr, vec, bool;
 export either, option, result, iter;
 export libc, os, io, run, rand, sys, unsafe, logging;
-export arc, comm, task, future;
+export arc, newcomm, comm, task, future;
 export extfmt;
 export tuple;
 export to_str;
@@ -176,6 +176,7 @@ mod dvec_iter {
 
 // Concurrency
 mod arc;
+mod newcomm;
 mod comm;
 mod task;
 mod future;
diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs
index d30179fd881..85d61d3f606 100644
--- a/src/libcore/dvec.rs
+++ b/src/libcore/dvec.rs
@@ -132,14 +132,6 @@ impl extensions<A> for dvec<A> {
         self.check_not_borrowed();
         self.data <- w;
     }
-}
-
-impl extensions<A:copy> for dvec<A> {
-    #[doc = "Append a single item to the end of the list"]
-    fn push(t: A) {
-        self.check_not_borrowed();
-        vec::push(self.data, t);
-    }
 
     #[doc = "Remove and return the last element"]
     fn pop() -> A {
@@ -151,6 +143,38 @@ impl extensions<A:copy> for dvec<A> {
         }
     }
 
+    #[doc = "Insert a single item at the front of the list"]
+    fn unshift(-t: A) {
+        unsafe {
+            let mut data = unsafe::reinterpret_cast(null::<()>());
+            data <-> self.data;
+            let data_ptr: *() = unsafe::reinterpret_cast(data);
+            if data_ptr.is_null() { fail "Recursive use of dvec"; }
+            log(error, "a");
+            self.data <- [mut t] + data;
+            log(error, "b");
+        }
+    }
+
+    #[doc = "Append a single item to the end of the list"]
+    fn push(+t: A) {
+        self.check_not_borrowed();
+        vec::push(self.data, t);
+    }
+
+
+    #[doc = "Remove and return the first element"]
+    fn shift() -> A {
+        self.borrow { |v|
+            let mut v = vec::from_mut(v);
+            let result = vec::shift(v);
+            self.return(vec::to_mut(v));
+            result
+        }
+    }
+}
+
+impl extensions<A:copy> for dvec<A> {
     #[doc = "
         Append all elements of a vector to the end of the list
 
@@ -213,16 +237,6 @@ impl extensions<A:copy> for dvec<A> {
         }
     }
 
-    #[doc = "Remove and return the first element"]
-    fn shift() -> A {
-        self.borrow { |v|
-            let mut v = vec::from_mut(v);
-            let result = vec::shift(v);
-            self.return(vec::to_mut(v));
-            result
-        }
-    }
-
     #[doc = "Copy out an individual element"]
     #[inline(always)]
     fn [](idx: uint) -> A {
diff --git a/src/libcore/newcomm.rs b/src/libcore/newcomm.rs
new file mode 100644
index 00000000000..6934dba84cd
--- /dev/null
+++ b/src/libcore/newcomm.rs
@@ -0,0 +1,88 @@
+#[doc="A new implementation of communication.
+
+This should be implementing almost entirely in Rust, and hopefully
+avoid needing a single global lock."]
+
+import arc::methods;
+import dvec::dvec;
+import dvec::{extensions};
+
+export port;
+export chan;
+export send, recv;
+export methods;
+
+type raw_port<T: send> = arc::exclusive<dvec<T>>;
+
+enum port<T: send> {
+    port_(raw_port<T>)
+}
+enum chan<T: send> {
+    chan_(raw_port<T>)
+}
+
+fn port<T: send>() -> port<T> {
+    port_(arc::exclusive(dvec()))
+}
+
+fn chan<T: send>(p: port<T>) -> chan<T> {
+    chan_((*p).clone())
+}
+
+fn send<T: send>(c: chan<T>, -x: T) {
+    let mut x <- some(x);
+    (*c).with {|cond, data|
+        let mut xx = none;
+        xx <-> x;
+        alt xx {
+          some(y) {
+            let mut x <- y;
+            (*data).push(x);
+            cond.signal();
+          }
+          none { fail }
+        };
+    }
+}
+
+fn recv<T: send>(p: port<T>) -> T {
+    (*p).with {|cond, data|
+        if (*data).len() == 0u {
+            cond.wait();
+        }
+        assert (*data).len() > 0u;
+        (*data).shift()
+    }
+}
+
+impl methods<T: send> for chan<T> {
+    fn send(-x: T) {
+        send(self, x)
+    }
+
+    fn clone() -> chan<T> {
+        chan_((*self).clone())
+    }
+}
+
+impl methods<T: send> for port<T> {
+    fn recv() -> T {
+        recv(self)
+    }
+
+    fn chan() -> chan<T> {
+        chan(self)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn newport_simple() {
+        let p = port();
+        let c = chan(p);
+
+        c.send(42);
+        assert p.recv() == 42;
+    }
+}
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index c029e9f2448..689c641e061 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -371,17 +371,25 @@ fn rsplitn<T: copy>(v: [T]/&, n: uint, f: fn(T) -> bool) -> [[T]] {
 // Mutators
 
 #[doc = "Removes the first element from a vector and return it"]
-fn shift<T: copy>(&v: [T]) -> T {
+fn shift<T>(&v: [T]) -> T {
     let ln = len::<T>(v);
     assert (ln > 0u);
-    let e = v[0];
-    v = slice::<T>(v, 1u, ln);
-    ret e;
-}
 
-#[doc = "Prepend an element to a vector"]
-fn unshift<T: copy>(&v: [T], +t: T) {
-    v = [t] + v;
+    let mut vv = [];
+    v <-> vv;
+
+    unsafe {
+        let vv = unsafe::to_ptr(vv);
+        let r <- *vv;
+
+        for uint::range(1u, ln) {|i|
+            // FIXME: this isn't legal, per se...
+            let r <- *ptr::offset(vv, i);
+            push(v, r);
+        }
+
+        r
+    }
 }
 
 #[doc = "Remove the last element from a vector and return it"]

From 3b9848b869c17ca369fc8bc7703e727eb19a211d Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 14 Jun 2012 18:09:31 -0700
Subject: [PATCH 36/50] Remove some warnings and make tests pass.

---
 src/libcore/arc.rs | 3 ---
 src/libcore/vec.rs | 7 -------
 2 files changed, 10 deletions(-)

diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs
index 2fa656f3eeb..ddbc4e8321f 100644
--- a/src/libcore/arc.rs
+++ b/src/libcore/arc.rs
@@ -28,7 +28,6 @@ resource arc_destruct<T>(data: *libc::c_void) {
     unsafe {
         let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
         let new_count = rustrt::rust_atomic_decrement(&mut data.count);
-        let data_ptr : *() = unsafe::reinterpret_cast(data);
         assert new_count >= 0;
         if new_count == 0 {
             // drop glue takes over.
@@ -70,7 +69,6 @@ fn clone<T: const>(rc: &arc<T>) -> arc<T> {
     unsafe {
         let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
         let new_count = rustrt::rust_atomic_increment(&mut ptr.count);
-        let data_ptr : *() = unsafe::reinterpret_cast(ptr);
         assert new_count >= 2;
         unsafe::forget(ptr);
     }
@@ -97,7 +95,6 @@ impl methods<T: send> for exclusive<T> {
             // this makes me nervous...
             let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
             let new_count = rustrt::rust_atomic_increment(&mut ptr.count);
-            let data_ptr : *() = unsafe::reinterpret_cast(ptr);
             assert new_count > 1;
             unsafe::forget(ptr);
         }
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 689c641e061..4455dbd2426 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -2193,13 +2193,6 @@ mod tests {
         assert addr == addr_imm;
     }
 
-    #[test]
-    fn test_unshift() {
-        let mut x = [1, 2, 3];
-        unshift(x, 0);
-        assert x == [0, 1, 2, 3];
-    }
-
     #[test]
     fn test_capacity() {
         let mut v = [0u64];

From dc3862bf58297b75a0e3d4dfdf1f66b56f51dd1d Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 14 Jun 2012 19:32:55 -0700
Subject: [PATCH 37/50] This was unsafe, and will probably leak.

---
 src/libcore/vec.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 4455dbd2426..a80acc67e42 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -379,16 +379,21 @@ fn shift<T>(&v: [T]) -> T {
     v <-> vv;
 
     unsafe {
-        let vv = unsafe::to_ptr(vv);
-        let r <- *vv;
+        let mut rr;
+        {
+            let vv = unsafe::to_ptr(vv);
+            let mut r <- *vv;
 
-        for uint::range(1u, ln) {|i|
-            // FIXME: this isn't legal, per se...
-            let r <- *ptr::offset(vv, i);
-            push(v, r);
+            for uint::range(1u, ln) {|i|
+                // FIXME: this isn't legal, per se...
+                let r <- *ptr::offset(vv, i);
+                push(v, r);
+            }
+            rr <- r;
         }
+        unsafe::set_len(vv, 0u);
 
-        r
+        rr
     }
 }
 

From 40559ea83961df06c82f76c333ce4c9604f12449 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Fri, 15 Jun 2012 14:10:36 -0700
Subject: [PATCH 38/50] Adding a benchmark for the new message passing code

---
 src/test/bench/msgsend-ring-new.rs | 76 ++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 src/test/bench/msgsend-ring-new.rs

diff --git a/src/test/bench/msgsend-ring-new.rs b/src/test/bench/msgsend-ring-new.rs
new file mode 100644
index 00000000000..cba62f2ada1
--- /dev/null
+++ b/src/test/bench/msgsend-ring-new.rs
@@ -0,0 +1,76 @@
+// This test creates a bunch of tasks that simultaneously send to each
+// other in a ring. The messages should all be basically
+// independent. It's designed to hammer the global kernel lock, so
+// that things will look really good once we get that lock out of the
+// message path.
+
+import newcomm::*;
+import future::future;
+
+use std;
+import std::time;
+
+fn thread_ring(i: uint,
+               count: uint,
+               num_chan: chan<uint>,
+               num_port: port<uint>) {
+    // Send/Receive lots of messages.
+    for uint::range(0u, count) {|j|
+        num_chan.send(i * j);
+        num_port.recv();
+    };
+}
+
+fn main(args: [str]) {
+    let args = if os::getenv("RUST_BENCH").is_some() {
+        ["", "100", "10000"]
+    } else if args.len() <= 1u {
+        ["", "100", "1000"]
+    } else {
+        args
+    };        
+
+    let num_tasks = option::get(uint::from_str(args[1]));
+    let msg_per_task = option::get(uint::from_str(args[2]));
+
+    let num_port = port();
+    let mut num_chan = chan(num_port);
+
+    let start = time::precise_time_s();
+
+    // create the ring
+    let mut futures = [];
+
+    for uint::range(1u, num_tasks) {|i|
+        let get_chan = port();
+        let get_chan_chan = chan(get_chan);
+        {
+            let num_chan = num_chan.clone();
+            futures += [future::spawn {|move num_chan, move get_chan_chan|
+                let p = port();
+                get_chan_chan.send(chan(p));
+                thread_ring(i, msg_per_task, num_chan,  p)
+            }];
+        }
+        
+        num_chan = get_chan.recv();
+    };
+
+    // do our iteration
+    thread_ring(0u, msg_per_task, num_chan, num_port);
+
+    // synchronize
+    for futures.each {|f| f.get() };
+
+    let stop = time::precise_time_s();
+
+    // all done, report stats.
+    let num_msgs = num_tasks * msg_per_task;
+    let elapsed = (stop - start);
+    let rate = (num_msgs as float) / elapsed;
+
+    io::println(#fmt("Sent %? messages in %? seconds",
+                     num_msgs, elapsed));
+    io::println(#fmt("  %? messages / second", rate));
+    io::println(#fmt("  %? μs / message", 1000000. / rate));
+}

From 28ab0e8c0335544359d1809a40682f38c9610b78 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 21 Jun 2012 14:09:39 -0700
Subject: [PATCH 39/50] Fixing illegal moves.

---
 src/libcore/newcomm.rs | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/libcore/newcomm.rs b/src/libcore/newcomm.rs
index 6934dba84cd..24c4c1cbd9c 100644
--- a/src/libcore/newcomm.rs
+++ b/src/libcore/newcomm.rs
@@ -34,14 +34,8 @@ fn send<T: send>(c: chan<T>, -x: T) {
     (*c).with {|cond, data|
         let mut xx = none;
         xx <-> x;
-        alt xx {
-          some(y) {
-            let mut x <- y;
-            (*data).push(x);
-            cond.signal();
-          }
-          none { fail }
-        };
+        (*data).push(option::unwrap(xx));
+        cond.signal();
     }
 }
 

From 559c30ab177530d0f6d7d5e717ab8a2ab7847742 Mon Sep 17 00:00:00 2001
From: Eric Holk <eric.holk@gmail.com>
Date: Thu, 21 Jun 2012 15:30:43 -0700
Subject: [PATCH 40/50] xfailing vec-add.

---
 src/test/compile-fail/vec-add.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/test/compile-fail/vec-add.rs b/src/test/compile-fail/vec-add.rs
index d4a0ce0cfed..6d18bf9e2f8 100644
--- a/src/test/compile-fail/vec-add.rs
+++ b/src/test/compile-fail/vec-add.rs
@@ -1,3 +1,9 @@
+// xfail-test
+
+// FIXME: + should allow immutable or mutable vectors on the right
+// hand side in all cases. We are getting compiler errors about this
+// now, so I'm xfailing the test for now. -eholk
+
 fn add(i: [int], m: [mut int], c: [const int]) {
 
     // Check that:

From 317864672df72a0cb33209f78506bedb99d16223 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 16:17:08 -0700
Subject: [PATCH 41/50] Revert "Add test for issue 2214"

This reverts commit 290206b17890a76f96979ad629203d965ff35d1c.

Forgot to add the actual native code, temporarily reverting.
---
 src/test/run-pass/issue-2214.rs | 18 ------------------
 1 file changed, 18 deletions(-)
 delete mode 100644 src/test/run-pass/issue-2214.rs

diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs
deleted file mode 100644
index 13be6c67dad..00000000000
--- a/src/test/run-pass/issue-2214.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-import libc::{c_double, c_int};
-
-fn lgamma(n: c_double, value: &mut int) -> c_double {
-  ret m::lgamma(n, value as &mut c_int);
-}
-
-#[link_name = "m"]
-#[abi = "cdecl"]
-native mod m {
-    #[link_name="lgamma_r"] fn lgamma(n: c_double, sign: &mut c_int)
-      -> c_double;
-}
-
-fn main() {
-  let mut y: int = 5;
-  let x: &mut int = &mut y;
-  assert (lgamma(1.0 as c_double, x) == 42.0 as c_double);
-}
\ No newline at end of file

From abfa8164cd9d64e95039019eb9b4c3fdec2685c5 Mon Sep 17 00:00:00 2001
From: Lindsey Kuper <lindsey@rockstargirl.org>
Date: Thu, 21 Jun 2012 13:25:25 -0700
Subject: [PATCH 42/50] Change the level of forcing in
 structurally_resolved_type().

A cleaner way to handle suffix inference for unary minus exprs.
---
 src/rustc/middle/typeck/check.rs | 13 +++----------
 src/rustc/middle/typeck/infer.rs | 14 +++++++-------
 2 files changed, 10 insertions(+), 17 deletions(-)

diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 16834c37919..e3f6ba40aef 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -74,7 +74,7 @@ import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
 import rscope::{in_binding_rscope, region_scope, type_rscope};
 import syntax::ast::ty_i;
 import typeck::infer::{unify_methods}; // infcx.set()
-import typeck::infer::{force_level, force_none, force_non_region_vars_only,
+import typeck::infer::{force_level, force_none, force_ty_vars_only,
                        force_all};
 
 type fn_ctxt =
@@ -1174,14 +1174,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
             }
           }
           ast::neg {
-            // If the operand's type is an integral type variable, we
-            // don't want to resolve it yet, because the rest of the
-            // typing context might not have had the opportunity to
-            // constrain it yet.
-            if !(ty::type_is_var_integral(oprnd_t)) {
-                oprnd_t = structurally_resolved_type(fcx, oprnd.span,
-                                                     oprnd_t);
-            }
+            oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t);
             if !(ty::type_is_integral(oprnd_t) ||
                  ty::type_is_fp(oprnd_t)) {
                 oprnd_t = check_user_unop(fcx, "-", "unary-", expr,
@@ -2116,7 +2109,7 @@ fn instantiate_path(fcx: @fn_ctxt,
 // resolution is possible, then an error is reported.
 fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
     alt infer::resolve_shallow(fcx.infcx, tp,
-                               force_non_region_vars_only) {
+                               force_ty_vars_only) {
       result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
       _ {
         fcx.ccx.tcx.sess.span_fatal
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index 2a1f1360487..d545702048f 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -197,7 +197,7 @@ export fixup_err, fixup_err_to_str;
 export assignment;
 export root, to_str;
 export int_ty_set_all;
-export force_level, force_none, force_non_region_vars_only, force_all;
+export force_level, force_none, force_ty_vars_only, force_all;
 
 // Bitvector to represent sets of integral types
 enum int_ty_set = uint;
@@ -1093,9 +1093,9 @@ enum force_level {
     // Any unconstrained variables are OK.
     force_none,
 
-    // Unconstrained region vars are OK; unconstrained ty vars and
-    // integral ty vars result in an error.
-    force_non_region_vars_only,
+    // Unconstrained region vars and integral ty vars are OK;
+    // unconstrained general-purpose ty vars result in an error.
+    force_ty_vars_only,
 
     // Any unconstrained variables result in an error.
     force_all,
@@ -1237,7 +1237,7 @@ impl methods for resolve_state {
               { ub:_, lb:some(t) } { self.resolve1(t) }
               { ub:none, lb:none } {
                 alt self.force_vars {
-                  force_non_region_vars_only | force_all {
+                  force_ty_vars_only | force_all {
                     self.err = some(unresolved_ty(vid));
                   }
                   force_none { /* ok */ }
@@ -1260,7 +1260,7 @@ impl methods for resolve_state {
           some(t) { t }
           none {
             alt self.force_vars {
-              force_non_region_vars_only | force_all {
+              force_all {
                 // As a last resort, default to int.
                 let ty = ty::mk_int(self.infcx.tcx);
                 self.infcx.set(
@@ -1270,7 +1270,7 @@ impl methods for resolve_state {
                         nde.rank));
                 ty
               }
-              force_none {
+              force_none | force_ty_vars_only {
                 ty::mk_var_integral(self.infcx.tcx, vid)
               }
             }

From 0fe9c0a9d11e64f556fcdee8296d7ae43c7fcd35 Mon Sep 17 00:00:00 2001
From: Lindsey Kuper <lindsey@rockstargirl.org>
Date: Thu, 21 Jun 2012 15:02:43 -0700
Subject: [PATCH 43/50] Add tests to exercise the "pattern has N field(s), but"
 error patterns.

---
 .../compile-fail/alt-pattern-field-mismatch-2.rs | 16 ++++++++++++++++
 .../compile-fail/alt-pattern-field-mismatch.rs   | 16 ++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 src/test/compile-fail/alt-pattern-field-mismatch-2.rs
 create mode 100644 src/test/compile-fail/alt-pattern-field-mismatch.rs

diff --git a/src/test/compile-fail/alt-pattern-field-mismatch-2.rs b/src/test/compile-fail/alt-pattern-field-mismatch-2.rs
new file mode 100644
index 00000000000..75e0763e4a6
--- /dev/null
+++ b/src/test/compile-fail/alt-pattern-field-mismatch-2.rs
@@ -0,0 +1,16 @@
+fn main() {
+    enum color {
+        rgb(uint, uint, uint),
+        cmyk(uint, uint, uint, uint),
+        no_color,
+    }
+
+    fn foo(c: color) {
+        alt c {
+          rgb(_, _, _) { }
+          cmyk(_, _, _, _) { }
+          no_color(_) { }
+          //!^ ERROR this pattern has 1 field, but the corresponding variant has no fields
+        }
+    }
+}
diff --git a/src/test/compile-fail/alt-pattern-field-mismatch.rs b/src/test/compile-fail/alt-pattern-field-mismatch.rs
new file mode 100644
index 00000000000..086267a85b3
--- /dev/null
+++ b/src/test/compile-fail/alt-pattern-field-mismatch.rs
@@ -0,0 +1,16 @@
+fn main() {
+    enum color {
+        rgb(uint, uint, uint),
+        cmyk(uint, uint, uint, uint),
+        no_color,
+    }
+
+    fn foo(c: color) {
+        alt c {
+          rgb(_, _) { }
+          //!^ ERROR this pattern has 2 fields, but the corresponding variant has 3 fields
+          cmyk(_, _, _, _) { }
+          no_color { }
+        }
+    }
+}

From 57101780811490fa759ed1dca310c405d28c0a72 Mon Sep 17 00:00:00 2001
From: Lindsey Kuper <lindsey@rockstargirl.org>
Date: Thu, 21 Jun 2012 15:38:21 -0700
Subject: [PATCH 44/50] Adding `i` suffixes so cfail tests keep failing after
 suffix inference

---
 src/test/compile-fail/binop-logic-int.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/compile-fail/binop-logic-int.rs b/src/test/compile-fail/binop-logic-int.rs
index ef8643bd7b4..ffa812c8b71 100644
--- a/src/test/compile-fail/binop-logic-int.rs
+++ b/src/test/compile-fail/binop-logic-int.rs
@@ -1,3 +1,3 @@
 // error-pattern:&& cannot be applied to type `int`
 
-fn main() { let x = 1 && 2; }
+fn main() { let x = 1i && 2i; }

From 312faf31dfcce7a2d15495c5042d80a3e3b476c9 Mon Sep 17 00:00:00 2001
From: Graydon Hoare <graydon@mozilla.com>
Date: Thu, 21 Jun 2012 16:44:10 -0700
Subject: [PATCH 45/50] Tag all remaining FIXMEs with bugs. Install rule in
 tidy script to enforce this.

---
 src/cargo/cargo.rs                        | 23 ++++-----
 src/compiletest/procsrv.rs                |  2 +-
 src/etc/get-snapshot.py                   |  6 +--
 src/etc/snapshot.py                       |  2 +-
 src/etc/tidy.py                           |  7 ++-
 src/libcore/cmath.rs                      | 18 ++++---
 src/libcore/core.rc                       |  6 +--
 src/libcore/extfmt.rs                     |  4 +-
 src/libcore/f32.rs                        | 17 +++----
 src/libcore/f64.rs                        | 15 +++---
 src/libcore/float.rs                      |  4 +-
 src/libcore/io.rs                         | 35 +++++++-------
 src/libcore/iter.rs                       |  8 ++--
 src/libcore/libc.rs                       | 10 ++--
 src/libcore/os.rs                         | 12 ++---
 src/libcore/run.rs                        |  4 +-
 src/libcore/str.rs                        |  4 +-
 src/libcore/task.rs                       | 16 +++----
 src/libcore/uint-template.rs              |  7 ++-
 src/libcore/vec.rs                        |  2 +-
 src/libstd/bitv.rs                        |  9 ++--
 src/libstd/deque.rs                       |  4 +-
 src/libstd/map.rs                         |  4 +-
 src/libstd/net_ip.rs                      |  2 +-
 src/libstd/net_tcp.rs                     | 35 ++++++--------
 src/libstd/smallintmap.rs                 |  4 +-
 src/libstd/time.rs                        | 37 +++++++--------
 src/libstd/uv_ll.rs                       |  2 +-
 src/libsyntax/ast.rs                      | 16 +++----
 src/libsyntax/ast_map.rs                  | 58 +++++++++++++----------
 src/libsyntax/ast_util.rs                 | 20 ++++----
 src/libsyntax/attr.rs                     | 22 ++++-----
 src/libsyntax/codemap.rs                  |  6 +--
 src/libsyntax/diagnostic.rs               |  2 +-
 src/libsyntax/ext/env.rs                  |  4 +-
 src/libsyntax/ext/expand.rs               |  8 ++--
 src/libsyntax/ext/fmt.rs                  |  7 ++-
 src/libsyntax/ext/qquote.rs               |  4 +-
 src/libsyntax/ext/simplext.rs             |  7 ++-
 src/libsyntax/fold.rs                     | 39 +++++++--------
 src/libsyntax/parse.rs                    |  6 +--
 src/libsyntax/parse/common.rs             |  4 +-
 src/libsyntax/parse/eval.rs               |  4 +-
 src/libsyntax/parse/lexer.rs              |  6 +--
 src/libsyntax/parse/parser.rs             | 20 ++++----
 src/libsyntax/print/pprust.rs             |  5 +-
 src/libsyntax/visit.rs                    | 21 ++++----
 src/rt/memory_region.h                    |  4 +-
 src/rt/rust.cpp                           |  4 +-
 src/rt/rust_builtin.cpp                   | 17 +++----
 src/rt/rust_cc.cpp                        | 12 +++--
 src/rt/rust_debug.h                       |  2 +-
 src/rt/rust_kernel.cpp                    | 23 +++++----
 src/rt/rust_log.cpp                       |  9 ++--
 src/rt/rust_run_program.cpp               |  2 +-
 src/rt/rust_sched_loop.h                  |  1 +
 src/rt/rust_scheduler.h                   |  2 +-
 src/rt/rust_shape.h                       |  5 +-
 src/rt/rust_task.cpp                      | 22 +++++----
 src/rt/rust_task.h                        | 26 +++++-----
 src/rt/rust_upcall.cpp                    | 14 +++---
 src/rt/rust_util.h                        |  2 +-
 src/rt/sync/lock_and_signal.cpp           |  3 +-
 src/rt/sync/lock_free_queue.h             |  4 +-
 src/rt/sync/timer.cpp                     |  2 +-
 src/rustc/back/link.rs                    | 12 ++---
 src/rustc/driver/driver.rs                | 24 +++++-----
 src/rustc/driver/session.rs               |  2 +-
 src/rustc/front/test.rs                   | 11 +++--
 src/rustc/metadata/creader.rs             |  4 +-
 src/rustc/metadata/decoder.rs             |  3 +-
 src/rustc/metadata/encoder.rs             |  3 +-
 src/rustc/metadata/filesearch.rs          |  4 +-
 src/rustc/metadata/loader.rs              |  4 +-
 src/rustc/middle/borrowck/gather_loans.rs | 14 +++---
 src/rustc/middle/const_eval.rs            |  4 +-
 src/rustc/middle/resolve.rs               |  6 +--
 src/rustc/middle/trans/base.rs            | 34 ++++++-------
 src/rustc/middle/trans/debuginfo.rs       |  4 +-
 src/rustc/middle/trans/native.rs          |  4 +-
 src/rustc/middle/trans/reflect.rs         | 12 ++---
 src/rustc/middle/trans/shape.rs           |  6 +--
 src/rustc/middle/trans/tvec.rs            |  5 +-
 src/rustc/middle/trans/type_use.rs        |  4 +-
 src/rustc/middle/tstate/ann.rs            |  4 +-
 src/rustc/middle/tstate/auxiliary.rs      |  9 ++--
 src/rustc/middle/tstate/states.rs         |  6 +--
 src/rustc/middle/tstate/tritv.rs          | 11 ++---
 src/rustc/middle/ty.rs                    |  5 +-
 src/rustc/middle/typeck/collect.rs        |  4 +-
 src/rustc/middle/typeck/infer.rs          | 16 +++----
 src/rustc/util/common.rs                  |  4 +-
 src/rustdoc/demo.rs                       |  2 +-
 src/rustdoc/doc.rs                        |  6 +--
 94 files changed, 460 insertions(+), 479 deletions(-)

diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs
index 7c4ada9baa7..a33f05a95f6 100644
--- a/src/cargo/cargo.rs
+++ b/src/cargo/cargo.rs
@@ -165,8 +165,8 @@ fn test_is_uuid() {
     assert !is_uuid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaป");
 }
 
-// FIXME: implement url/URL parsing so we don't have to resort to weak checks
-// (#2661)
+// FIXME (#2661): implement url/URL parsing so we don't have to resort
+// to weak checks
 
 fn has_archive_extension(p: str) -> bool {
     str::ends_with(p, ".tar") ||
@@ -189,8 +189,8 @@ fn is_archive_path(u: str) -> bool {
 }
 
 fn is_archive_url(u: str) -> bool {
-    // FIXME: this requires the protocol bit - if we had proper url parsing,
-    // we wouldn't need it (#2661)
+    // FIXME (#2661): this requires the protocol bit - if we had proper
+    // url parsing, we wouldn't need it
 
     alt str::find_str(u, "://") {
         option::some(i) { has_archive_extension(u) }
@@ -957,9 +957,10 @@ fn cmd_uninstall(c: cargo) {
     let bin = c.bindir;
     let target = c.opts.free[2u];
 
-    // FIXME: needs stronger pattern matching
-    // FIXME: needs to uninstall from a specified location in a cache instead
-    // of looking for it (binaries can be uninstalled by name only) (#2662)
+    // FIXME (#2662): needs stronger pattern matching
+    // FIXME (#2662): needs to uninstall from a specified location in a
+    // cache instead of looking for it (binaries can be uninstalled by
+    // name only)
     if is_uuid(target) {
         for os::list_dir(lib).each { |file|
             alt str::find_str(file, "-" + target + "-") {
@@ -1060,9 +1061,9 @@ fn install_query(c: cargo, wd: str, target: str) {
         }
     }
 
-    // FIXME: This whole dep_cache and current_install
-    // thing is a bit of a hack. It should be cleaned up in the future.
-    // #2662
+    // FIXME (#2662): This whole dep_cache and current_install thing is
+    // a bit of a hack. It should be cleaned up in the future.
+
     if target == c.current_install {
         for c.dep_cache.each { |k, _v|
             c.dep_cache.remove(k);
@@ -1895,7 +1896,7 @@ fn main(argv: [str]) {
     if !first_time && o.free[1] != "init" {
         cmd_init(c);
 
-        // FIXME: shouldn't need to reconfigure (#2662)
+        // FIXME (#2662): shouldn't need to reconfigure
         c = configure(o);
     }
 
diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs
index b3344bece7a..354d966c2cc 100644
--- a/src/compiletest/procsrv.rs
+++ b/src/compiletest/procsrv.rs
@@ -32,7 +32,7 @@ fn target_env(_lib_path: str, _prog: str) -> [(str,str)] {
 }
 
 
-// FIXME: This code is duplicated in core::run::program_output (#2659)
+// FIXME (#2659): This code is duplicated in core::run::program_output
 fn run(lib_path: str,
        prog: str,
        args: [str],
diff --git a/src/etc/get-snapshot.py b/src/etc/get-snapshot.py
index 964c06ffcae..7d390c8c9aa 100755
--- a/src/etc/get-snapshot.py
+++ b/src/etc/get-snapshot.py
@@ -8,11 +8,7 @@ def unpack_snapshot(triple, dl_path):
   tar = tarfile.open(dl_path)
   kernel = get_kernel(triple)
   for p in tar.getnames():
-
-    # FIXME: Fix this once win32 snapshot globs are fixed.
-    name = p.replace("rust-stage0/stage3/", "", 1);
-    name = name.replace("rust-stage0/", "", 1);
-
+    name = p.replace("rust-stage0/", "", 1);
     stagep = os.path.join(triple, "stage0")
     fp = os.path.join(stagep, name)
     print("extracting " + p)
diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py
index 9da9ae6b14d..780ba428209 100644
--- a/src/etc/snapshot.py
+++ b/src/etc/snapshot.py
@@ -183,7 +183,7 @@ Please make a clean build." % "\n  ".join(matches))
     shutil.move(file0, file1)
 
     if flag == "install":
-      # FIXME this is an ugly quick hack; pls make it better
+      # FIXME (#2664): this is an ugly quick hack; pls make it better
       path  = file1
       comps = path.split("-")
       parts = { 'year': comps[2], \
diff --git a/src/etc/tidy.py b/src/etc/tidy.py
index a8d87ece989..51e13e7af19 100644
--- a/src/etc/tidy.py
+++ b/src/etc/tidy.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import sys, fileinput, subprocess
+import sys, fileinput, subprocess, re
 
 err=0
 cols=78
@@ -23,6 +23,11 @@ file_names = [s for s in sys.argv[1:] if not s.endswith("_gen.rs")]
 try:
     for line in fileinput.input(file_names,
                                 openhook=fileinput.hook_encoded("utf-8")):
+
+        if fileinput.filename().find("tidy.py") == -1:
+            if line.find("FIXME") != -1:
+                if re.search("FIXME.*#\d+", line) == None:
+                    report_err("FIXME without issue number")
         if (line.find('\t') != -1 and
             fileinput.filename().find("Makefile") == -1):
             report_err("tab character")
diff --git a/src/libcore/cmath.rs b/src/libcore/cmath.rs
index f0b346e32a3..fbb434d8e4b 100644
--- a/src/libcore/cmath.rs
+++ b/src/libcore/cmath.rs
@@ -2,8 +2,8 @@ export c_float;
 export c_double;
 
 // uncomment once #1433 is fixed
-// FIXME export c_float_math_consts;
-// FIXME export c_double_math_consts;
+// FIXME (#1433): export c_float_math_consts;
+// FIXME (#1433): export c_double_math_consts;
 
 export c_float_targ_consts;
 export c_double_targ_consts;
@@ -68,8 +68,7 @@ native mod c_double {
     #[link_name="ilogb"] pure fn ilog_radix(n: c_double) -> c_int;
     pure fn modf(n: c_double, &iptr: c_double) -> c_double;
     pure fn pow(n: c_double, e: c_double) -> c_double;
-// FIXME enable when rounding modes become available
-// (See Issue #1379)
+// FIXME (#1379): enable when rounding modes become available
 //    pure fn rint(n: c_double) -> c_double;
     pure fn round(n: c_double) -> c_double;
     // rename: for consistency with logradix
@@ -149,8 +148,7 @@ native mod c_float {
     #[link_name="modff"] pure fn modf(n: c_float,
                                       &iptr: c_float) -> c_float;
     #[link_name="powf"] pure fn pow(n: c_float, e: c_float) -> c_float;
-// FIXME enable when rounding modes become available
-// (See Issue #1379)
+// FIXME (#1379): enable when rounding modes become available
 //    #[link_name="rintf"] pure fn rint(n: c_float) -> c_float;
     #[link_name="roundf"] pure fn round(n: c_float) -> c_float;
     #[link_name="scalbnf"] pure fn ldexp_radix(n: c_float, i: c_int)
@@ -176,8 +174,8 @@ mod c_float_targ_consts {
     const max_exp: uint = 128u;
     const min_10_exp: int = -37;
     const max_10_exp: int = 38;
-    // FIXME this is wrong! replace with hexadecimal (%a) constants below
-    // (see Issue #1433)
+    // FIXME (#1433): this is wrong, replace with hexadecimal (%a) constants
+    // below.
     const min_value: f32 = 1.175494e-38_f32;
     const max_value: f32 = 3.402823e+38_f32;
     const epsilon: f32 = 0.000000_f32;
@@ -191,8 +189,8 @@ mod c_double_targ_consts {
     const max_exp: uint = 1024u;
     const min_10_exp: int = -307;
     const max_10_exp: int = 308;
-    // FIXME this is wrong! replace with hexadecimal (%a) constants below
-    // (see Issue #1433)
+    // FIXME (#1433): this is wrong, replace with hexadecimal (%a) constants
+    // below.
     const min_value: f64 = 2.225074e-308_f64;
     const max_value: f64 = 1.797693e+308_f64;
     const epsilon: f64 = 2.220446e-16_f64;
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index 3185d8e30c0..8f4b301adaf 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -50,9 +50,9 @@ export num;
 // NDM seems to be necessary for resolve to work
 export option_iter;
 
-// FIXME: This creates some APIs that I do not want to commit to. It is
-// currently exported for the uv code in std, but when that code moves into
-// core this should become unexported
+// FIXME (#2648): This creates some APIs that I do not want to commit
+// to. It is currently exported for the uv code in std, but when that
+// code moves into core this should become unexported
 export priv;
 
 
diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs
index 1ae69046715..144ea571d7c 100644
--- a/src/libcore/extfmt.rs
+++ b/src/libcore/extfmt.rs
@@ -274,8 +274,8 @@ mod rt {
     enum count { count_is(int), count_implied, }
     enum ty { ty_default, ty_bits, ty_hex_upper, ty_hex_lower, ty_octal, }
 
-    // FIXME: May not want to use a vector here for flags;
-    // instead just use a bool per flag (see Issue #1993)
+    // FIXME (#1993): May not want to use a vector here for flags; instead
+    // just use a bool per flag.
     type conv = {flags: [flag], width: count, precision: count, ty: ty};
 
     fn conv_int(cv: conv, i: int) -> str {
diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs
index e1d30081966..821fa68f55c 100644
--- a/src/libcore/f32.rs
+++ b/src/libcore/f32.rs
@@ -6,8 +6,6 @@ import cmath::c_float::*;
 import cmath::c_float_targ_consts::*;
 import num::num;
 
-// FIXME find out why these have to be exported explicitly
-
 export add, sub, mul, div, rem, lt, le, gt, eq, eq, ne;
 export is_positive, is_negative, is_nonpositive, is_nonnegative;
 export is_zero, is_infinite, is_finite;
@@ -55,9 +53,8 @@ pure fn ge(x: f32, y: f32) -> bool { ret x >= y; }
 
 pure fn gt(x: f32, y: f32) -> bool { ret x > y; }
 
-// FIXME replace the predicates below with llvm intrinsics or calls
-// to the libmath macros in the rust runtime for performance
-// See Issue #1999
+// FIXME (#1999): replace the predicates below with llvm intrinsics or
+// calls to the libmath macros in the rust runtime for performance.
 
 #[doc = "
 Returns true if `x` is a positive number, including +0.0f320 and +Infinity
@@ -106,14 +103,13 @@ pure fn is_finite(x: f32) -> bool {
     ret !(is_NaN(x) || is_infinite(x));
 }
 
-// FIXME add is_normal, is_subnormal, and fpclassify
-// also see Issue #1999
+// FIXME (#1999): add is_normal, is_subnormal, and fpclassify.
 
 /* Module: consts */
 mod consts {
 
-    // FIXME replace with mathematical constants from cmath
-    // (requires Issue #1433 to fix)
+    // FIXME (requires Issue #1433 to fix): replace with mathematical
+    // constants from cmath.
     #[doc = "Archimedes' constant"]
     const pi: f32 = 3.14159265358979323846264338327950288_f32;
 
@@ -167,9 +163,8 @@ pure fn logarithm(n: f32, b: f32) -> f32 {
 
 #[cfg(target_os="freebsd")]
 pure fn logarithm(n: f32, b: f32) -> f32 {
-    // FIXME check if it is good to use log2 instead of ln here;
+    // FIXME (#2000): check if it is good to use log2 instead of ln here;
     // in theory should be faster since the radix is 2
-    // See Issue #2000
     ret ln(n) / ln(b);
 }
 
diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs
index af83a0829e1..066b1b818c7 100644
--- a/src/libcore/f64.rs
+++ b/src/libcore/f64.rs
@@ -29,8 +29,7 @@ export num;
 
 // PORT check per architecture
 
-// FIXME obtain these in a different way
-// (perhaps related to Issue #1433)
+// FIXME (#1433): obtain these in a different way
 
 const radix: uint = 2u;
 
@@ -127,14 +126,13 @@ pure fn is_finite(x: f64) -> bool {
     ret !(is_NaN(x) || is_infinite(x));
 }
 
-// FIXME add is_normal, is_subnormal, and fpclassify
-// also see Issue #1999
+// FIXME (#1999): add is_normal, is_subnormal, and fpclassify
 
 /* Module: consts */
 mod consts {
 
-    // FIXME replace with mathematical constants from cmath
-    // (requires Issue #1433 to fix)
+    // FIXME (requires Issue #1433 to fix): replace with mathematical
+    // constants from cmath.
     #[doc = "Archimedes' constant"]
     const pi: f64 = 3.14159265358979323846264338327950288_f64;
 
@@ -188,9 +186,8 @@ pure fn logarithm(n: f64, b: f64) -> f64 {
 
 #[cfg(target_os="freebsd")]
 pure fn logarithm(n: f64, b: f64) -> f64 {
-    // FIXME check if it is good to use log2 instead of ln here;
-    // in theory should be faster since the radix is 2
-    // See Issue #2000
+    // FIXME (#2000): check if it is good to use log2 instead of ln here; in
+    // theory should be faster since the radix is 2
     ret ln(n) / ln(b);
 }
 
diff --git a/src/libcore/float.rs b/src/libcore/float.rs
index f50719408d0..9c995100273 100644
--- a/src/libcore/float.rs
+++ b/src/libcore/float.rs
@@ -38,8 +38,8 @@ const neg_infinity: float = -1.0/0.0;
 /* Module: consts */
 mod consts {
 
-    // FIXME replace with mathematical constants from cmath
-    // (requires Issue #1433 to fix)
+    // FIXME (requires Issue #1433 to fix): replace with mathematical
+    // constants from cmath.
     #[doc = "Archimedes' constant"]
     const pi: float = 3.14159265358979323846264338327950288;
 
diff --git a/src/libcore/io.rs b/src/libcore/io.rs
index 077a178546e..635b3f9ebf4 100644
--- a/src/libcore/io.rs
+++ b/src/libcore/io.rs
@@ -22,14 +22,14 @@ native mod rustrt {
 
 // Reading
 
-// FIXME This is all buffered. We might need an unbuffered variant as well
-// #2004
+// FIXME (#2004): This is all buffered. We might need an unbuffered variant
+// as well
 enum seek_style { seek_set, seek_end, seek_cur, }
 
 
 // The raw underlying reader iface. All readers must implement this.
 iface reader {
-    // FIXME: Seekable really should be orthogonal. // #2004
+    // FIXME (#2004): Seekable really should be orthogonal.
     fn read_bytes(uint) -> [u8];
     fn read_byte() -> int;
     fn unread_byte(int);
@@ -82,8 +82,8 @@ impl reader_util for reader {
         while nbread > 0u {
             let data = self.read_bytes(nbread);
             if vec::len(data) == 0u {
-                // eof - FIXME should we do something if
-                // we're split in a unicode char? // #2004
+                // eof - FIXME (#2004): should we do something if
+                // we're split in a unicode char?
                 break;
             }
             buf += data;
@@ -234,9 +234,9 @@ fn FILE_reader(f: *libc::FILE, cleanup: bool) -> reader {
     }
 }
 
-// FIXME: this should either be an iface-less impl, a set of top-level
-// functions that take a reader, or a set of default methods on reader
-// (which can then be called reader) // #2004
+// FIXME (#2004): this should either be an iface-less impl, a set of
+// top-level functions that take a reader, or a set of default methods on
+// reader (which can then be called reader)
 
 fn stdin() -> reader { rustrt::rust_get_stdin() as reader }
 
@@ -312,9 +312,8 @@ fn with_str_reader<T>(s: str, f: fn(reader) -> T) -> T {
 // Writing
 enum fileflag { append, create, truncate, no_flag, }
 
-// FIXME: Seekable really should be orthogonal.
-// FIXME: eventually u64
-// #2004
+// FIXME (#2004): Seekable really should be orthogonal.
+// FIXME (#2004): eventually u64
 iface writer {
     fn write([const u8]/&);
     fn seek(int, seek_style);
@@ -586,9 +585,9 @@ fn buffered_file_writer(path: str) -> result<writer, str> {
     else { result::ok(FILE_writer(f, true)) }
 }
 
-// FIXME it would be great if this could be a const
-// FIXME why are these different from the way stdin() is implemented?
-// #2004
+// FIXME (#2004) it would be great if this could be a const
+// FIXME (#2004) why are these different from the way stdin() is
+// implemented?
 fn stdout() -> writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
 fn stderr() -> writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
 
@@ -670,8 +669,8 @@ fn read_whole_file_str(file: str) -> result<str, str> {
     })
 }
 
-// FIXME implement this in a low-level way. Going through the abstractions is
-// pointless. // #2004
+// FIXME (#2004): implement this in a low-level way. Going through the
+// abstractions is pointless.
 fn read_whole_file(file: str) -> result<[u8], str> {
     result::chain(file_reader(file), { |rdr|
         result::ok(rdr.read_whole_stream())
@@ -714,8 +713,8 @@ mod fsync {
     };
 
     // fsync file after executing blk
-    // FIXME find better way to create resources within lifetime of outer res
-    // #2004
+    // FIXME (#2004) find better way to create resources within lifetime of
+    // outer res
     fn FILE_res_sync(&&file: FILE_res, opt_level: option<level>,
                   blk: fn(&&res<*libc::FILE>)) {
         blk(res({
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index cf903c3bebe..070e909c626 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -97,8 +97,8 @@ fn min<A:copy,IA:base_iter<A>>(self: IA) -> A {
     alt foldl::<A,option<A>,IA>(self, none) {|a, b|
         alt a {
           some(a_) if a_ < b {
-            // FIXME: Not sure if this is successfully optimized to a move
-            // #2005
+            // FIXME (#2005): Not sure if this is successfully optimized to
+            // a move
             a
           }
           _ { some(b) }
@@ -113,8 +113,8 @@ fn max<A:copy,IA:base_iter<A>>(self: IA) -> A {
     alt foldl::<A,option<A>,IA>(self, none) {|a, b|
         alt a {
           some(a_) if a_ > b {
-            // FIXME: Not sure if this is successfully optimized to a move
-            // #2005
+            // FIXME (#2005): Not sure if this is successfully optimized to
+            // a move.
             a
           }
           _ { some(b) }
diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs
index b6861b42eb7..c2679c6956e 100644
--- a/src/libcore/libc.rs
+++ b/src/libcore/libc.rs
@@ -37,8 +37,7 @@ dissolved.
 // Initial glob-exports mean that all the contents of all the modules
 // wind up exported, if you're interested in writing platform-specific code.
 
-// FIXME: change these to glob-exports when sufficiently supported.
-// Issue #2006
+// FIXME (#2006): change these to glob-exports when sufficiently supported.
 
 import types::common::c95::*;
 import types::common::c99::*;
@@ -79,10 +78,9 @@ import funcs::posix08::unistd::*;
 import funcs::bsd44::*;
 import funcs::extra::*;
 
-// FIXME: remove these 3 exports (and their uses next door in os::) when
-// export globs work. They provide access (for now) for os:: to dig around in
-// the rest of the platform-specific definitions.
-// Issue #2006
+// FIXME (#2006): remove these 3 exports (and their uses next door in os::)
+// when export globs work. They provide access (for now) for os:: to dig
+// around in the rest of the platform-specific definitions.
 
 export types, funcs, consts;
 
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 34c38321f47..9ee7a80fcda 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -166,8 +166,8 @@ mod global_env {
             task::set_opts(builder, {
                 sched:  some({
                     mode: task::single_threaded,
-                    // FIXME: This would be a good place to use
-                    // a very small native stack (#2621)
+                    // FIXME (#2621): This would be a good place to use a
+                    // very small native stack
                     native_stack_size: none
                 })
                 with task::get_opts(builder)
@@ -499,8 +499,8 @@ fn path_exists(p: path) -> bool {
     }
 }
 
-// FIXME: under Windows, we should prepend the current drive letter to paths
-// that start with a slash. #2622
+// FIXME (#2622): under Windows, we should prepend the current drive letter
+// to paths that start with a slash.
 #[doc = "
 Convert a relative path to an absolute path
 
@@ -696,8 +696,8 @@ fn remove_file(p: path) -> bool {
 
     #[cfg(windows)]
     fn unlink(p: path) -> bool {
-        // FIXME: remove imports when export globs work properly.
-        // (similar to Issue #2006)
+        // FIXME (similar to Issue #2006): remove imports when export globs
+        // work properly.
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
diff --git a/src/libcore/run.rs b/src/libcore/run.rs
index d8905730dc2..401454c40df 100644
--- a/src/libcore/run.rs
+++ b/src/libcore/run.rs
@@ -286,8 +286,8 @@ fn program_output(prog: str, args: [str]) ->
 
     // Spawn two entire schedulers to read both stdout and sterr
     // in parallel so we don't deadlock while blocking on one
-    // or the other. FIXME: Surely there's a much more clever way
-    // to do this. (#2625)
+    // or the other. FIXME (#2625): Surely there's a much more
+    // clever way to do this.
     let p = comm::port();
     let ch = comm::chan(p);
     task::spawn_sched(task::single_threaded) {||
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index 078243dfaee..dbdd798033c 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -593,8 +593,8 @@ Section: Comparing strings
 
 #[doc = "Bytewise string equality"]
 pure fn eq(&&a: str, &&b: str) -> bool {
-    // FIXME: This should just be "a == b" but that calls into the shape code
-    // :( (#2627)
+    // FIXME (#2627): This should just be "a == b" but that calls into the
+    // shape code.
     let a_len = a.len();
     let b_len = b.len();
     if a_len != b_len { ret false; }
diff --git a/src/libcore/task.rs b/src/libcore/task.rs
index 5f31b5090f0..ab9b4f7d3d7 100644
--- a/src/libcore/task.rs
+++ b/src/libcore/task.rs
@@ -64,8 +64,8 @@ Indicates the manner in which a task exited.
 A task that completes without failing and whose supervised children complete
 without failing is considered to exit successfully.
 
-FIXME: This description does not indicate the current behavior for linked
-failure. (See #1868)
+FIXME (See #1868): This description does not indicate the current behavior
+for linked failure.
 "]
 enum task_result {
     success,
@@ -275,7 +275,7 @@ fn future_result(builder: builder) -> future::future<task_result> {
     task.
     "];
 
-    // FIXME (1087, 1857): Once linked failure and notification are
+    // FIXME (#1087, #1857): Once linked failure and notification are
     // handled in the library, I can imagine implementing this by just
     // registering an arbitrary number of task::on_exit handlers and
     // sending out messages.
@@ -506,10 +506,10 @@ fn spawn_raw(opts: task_opts, +f: fn~()) unsafe {
     let mut f = if opts.supervise {
         f
     } else {
-        // FIXME: The runtime supervision API is weird here because it
-        // was designed to let the child unsupervise itself, when what
-        // we actually want is for parents to unsupervise new
-        // children. (#1868, #1789)
+        // FIXME (#1868, #1789): The runtime supervision API is weird here
+        // because it was designed to let the child unsupervise itself,
+        // when what we actually want is for parents to unsupervise new
+        // children.
         fn~() {
             rustrt::unsupervise();
             f();
@@ -529,7 +529,7 @@ fn spawn_raw(opts: task_opts, +f: fn~()) unsafe {
     };
 
     option::iter(opts.notify_chan) {|c|
-        // FIXME (1087): Would like to do notification in Rust
+        // FIXME (#1087): Would like to do notification in Rust
         rustrt::rust_task_config_notify(new_task, c);
     }
 
diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs
index f58a85c3618..be491433cd0 100644
--- a/src/libcore/uint-template.rs
+++ b/src/libcore/uint-template.rs
@@ -173,10 +173,9 @@ fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
          0u8,0u8,0u8,0u8,0u8
          ]/65;
 
-    // FIXME: post-snapshot, you can do this without
-    // the raw pointers and unsafe bits, and the
-    // codegen will prove it's all in-bounds, no
-    // extra cost.
+    // FIXME (#2649): post-snapshot, you can do this without the raw
+    // pointers and unsafe bits, and the codegen will prove it's all
+    // in-bounds, no extra cost.
 
     vec::unpack_slice(buf) {|p, len|
         let mp = p as *mut u8;
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index a80acc67e42..494470e32e4 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -385,7 +385,7 @@ fn shift<T>(&v: [T]) -> T {
             let mut r <- *vv;
 
             for uint::range(1u, ln) {|i|
-                // FIXME: this isn't legal, per se...
+                // FIXME (#2703): this isn't legal, per se...
                 let r <- *ptr::offset(vv, i);
                 push(v, r);
             }
diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs
index 1be4d12d23e..254ed4d4ede 100644
--- a/src/libstd/bitv.rs
+++ b/src/libstd/bitv.rs
@@ -16,11 +16,10 @@ export to_vec;
 export to_str;
 export eq_vec;
 
-// FIXME: With recursive object types, we could implement binary methods like
-//        union, intersection, and difference. At that point, we could write
-//        an optimizing version of this module that produces a different obj
-//        for the case where nbits <= 32.
-// (Issue #2341)
+// FIXME (#2341): With recursive object types, we could implement binary
+// methods like union, intersection, and difference. At that point, we could
+// write an optimizing version of this module that produces a different obj
+// for the case where nbits <= 32.
 
 #[doc = "The bitvector type"]
 type bitv = @{storage: [mut uint], nbits: uint};
diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs
index eafd2776d19..f57d2a21af6 100644
--- a/src/libstd/deque.rs
+++ b/src/libstd/deque.rs
@@ -14,8 +14,8 @@ iface t<T> {
     fn get(int) -> T;
 }
 
-// FIXME eventually, a proper datatype plus an exported impl would be
-// preferrable (#2343)
+// FIXME (#2343) eventually, a proper datatype plus an exported impl would
+// be preferrable.
 fn create<T: copy>() -> t<T> {
     type cell<T> = option<T>;
 
diff --git a/src/libstd/map.rs b/src/libstd/map.rs
index bfa1fb4a7b6..c988b167fd0 100644
--- a/src/libstd/map.rs
+++ b/src/libstd/map.rs
@@ -67,8 +67,8 @@ iface map<K, V: copy> {
     fn each_value(fn(V) -> bool);
 }
 
-// FIXME: package this up and export it as a datatype usable for
-// external code that doesn't want to pay the cost of a box. (#2344)
+// FIXME (#2344): package this up and export it as a datatype usable for
+// external code that doesn't want to pay the cost of a box.
 mod chained {
     export t, mk, hashmap;
 
diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs
index 024a4367eb8..64cded848d1 100644
--- a/src/libstd/net_ip.rs
+++ b/src/libstd/net_ip.rs
@@ -36,7 +36,7 @@ fn format_addr(ip: ip_addr) -> str {
         #fmt["%u.%u.%u.%u", a as uint, b as uint, c as uint, d as uint]
       }
       ipv6(_, _, _, _, _, _, _, _) {
-        fail "FIXME impl parsing of ipv6 addr";
+        fail "FIXME (#2651) impl parsing of ipv6 addr";
       }
     }
 }
diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs
index 0b06dd67f76..a2d36ac354b 100644
--- a/src/libstd/net_tcp.rs
+++ b/src/libstd/net_tcp.rs
@@ -2,15 +2,12 @@
 High-level interface to libuv's TCP functionality
 "];
 
-// FIXME: Fewer import *'s
 import ip = net_ip;
 import uv::iotask;
 import uv::iotask::iotask;
-import comm::*;
-import result::*;
-import str::*;
-import future::*;
-import libc::size_t;
+import comm::methods;
+import future::future;
+import result::{result,err,ok,extensions};
 
 // data
 export tcp_socket, tcp_conn_port, tcp_err_data;
@@ -364,8 +361,8 @@ fn new_listener(host_ip: ip::ip_addr, port: uint, backlog: uint,
     let new_conn_po = comm::port::<result::result<*uv::ll::uv_tcp_t,
                                                   tcp_err_data>>();
     let new_conn_ch = comm::chan(new_conn_po);
-    // FIXME: This shared box should not be captured in the i/o task
-    // Make it a unique pointer.
+    // FIXME (#2656): This shared box should not be captured in the i/o
+    // task Make it a unique pointer.
     let server_data: @tcp_conn_port_data = @{
         server_stream: uv::ll::tcp_t(),
         stream_closed_po: stream_closed_po,
@@ -946,10 +943,10 @@ fn write_common_impl(socket_data_ptr: *tcp_socket_data,
           }
         }
     };
-    // FIXME: Instead of passing unsafe pointers to local data, and waiting
-    // here for the write to complete, we should transfer ownership of
-    // everything to the I/O task and let it deal with the aftermath,
-    // so we don't have to sit here blocking.
+    // FIXME (#2656): Instead of passing unsafe pointers to local data,
+    // and waiting here for the write to complete, we should transfer
+    // ownership of everything to the I/O task and let it deal with the
+    // aftermath, so we don't have to sit here blocking.
     alt comm::recv(result_po) {
       tcp_write_success { result::ok(()) }
       tcp_write_error(err_data) { result::err(err_data.to_tcp_err()) }
@@ -1191,20 +1188,16 @@ crust fn tcp_write_complete_cb(write_req: *uv::ll::uv_write_t,
                               status: libc::c_int) unsafe {
     let write_data_ptr = uv::ll::get_data_for_req(write_req)
         as *write_req_data;
-    // FIXME: if instead of alt
-    alt status {
-      0i32 {
+    if status == 0i32 {
         log(debug, "successful write complete");
         comm::send((*write_data_ptr).result_ch, tcp_write_success);
-      }
-      _ {
+    } else {
         let stream_handle_ptr = uv::ll::get_stream_handle_from_write_req(
             write_req);
         let loop_ptr = uv::ll::get_loop_for_uv_handle(stream_handle_ptr);
         let err_data = uv::ll::get_last_err_data(loop_ptr);
         log(debug, "failure to write");
         comm::send((*write_data_ptr).result_ch, tcp_write_error(err_data));
-      }
     }
 }
 
@@ -1273,20 +1266,20 @@ type tcp_socket_data = {
 // convert rust ip_addr to libuv's native representation
 fn ipv4_ip_addr_to_sockaddr_in(input_ip: ip::ip_addr,
                                port: uint) -> uv::ll::sockaddr_in unsafe {
-    // FIXME ipv6
+    // FIXME (#2656): ipv6
     alt input_ip {
       ip::ipv4(_,_,_,_) {
         uv::ll::ip4_addr(ip::format_addr(input_ip), port as int)
       }
       ip::ipv6(_,_,_,_,_,_,_,_) {
-        fail "FIXME ipv6 not yet supported";
+        fail "FIXME (#2656) ipv6 not yet supported";
       }
     }
 }
 
 #[cfg(test)]
 mod test {
-    // FIXME don't run on fbsd or linux 32 bit(#2064)
+    // FIXME don't run on fbsd or linux 32 bit (#2064)
     #[cfg(target_os="win32")]
     #[cfg(target_os="darwin")]
     #[cfg(target_os="linux")]
diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs
index 3a3b90d2513..89e9d0338fe 100644
--- a/src/libstd/smallintmap.rs
+++ b/src/libstd/smallintmap.rs
@@ -6,8 +6,8 @@ import core::option;
 import core::option::{some, none};
 import dvec::{dvec, extensions};
 
-// FIXME: Should not be @; there's a bug somewhere in rustc that requires this
-// to be. (#2347)
+// FIXME (#2347): Should not be @; there's a bug somewhere in rustc that
+// requires this to be.
 type smallintmap<T: copy> = @{v: dvec<option<T>>};
 
 #[doc = "Create a smallintmap"]
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index 2c7902c63e9..d06749b5757 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -319,15 +319,14 @@ fn strptime(s: str, format: str) -> result<tm, str> {
                 .chain { |pos| parse_type(s, pos, 'd', tm) }
           }
           'H' {
-            // FIXME: range check. (#2350 -- same issue for all FIXMEs in this
-            // file.)
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) { let (v, pos) = item; tm.tm_hour = v; ok(pos) }
               none { err("Invalid hour") }
             }
           }
           'I' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) {
                   let (v, pos) = item;
@@ -338,7 +337,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
             }
           }
           'j' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 3u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -349,14 +348,14 @@ fn strptime(s: str, format: str) -> result<tm, str> {
             }
           }
           'k' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, true) {
               some(item) { let (v, pos) = item; tm.tm_hour = v; ok(pos) }
               none { err("Invalid hour") }
             }
           }
           'l' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, true) {
               some(item) {
                   let (v, pos) = item;
@@ -367,14 +366,14 @@ fn strptime(s: str, format: str) -> result<tm, str> {
             }
           }
           'M' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) { let (v, pos) = item; tm.tm_min = v; ok(pos) }
               none { err("Invalid minute") }
             }
           }
           'm' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -412,7 +411,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
                 .chain { |pos| parse_type(s, pos, 'p', tm) }
           }
           'S' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -432,7 +431,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
           }
           't' { parse_char(s, pos, '\t') }
           'u' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 1u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -451,7 +450,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
           }
           //'W' {}
           'w' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 1u, false) {
               some(item) { let (v, pos) = item; tm.tm_wday = v; ok(pos) }
               none { err("Invalid weekday") }
@@ -460,7 +459,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
           //'X' {}
           //'x' {}
           'Y' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 4u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -471,7 +470,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
             }
           }
           'y' {
-            // FIXME: range check.
+            // FIXME (#2350): range check.
             alt match_digits(s, pos, 2u, false) {
               some(item) {
                 let (v, pos) = item;
@@ -584,7 +583,7 @@ fn strptime(s: str, format: str) -> result<tm, str> {
 
 fn strftime(format: str, tm: tm) -> str {
     fn parse_type(ch: char, tm: tm) -> str {
-        //FIXME: Implement missing types.
+        //FIXME (#2350): Implement missing types.
         alt check ch {
           'A' {
             alt check tm.tm_wday as int {
@@ -915,7 +914,7 @@ mod tests {
         assert local.tm_isdst == 0_i32;
         assert local.tm_gmtoff == -28800_i32;
 
-        // FIXME: We should probably standardize on the timezone
+        // FIXME (#2350): We should probably standardize on the timezone
         // abbreviation.
         let zone = local.tm_zone;
         assert zone == "PST" || zone == "Pacific Standard Time";
@@ -1063,8 +1062,8 @@ mod tests {
         assert test("2009-02-13", "%F");
         assert test("03", "%H");
         assert test("13", "%H");
-        assert test("03", "%I"); // FIXME: flesh out
-        assert test("11", "%I"); // FIXME: flesh out
+        assert test("03", "%I"); // FIXME (#2350): flesh out
+        assert test("11", "%I"); // FIXME (#2350): flesh out
         assert test("044", "%j");
         assert test(" 3", "%k");
         assert test("13", "%k");
@@ -1162,7 +1161,7 @@ mod tests {
         assert local.strftime("%Y") == "2009";
         assert local.strftime("%y") == "09";
 
-        // FIXME: We should probably standardize on the timezone
+        // FIXME (#2350): We should probably standardize on the timezone
         // abbreviation.
         let zone = local.strftime("%Z");
         assert zone == "PST" || zone == "Pacific Standard Time";
@@ -1170,7 +1169,7 @@ mod tests {
         assert local.strftime("%z") == "-0800";
         assert local.strftime("%%") == "%";
 
-        // FIXME: We should probably standardize on the timezone
+        // FIXME (#2350): We should probably standardize on the timezone
         // abbreviation.
         let rfc822 = local.rfc822();
         let prefix = "Fri, 13 Feb 2009 15:31:30 ";
diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs
index e882eba5d6b..b7e1ee7d82c 100644
--- a/src/libstd/uv_ll.rs
+++ b/src/libstd/uv_ll.rs
@@ -505,7 +505,7 @@ native mod rustrt {
                            tcp_handle_ptr: *uv_tcp_t,
                            ++after_cb: *u8,
                            ++addr: *sockaddr_in) -> libc::c_int;
-    // FIXME ref 2064
+    // FIXME ref #2064
     fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t,
                         ++addr: *sockaddr_in) -> libc::c_int;
     fn rust_uv_listen(stream: *libc::c_void, backlog: libc::c_int,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 98cf35efdc8..9d3dcb0f23e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -176,9 +176,7 @@ enum proto {
 
 #[auto_serialize]
 enum vstore {
-    /* FIXME: Change uint to @expr (actually only constant exprs,
-       as per #2112)
-     */
+    // FIXME (#2112): Change uint to @expr (actually only constant exprs)
     vstore_fixed(option<uint>),   // [1,2,3,4]/_ or 4
     vstore_uniq,                  // [1,2,3,4]/~
     vstore_box,                   // [1,2,3,4]/@
@@ -256,12 +254,11 @@ enum init_op { init_assign, init_move, }
 #[auto_serialize]
 type initializer = {op: init_op, expr: @expr};
 
+// FIXME (pending discussion of #1697, #2178...): local should really be
+// a refinement on pat.
 #[auto_serialize]
-type local_ =  /* FIXME: should really be a refinement on pat
-                  (pending discussion of #1697, #2178...)
-                */
-    {is_mutbl: bool, ty: @ty, pat: @pat,
-     init: option<initializer>, id: node_id};
+type local_ =  {is_mutbl: bool, ty: @ty, pat: @pat,
+                init: option<initializer>, id: node_id};
 
 #[auto_serialize]
 type local = spanned<local_>;
@@ -322,9 +319,8 @@ enum expr_ {
     expr_block(blk),
 
     /*
-     * FIXME: many of these @exprs should be constrained with
+     * FIXME (#34): many of these @exprs should be constrained with
      * is_lval once we have constrained types working.
-     * (See #34)
      */
     expr_copy(@expr),
     expr_move(@expr, @expr),
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index e11e673494c..9355da5779e 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -13,8 +13,8 @@ type path = [path_elt];
 fn path_to_str_with_sep(p: path, sep: str) -> str {
     let strs = vec::map(p) {|e|
         alt e {
-          path_mod(s) { /* FIXME: bad */ copy *s }
-          path_name(s) { /* FIXME: bad */ copy *s }
+          path_mod(s) { /* FIXME (#2543) */ copy *s }
+          path_name(s) { /* FIXME (#2543) */ copy *s }
         }
     };
     str::connect(strs, sep)
@@ -22,7 +22,7 @@ fn path_to_str_with_sep(p: path, sep: str) -> str {
 
 fn path_ident_to_str(p: path, i: ident) -> str {
     if vec::is_empty(p) {
-        /* FIXME: bad */ copy *i
+        /* FIXME (#2543) */ copy *i
     } else {
         #fmt["%s::%s", path_to_str(p), *i]
     }
@@ -98,7 +98,7 @@ fn map_decoded_item(diag: span_handler,
     // even if we did I think it only needs an ordering between local
     // variables that are simultaneously in scope).
     let cx = {map: map,
-              mut path: /* FIXME: bad */ copy path,
+              mut path: /* FIXME (#2543) */ copy path,
               mut local_id: 0u,
               diag: diag};
     let v = mk_ast_map_visitor();
@@ -124,27 +124,29 @@ fn map_decoded_item(diag: span_handler,
 fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
           sp: codemap::span, id: node_id, cx: ctx, v: vt) {
     for decl.inputs.each {|a|
-        cx.map.insert(a.id, node_arg(/* FIXME: bad */ copy a, cx.local_id));
+        cx.map.insert(a.id,
+                      node_arg(/* FIXME (#2543) */
+                          copy a, cx.local_id));
         cx.local_id += 1u;
     }
     alt fk {
       visit::fk_ctor(nm, tps, self_id, parent_id) {
           let ct = @{node: {id: id,
                             self_id: self_id,
-                            dec: /* FIXME: bad */ copy decl,
-                            body: /* FIXME: bad */ copy body},
+                            dec: /* FIXME (#2543) */ copy decl,
+                            body: /* FIXME (#2543) */ copy body},
                     span: sp};
-          cx.map.insert(id, node_ctor(/* FIXME: bad */ copy nm,
-                                      /* FIXME: bad */ copy tps,
+          cx.map.insert(id, node_ctor(/* FIXME (#2543) */ copy nm,
+                                      /* FIXME (#2543) */ copy tps,
                                       class_ctor(ct, parent_id),
-                                      @/* FIXME: bad */ copy cx.path));
+                                      @/* FIXME (#2543) */ copy cx.path));
        }
       visit::fk_dtor(tps, self_id, parent_id) {
           let dt = @{node: {id: id, self_id: self_id,
-                     body: /* FIXME: bad */ copy body}, span: sp};
-          cx.map.insert(id, node_dtor(/* FIXME: bad */ copy tps, dt,
+                     body: /* FIXME (#2543) */ copy body}, span: sp};
+          cx.map.insert(id, node_dtor(/* FIXME (#2543) */ copy tps, dt,
                                       parent_id,
-                                      @/* FIXME: bad */ copy cx.path));
+                                      @/* FIXME (#2543) */ copy cx.path));
        }
 
        _ {}
@@ -153,7 +155,7 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
 }
 
 fn map_block(b: blk, cx: ctx, v: vt) {
-    cx.map.insert(b.node.id, node_block(/* FIXME: bad */ copy b));
+    cx.map.insert(b.node.id, node_block(/* FIXME (#2543) */ copy b));
     visit::visit_block(b, cx, v);
 }
 
@@ -187,7 +189,7 @@ fn map_method(impl_did: def_id, impl_path: @path,
 }
 
 fn map_item(i: @item, cx: ctx, v: vt) {
-    let item_path = @/* FIXME: bad */ copy cx.path;
+    let item_path = @/* FIXME (#2543) */ copy cx.path;
     cx.map.insert(i.id, node_item(i, item_path));
     alt i.node {
       item_impl(_, _, _, _, ms) {
@@ -198,9 +200,10 @@ fn map_item(i: @item, cx: ctx, v: vt) {
         }
       }
       item_res(decl, tps, _, dtor_id, ctor_id, _) {
-        cx.map.insert(ctor_id, node_ctor(/* FIXME: bad */ copy i.ident,
-                                         /* FIXME: bad */ copy tps,
-                                         res_ctor(/* FIXME: bad */ copy decl,
+        cx.map.insert(ctor_id, node_ctor(/* FIXME (#2543) */ copy i.ident,
+                                         /* FIXME (#2543) */ copy tps,
+                                         res_ctor(/* FIXME (#2543) */
+                                                  copy decl,
                                                   ctor_id, i.span),
                                          item_path));
         cx.map.insert(dtor_id, node_item(i, item_path));
@@ -208,7 +211,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
       item_enum(vs, _, _) {
         for vs.each {|v|
             cx.map.insert(v.node.id, node_variant(
-                /* FIXME: bad */ copy v, i,
+                /* FIXME (#2543) */ copy v, i,
                 extend(cx, i.ident)));
         }
       }
@@ -220,7 +223,8 @@ fn map_item(i: @item, cx: ctx, v: vt) {
         for nm.items.each {|nitem|
             cx.map.insert(nitem.id,
                           node_native_item(nitem, abi,
-                                           @/* FIXME: bad */ copy cx.path));
+                                           /* FIXME (#2543) */
+                                           @copy cx.path));
         }
       }
       item_class(tps, ifces, items, ctor, dtor, _) {
@@ -251,7 +255,9 @@ fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
       view_item_export(vps) {
         for vps.each {|vp|
             let (id, name) = alt vp.node {
-              view_path_simple(nm, _, id) { (id, /* FIXME: bad */ copy nm) }
+              view_path_simple(nm, _, id) {
+                (id, /* FIXME (#2543) */ copy nm)
+              }
               view_path_glob(pth, id) | view_path_list(pth, _, id) {
                 (id, path_to_ident(pth))
               }
@@ -294,19 +300,19 @@ fn node_id_to_str(map: map, id: node_id) -> str {
       }
       // FIXMEs are as per #2410
       some(node_export(_, path)) {
-        #fmt["export %s (id=%?)", // FIXME: add more info here
+        #fmt["export %s (id=%?)", // add more info here
              path_to_str(*path), id]
       }
-      some(node_arg(_, _)) { // FIXME: add more info here
+      some(node_arg(_, _)) { // add more info here
         #fmt["arg (id=%?)", id]
       }
-      some(node_local(_)) { // FIXME: add more info here
+      some(node_local(_)) { // add more info here
         #fmt["local (id=%?)", id]
       }
-      some(node_ctor(*)) { // FIXME: add more info here
+      some(node_ctor(*)) { // add more info here
         #fmt["node_ctor (id=%?)", id]
       }
-      some(node_dtor(*)) { // FIXME: add more info here
+      some(node_dtor(*)) { // add more info here
         #fmt["node_dtor (id=%?)", id]
       }
       some(node_block(_)) {
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index e56bb25e55d..8ce34a06329 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -159,7 +159,7 @@ fn is_exported(i: ident, m: _mod) -> bool {
             for variants.each {|v|
                 if v.node.name == i {
                    local = true;
-                   parent_enum = some(/* FIXME: bad */ copy it.ident);
+                   parent_enum = some(/* FIXME (#2543) */ copy it.ident);
                 }
             }
           }
@@ -268,7 +268,7 @@ pure fn is_unguarded(&&a: arm) -> bool {
 }
 
 pure fn unguarded_pat(a: arm) -> option<[@pat]> {
-    if is_unguarded(a) { some(/* FIXME: bad */ copy a.pats) } else { none }
+    if is_unguarded(a) { some(/* FIXME (#2543) */ copy a.pats) } else { none }
 }
 
 // Provides an extra node_id to hang callee information on, in case the
@@ -278,8 +278,8 @@ fn op_expr_callee_id(e: @expr) -> node_id { e.id - 1 }
 
 pure fn class_item_ident(ci: @class_member) -> ident {
     alt ci.node {
-      instance_var(i,_,_,_,_) { /* FIXME: bad */ copy i }
-      class_method(it) { /* FIXME: bad */ copy it.ident }
+      instance_var(i,_,_,_,_) { /* FIXME (#2543) */ copy i }
+      class_method(it) { /* FIXME (#2543) */ copy it.ident }
     }
 }
 
@@ -297,7 +297,7 @@ fn split_class_items(cs: [@class_member]) -> ([ivar], [@method]) {
     for cs.each {|c|
       alt c.node {
         instance_var(i, t, cm, id, vis) {
-          vs += [{ident: /* FIXME: bad */ copy i,
+          vs += [{ident: /* FIXME (#2543) */ copy i,
                   ty: t,
                   cm: cm,
                   id: id,
@@ -319,11 +319,11 @@ pure fn class_member_visibility(ci: @class_member) -> visibility {
 impl inlined_item_methods for inlined_item {
     fn ident() -> ident {
         alt self {
-          ii_item(i) { /* FIXME: bad */ copy i.ident }
-          ii_native(i) { /* FIXME: bad */ copy i.ident }
-          ii_method(_, m) { /* FIXME: bad */ copy m.ident }
-          ii_ctor(_, nm, _, _) { /* FIXME: bad */ copy nm }
-          ii_dtor(_, nm, _, _) { /* FIXME: bad */ copy nm }
+          ii_item(i) { /* FIXME (#2543) */ copy i.ident }
+          ii_native(i) { /* FIXME (#2543) */ copy i.ident }
+          ii_method(_, m) { /* FIXME (#2543) */ copy m.ident }
+          ii_ctor(_, nm, _, _) { /* FIXME (#2543) */ copy nm }
+          ii_dtor(_, nm, _, _) { /* FIXME (#2543) */ copy nm }
         }
     }
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 5dfe40b7ee0..fb9560065a8 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -91,9 +91,9 @@ fn get_attr_name(attr: ast::attribute) -> ast::ident {
 // All "bad" FIXME copies are as per #2543
 fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident {
     alt meta.node {
-      ast::meta_word(n) { /* FIXME bad */ copy n }
-      ast::meta_name_value(n, _) { /* FIXME bad */ copy n }
-      ast::meta_list(n, _) { /* FIXME bad */ copy n }
+      ast::meta_word(n) { /* FIXME (#2543) */ copy n }
+      ast::meta_name_value(n, _) { /* FIXME (#2543) */ copy n }
+      ast::meta_list(n, _) { /* FIXME (#2543) */ copy n }
     }
 }
 
@@ -120,7 +120,7 @@ fn get_meta_item_value_str(meta: @ast::meta_item) -> option<@str> {
 #[doc = "Gets a list of inner meta items from a list meta_item type"]
 fn get_meta_item_list(meta: @ast::meta_item) -> option<[@ast::meta_item]> {
     alt meta.node {
-      ast::meta_list(_, l) { option::some(/* FIXME bad */ copy l) }
+      ast::meta_list(_, l) { option::some(/* FIXME (#2543) */ copy l) }
       _ { option::none }
     }
 }
@@ -266,15 +266,15 @@ fn last_meta_item_list_by_name(
 
 /* Higher-level applications */
 
-// FIXME: This needs to sort by meta_item variant in addition to the item name
-// (See [Fixme-sorting])
+// FIXME (#607): This needs to sort by meta_item variant in addition to
+// the item name (See [Fixme-sorting])
 fn sort_meta_items(+items: [@ast::meta_item]) -> [@ast::meta_item] {
     fn lteq(&&ma: @ast::meta_item, &&mb: @ast::meta_item) -> bool {
         fn key(m: @ast::meta_item) -> ast::ident {
             alt m.node {
-              ast::meta_word(name) { /* FIXME bad */ copy name }
-              ast::meta_name_value(name, _) { /* FIXME bad */ copy name }
-              ast::meta_list(name, _) { /* FIXME bad */ copy name }
+              ast::meta_word(name) { /* FIXME (#2543) */ copy name }
+              ast::meta_name_value(name, _) { /* FIXME (#2543) */ copy name }
+              ast::meta_list(name, _) { /* FIXME (#2543) */ copy name }
             }
         }
         ret key(ma) <= key(mb);
@@ -292,7 +292,7 @@ fn remove_meta_items_by_name(items: [@ast::meta_item], name: ast::ident) ->
     ret vec::filter_map(items, {
         |item|
         if get_meta_item_name(item) != name {
-            option::some(/* FIXME bad */ copy item)
+            option::some(/* FIXME (#2543) */ copy item)
         } else {
             option::none
         }
@@ -317,7 +317,7 @@ linkage
 fn find_linkage_metas(attrs: [ast::attribute]) -> [@ast::meta_item] {
     find_linkage_attrs(attrs).flat_map {|attr|
         alt check attr.node.value.node {
-          ast::meta_list(_, items) { /* FIXME bad */ copy items }
+          ast::meta_list(_, items) { /* FIXME (#2543) */ copy items }
         }
     }
 }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 97911f9d8b8..49560fb5bbd 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -123,7 +123,7 @@ fn lookup_char_pos_adj(map: codemap, pos: uint)
     let loc = lookup_char_pos(map, pos);
     alt (loc.file.substr) {
       fss_none {
-        {filename: /* FIXME bad */ copy loc.file.name,
+        {filename: /* FIXME (#2543) */ copy loc.file.name,
          line: loc.line,
          col: loc.col,
          file: some(loc.file)}
@@ -132,7 +132,7 @@ fn lookup_char_pos_adj(map: codemap, pos: uint)
         lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
       }
       fss_external(eloc) {
-        {filename: /* FIXME bad */ copy eloc.filename,
+        {filename: /* FIXME (#2543) */ copy eloc.filename,
          line: eloc.line + loc.line - 1u,
          col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
          file: none}
@@ -178,7 +178,7 @@ type file_lines = {file: filemap, lines: [uint]};
 
 fn span_to_filename(sp: span, cm: codemap::codemap) -> filename {
     let lo = lookup_char_pos(cm, sp.lo);
-    ret /* FIXME bad */ copy lo.file.name;
+    ret /* FIXME (#2543) */ copy lo.file.name;
 }
 
 fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index b65c6524d12..b8ebb27f51b 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -201,7 +201,7 @@ fn highlight_lines(cm: codemap::codemap, sp: span,
     // arbitrarily only print up to six lines of the error
     let max_lines = 6u;
     let mut elided = false;
-    let mut display_lines = /* FIXME bad */ copy lines.lines;
+    let mut display_lines = /* FIXME (#2543) */ copy lines.lines;
     if vec::len(display_lines) > max_lines {
         display_lines = vec::slice(display_lines, 0u, max_lines);
         elided = true;
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index ebb56fa3b58..26a906f8cf0 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -11,8 +11,8 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
                      _body: ast::mac_body) -> @ast::expr {
     let args = get_mac_args(cx, sp, arg, 1u, option::some(1u), "env");
 
-    // FIXME: if this was more thorough it would manufacture an
-    // option<str> rather than just an maybe-empty string. (Issue #2248)
+    // FIXME (#2248): if this was more thorough it would manufacture an
+    // option<str> rather than just an maybe-empty string.
 
     let var = expr_to_str(cx, args[0], "#env requires a string");
     alt os::getenv(var) {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index ba44404fe24..26313e97494 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -109,10 +109,10 @@ fn new_span(cx: ext_ctxt, sp: span) -> span {
     ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
 }
 
-// FIXME: this is a terrible kludge to inject some macros into the default
-// compilation environment. When the macro-definition system is substantially
-// more mature, these should move from here, into a compiled part of libcore
-// at very least. (Issue #2247)
+// FIXME (#2247): this is a terrible kludge to inject some macros into
+// the default compilation environment. When the macro-definition system
+// is substantially more mature, these should move from here, into a
+// compiled part of libcore at very least.
 
 fn core_macros() -> str {
     ret
diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs
index 5ea8b677675..0cc4ba0a570 100644
--- a/src/libsyntax/ext/fmt.rs
+++ b/src/libsyntax/ext/fmt.rs
@@ -30,11 +30,10 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
     ret pieces_to_expr(cx, sp, pieces, args);
 }
 
-// FIXME: A lot of these functions for producing expressions can probably
-// be factored out in common with other code that builds expressions.
-// FIXME: Cleanup the naming of these functions
+// FIXME (#2249): A lot of these functions for producing expressions can
+// probably be factored out in common with other code that builds
+// expressions.  Also: Cleanup the naming of these functions.
 // NOTE: Moved many of the common ones to build.rs --kevina
-// See Issue #2249
 fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
    -> @ast::expr {
     fn make_path_vec(_cx: ext_ctxt, ident: ast::ident) -> [ast::ident] {
diff --git a/src/libsyntax/ext/qquote.rs b/src/libsyntax/ext/qquote.rs
index 9830c379ef6..3f3eb001250 100644
--- a/src/libsyntax/ext/qquote.rs
+++ b/src/libsyntax/ext/qquote.rs
@@ -104,8 +104,8 @@ fn gather_anti_quotes<N: qq_helper>(lo: uint, node: N) -> aq_ctxt
               with *default_visitor()};
     let cx = @{lo:lo, gather: dvec()};
     node.visit(cx, mk_vt(v));
-    // FIXME: Maybe this is an overkill (merge_sort), it might be better
-    //   to just keep the gather array in sorted order ... (Issue #2250)
+    // FIXME (#2250): Maybe this is an overkill (merge_sort), it might
+    // be better to just keep the gather array in sorted order.
     cx.gather.swap { |v|
         vec::to_mut(std::sort::merge_sort({|a,b| a.lo < b.lo}, v))
     };
diff --git a/src/libsyntax/ext/simplext.rs b/src/libsyntax/ext/simplext.rs
index bf3014d1621..4dad13dc06a 100644
--- a/src/libsyntax/ext/simplext.rs
+++ b/src/libsyntax/ext/simplext.rs
@@ -466,8 +466,7 @@ fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) {
               }
             }
           }
-          /* FIXME: handle embedded types and blocks, at least
-             (Issue #2251) */
+          /* FIXME (#2251): handle embedded types and blocks, at least */
           expr_mac(mac) {
             p_t_s_r_mac(cx, mac, s, b);
           }
@@ -722,8 +721,8 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
                         [@{params: pattern_to_selectors(cx, arg),
                            body: elts[1u]}];
 
-                    // FIXME: check duplicates (or just simplify
-                    // the macro arg situation) (Issue #2251)
+                    // FIXME (#2251): check duplicates (or just simplify
+                    // the macro arg situation)
                   }
                   _ {
                       cx.span_bug(mac.span, "undocumented invariant in \
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 0589e48489c..ff296eb5aad 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -88,11 +88,12 @@ fn fold_meta_item_(&&mi: @meta_item, fld: ast_fold) -> @meta_item {
                 meta_word(id) { meta_word(fld.fold_ident(id)) }
                 meta_list(id, mis) {
                   let fold_meta_item = {|x|fold_meta_item_(x, fld)};
-                  meta_list(/* FIXME: bad */ copy id,
+                  meta_list(/* FIXME: (#2543) */ copy id,
                             vec::map(mis, fold_meta_item))
                 }
                 meta_name_value(id, s) {
-                  meta_name_value(fld.fold_ident(id), /* FIXME: bad */ copy s)
+                  meta_name_value(fld.fold_ident(id),
+                                  /* FIXME (#2543) */ copy s)
                 }
               },
           span: fld.new_span(mi.span)};
@@ -123,8 +124,8 @@ fn fold_mac_(m: mac, fld: ast_fold) -> mac {
                mac_embed_type(ty) { mac_embed_type(fld.fold_ty(ty)) }
                mac_embed_block(blk) { mac_embed_block(fld.fold_block(blk)) }
                mac_ellipsis { mac_ellipsis }
-               mac_aq(_,_) { /* FIXME: bad */ copy m.node }
-               mac_var(_) { /* FIXME: bad */ copy m.node }
+               mac_aq(_,_) { /* FIXME (#2543) */ copy m.node }
+               mac_var(_) { /* FIXME (#2543) */ copy m.node }
              },
          span: fld.new_span(m.span)};
 }
@@ -145,7 +146,7 @@ fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound {
 }
 
 fn fold_ty_param(tp: ty_param, fld: ast_fold) -> ty_param {
-    {ident: /* FIXME: bad */ copy tp.ident,
+    {ident: /* FIXME (#2543) */ copy tp.ident,
      id: fld.new_id(tp.id),
      bounds: @vec::map(*tp.bounds, {|x|fold_ty_param_bound(x, fld)})}
 }
@@ -168,12 +169,12 @@ fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) ->
    crate_directive_ {
     ret alt cd {
           cdir_src_mod(id, attrs) {
-            cdir_src_mod(fld.fold_ident(id), /* FIXME: bad */ copy attrs)
+            cdir_src_mod(fld.fold_ident(id), /* FIXME (#2543) */ copy attrs)
           }
           cdir_dir_mod(id, cds, attrs) {
             cdir_dir_mod(fld.fold_ident(id),
                          vec::map(cds, fld.fold_crate_directive),
-                         /* FIXME: bad */ copy attrs)
+                         /* FIXME (#2543) */ copy attrs)
           }
           cdir_view_item(vi) { cdir_view_item(fld.fold_view_item(vi)) }
           cdir_syntax(_) { copy cd }
@@ -181,7 +182,7 @@ fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) ->
 }
 
 fn noop_fold_view_item(vi: view_item_, _fld: ast_fold) -> view_item_ {
-    ret /* FIXME: bad */ copy vi;
+    ret /* FIXME (#2543) */ copy vi;
 }
 
 
@@ -223,8 +224,8 @@ fn noop_fold_class_item(&&ci: @class_member, fld: ast_fold)
     -> @class_member {
     @{node: alt ci.node {
         instance_var(ident, t, cm, id, p) {
-           instance_var(/* FIXME: bad */ copy ident, fld.fold_ty(t), cm, id,
-                        p)
+           instance_var(/* FIXME (#2543) */ copy ident,
+                        fld.fold_ty(t), cm, id, p)
         }
         class_method(m) { class_method(fld.fold_method(m)) }
       },
@@ -260,7 +261,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
                         id: dtor_id with dtor.node}
                     with dtor}};
               item_class(
-                  /* FIXME: bad */ copy typms,
+                  /* FIXME (#2543) */ copy typms,
                   vec::map(ifaces, {|p| fold_iface_ref(p, fld) }),
                   vec::map(items, fld.fold_class_item),
                   {node: {body: ctor_body,
@@ -278,7 +279,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
           item_iface(tps, rp, methods) {
             item_iface(fold_ty_params(tps, fld),
                        rp,
-                       /* FIXME: bad */ copy methods)
+                       /* FIXME (#2543) */ copy methods)
           }
           item_res(decl, typms, body, did, cid, rp) {
             item_res(fold_fn_decl(decl, fld),
@@ -297,7 +298,7 @@ fn fold_iface_ref(&&p: @iface_ref, fld: ast_fold) -> @iface_ref {
 
 fn noop_fold_method(&&m: @method, fld: ast_fold) -> @method {
     ret @{ident: fld.fold_ident(m.ident),
-          attrs: /* FIXME: bad */ copy m.attrs,
+          attrs: /* FIXME (#2543) */ copy m.attrs,
           tps: fold_ty_params(m.tps, fld),
           decl: fold_fn_decl(m.decl, fld),
           body: fld.fold_block(m.body),
@@ -344,7 +345,7 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
           pat_rec(fields, etc) {
             let mut fs = [];
             for fields.each {|f|
-                fs += [{ident: /* FIXME: bad */ copy f.ident,
+                fs += [{ident: /* FIXME (#2543) */ copy f.ident,
                         pat: fld.fold_pat(f.pat)}];
             }
             pat_rec(fs, etc)
@@ -507,13 +508,13 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
 }
 
 fn noop_fold_constr(c: constr_, fld: ast_fold) -> constr_ {
-    {path: fld.fold_path(c.path), args: /* FIXME: bad */ copy c.args,
+    {path: fld.fold_path(c.path), args: /* FIXME (#2543) */ copy c.args,
      id: fld.new_id(c.id)}
 }
 
 fn noop_fold_ty_constr(c: ty_constr_, fld: ast_fold) -> ty_constr_ {
     let rslt: ty_constr_ =
-        {path: fld.fold_path(c.path), args: /* FIXME: bad */ copy c.args,
+        {path: fld.fold_path(c.path), args: /* FIXME (#2543) */ copy c.args,
          id: fld.new_id(c.id)};
     rslt
 }
@@ -542,7 +543,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
       some(e) {some(fld.fold_expr(e))}
       none {none}
     };
-    ret {name: /* FIXME: bad */ copy v.name,
+    ret {name: /* FIXME (#2543) */ copy v.name,
          attrs: attrs,
          args: args, id: fld.new_id(v.id),
          disr_expr: de,
@@ -550,7 +551,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
 }
 
 fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident {
-    ret /* FIXME: bad */ copy i;
+    ret /* FIXME (#2543) */ copy i;
 }
 
 fn noop_fold_path(&&p: path, fld: ast_fold) -> path {
@@ -644,7 +645,7 @@ impl of ast_fold for ast_fold_precursor {
     fn fold_class_item(&&ci: @class_member) -> @class_member {
         @{node: alt ci.node {
            instance_var(nm, t, mt, id, p) {
-               instance_var(/* FIXME: bad */ copy nm,
+               instance_var(/* FIXME (#2543) */ copy nm,
                             (self as ast_fold).fold_ty(t), mt, id, p)
            }
            class_method(m) {
diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs
index 4ebdd0dd5b5..d062f4bde6d 100644
--- a/src/libsyntax/parse.rs
+++ b/src/libsyntax/parse.rs
@@ -17,7 +17,7 @@ import attr::parser_attr;
 import common::parser_common;
 import ast::node_id;
 import util::interner;
-// FIXME: resolve badness
+// FIXME (#1935): resolve badness
 import lexer::*;//{string_reader_as_reader, tt_reader_as_reader,
                //reader, string_reader, tt_reader};
 import diagnostic::{span_handler, mk_span_handler, mk_handler, emitter};
@@ -75,7 +75,7 @@ fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
     let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
-    let cx = @{sess: sess, cfg: /* FIXME: bad */ copy p.cfg};
+    let cx = @{sess: sess, cfg: /* FIXME (#2543) */ copy p.cfg};
     let (companionmod, _) = path::splitext(path::basename(input));
     let (m, attrs) = eval::eval_crate_directives_to_mod(
         cx, cdirs, prefix, option::some(companionmod));
@@ -85,7 +85,7 @@ fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
                           {directives: cdirs,
                            module: m,
                            attrs: crate_attrs + attrs,
-                           config: /* FIXME: bad */ copy p.cfg});
+                           config: /* FIXME (#2543) */ copy p.cfg});
 }
 
 fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index b8362eb8734..52cb9366df8 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -93,8 +93,8 @@ impl parser_common for parser {
     fn eat_keyword(word: str) -> bool {
         self.require_keyword(word);
 
-        // FIXME: this gratuitous use of @ is to
-        // workaround LLVM bug #13042
+        // FIXME (#13042): this gratuitous use of @ is to
+        // workaround LLVM bug.
         alt @self.token {
           @token::IDENT(sid, false) {
             if str::eq(word, *self.get_str(sid)) {
diff --git a/src/libsyntax/parse/eval.rs b/src/libsyntax/parse/eval.rs
index 5ef8417ec6f..ae11c883443 100644
--- a/src/libsyntax/parse/eval.rs
+++ b/src/libsyntax/parse/eval.rs
@@ -103,7 +103,7 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: str,
         let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs);
 
         let i = p0.mk_item(cdir.span.lo, cdir.span.hi,
-                           /* FIXME: bad */ copy id,
+                           /* FIXME (#2543) */ copy id,
                            ast::item_mod(m0), ast::public, mod_attrs);
         // Thread defids, chpos and byte_pos through the parsers
         cx.sess.chpos = r0.chpos;
@@ -119,7 +119,7 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: str,
         let (m0, a0) = eval_crate_directives_to_mod(
             cx, cdirs, full_path, none);
         let i =
-            @{ident: /* FIXME: bad */ copy id,
+            @{ident: /* FIXME (#2543) */ copy id,
               attrs: attrs + a0,
               id: cx.sess.next_id,
               node: ast::item_mod(m0),
diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index bbf5330c18a..02b34e8dc86 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -414,9 +414,9 @@ fn scan_number(c: char, rdr: string_reader) -> token::token {
             bump(rdr);
             ret token::LIT_FLOAT(intern(*rdr.interner, @num_str),
                                  ast::ty_f64);
-            /* FIXME: if this is out of range for either a 32-bit or
-            64-bit float, it won't be noticed till the back-end (Issue #2252)
-            */
+            /* FIXME (#2252): if this is out of range for either a
+            32-bit or 64-bit float, it won't be noticed till the
+            back-end.  */
         } else {
             is_float = true;
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 146c3ab3de9..46e838fd4be 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -17,10 +17,10 @@ import dvec::{dvec, extensions};
 export file_type;
 export parser;
 
-// FIXME: #ast expects to find this here but it's actually defined in `parse`
-// Fixing this will be easier when we have export decls on individual items --
-// then parse can export this publicly, and everything else crate-visibly.
-// (See #1893)
+// FIXME (#1893): #ast expects to find this here but it's actually
+// defined in `parse` Fixing this will be easier when we have export
+// decls on individual items -- then parse can export this publicly, and
+// everything else crate-visibly.
 import parse_from_source_str;
 export parse_from_source_str;
 
@@ -172,10 +172,10 @@ class parser {
             {mode: mode, ty: p.parse_ty(false), ident: name,
              id: p.get_id()}
         };
-        // FIXME: constrs is empty because right now, higher-order functions
-        // can't have constrained types.
-        // Not sure whether that would be desirable anyway. See #34 for the
-        // story on constrained types.
+        // FIXME (#34): constrs is empty because right now, higher-order
+        // functions can't have constrained types. Not sure whether
+        // that would be desirable anyway. See bug for the story on
+        // constrained types.
         let constrs: [@constr] = [];
         let (ret_style, ret_ty) = self.parse_ret_ty();
         ret {inputs: inputs, output: ret_ty,
@@ -2039,7 +2039,7 @@ class parser {
     }
 
     fn parse_ctor(result_ty: ast::ty_) -> class_contents {
-        // Can ctors/dtors have attrs? FIXME
+        // FIXME (#2660): Can ctors/dtors have attrs?
         let lo = self.last_span.lo;
         let (decl_, _) = self.parse_fn_decl(impure_fn, {|p| p.parse_arg()});
         let decl = {output: @{id: self.get_id(),
@@ -2050,7 +2050,7 @@ class parser {
     }
 
     fn parse_dtor() -> class_contents {
-        // Can ctors/dtors have attrs? FIXME
+        // FIXME (#2660): Can ctors/dtors have attrs?
         let lo = self.last_span.lo;
         let body = self.parse_block();
         dtor_decl(body, mk_sp(lo, self.last_span.hi))
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6bd9e79b727..89f3b2d3aba 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -545,12 +545,11 @@ fn print_item(s: ps, &&item: @ast::item) {
           }
           for items.each {|ci|
                   /*
-                     FIXME: collect all private items and print them
-                     in a single "priv" section
+                     FIXME (#1893): collect all private items and print
+                     them in a single "priv" section
 
                      tjc: I'm not going to fix this yet b/c we might
                      change how exports work, including for class items
-                     (see #1893)
                    */
              hardbreak_if_not_bol(s);
              maybe_print_comment(s, ci.span.lo);
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 3b5b73d78de..5d27ee1452f 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -28,7 +28,7 @@ enum fn_kind {
 fn name_of_fn(fk: fn_kind) -> ident {
     alt fk {
       fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _, _)
-          | fk_ctor(name, _, _, _) { /* FIXME: bad */ copy name }
+          | fk_ctor(name, _, _, _) { /* FIXME (#2543) */ copy name }
       fk_anon(*) | fk_fn_block(*) { @"anon" }
       fk_dtor(*)                  { @"drop" }
     }
@@ -38,7 +38,7 @@ fn tps_of_fn(fk: fn_kind) -> [ty_param] {
     alt fk {
       fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps, _)
               | fk_ctor(_, tps, _, _) | fk_dtor(tps, _, _) {
-          /* FIXME: bad */ copy tps
+          /* FIXME (#2543) */ copy tps
       }
       fk_anon(*) | fk_fn_block(*) { [] }
     }
@@ -117,8 +117,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
     alt i.node {
       item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); }
       item_fn(decl, tp, body) {
-        v.visit_fn(fk_item_fn(/* FIXME: bad */ copy i.ident,
-                              /* FIXME: bad */ copy tp), decl, body,
+        v.visit_fn(fk_item_fn(/* FIXME (#2543) */ copy i.ident,
+                              /* FIXME (#2543) */ copy tp), decl, body,
                    i.span, i.id, e, v);
       }
       item_mod(m) { v.visit_mod(m, i.span, i.id, e, v); }
@@ -131,8 +131,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
         v.visit_ty_params(tps, e, v);
       }
       item_res(decl, tps, body, dtor_id, _, rp) {
-        v.visit_fn(fk_res(/* FIXME: bad */ copy i.ident,
-                          /* FIXME: bad */ copy tps,
+        v.visit_fn(fk_res(/* FIXME (#2543) */ copy i.ident,
+                          /* FIXME (#2543) */ copy tps,
                           rp),
                    decl, body, i.span, dtor_id, e, v);
       }
@@ -287,15 +287,16 @@ fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
 // because it is not a default impl of any method, though I doubt that really
 // clarifies anything. - Niko
 fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) {
-    v.visit_fn(fk_method(/* FIXME: bad */ copy m.ident,
-                         /* FIXME: bad */ copy m.tps, m),
+    v.visit_fn(fk_method(/* FIXME (#2543) */ copy m.ident,
+                         /* FIXME (#2543) */ copy m.tps, m),
                m.decl, m.body, m.span, m.id, e, v);
 }
 
 // Similar logic to the comment on visit_method_helper - Tim
 fn visit_class_ctor_helper<E>(ctor: class_ctor, nm: ident, tps: [ty_param],
                               parent_id: def_id, e: E, v: vt<E>) {
-    v.visit_fn(fk_ctor(/* FIXME: bad */ copy nm, /* FIXME: bad */ copy tps,
+    v.visit_fn(fk_ctor(/* FIXME (#2543) */ copy nm,
+                       /* FIXME (#2543) */ copy tps,
                        ctor.node.self_id, parent_id), ctor.node.dec,
                ctor.node.body, ctor.span, ctor.node.id, e, v)
 
@@ -303,7 +304,7 @@ fn visit_class_ctor_helper<E>(ctor: class_ctor, nm: ident, tps: [ty_param],
 
 fn visit_class_dtor_helper<E>(dtor: class_dtor, tps: [ty_param],
                               parent_id: def_id, e: E, v: vt<E>) {
-    v.visit_fn(fk_dtor(/* FIXME: bad */ copy tps, dtor.node.self_id,
+    v.visit_fn(fk_dtor(/* FIXME (#2543) */ copy tps, dtor.node.self_id,
                        parent_id), ast_util::dtor_dec(),
                dtor.node.body, dtor.span, dtor.node.id, e, v)
 
diff --git a/src/rt/memory_region.h b/src/rt/memory_region.h
index fbc439a92a6..be8689672a8 100644
--- a/src/rt/memory_region.h
+++ b/src/rt/memory_region.h
@@ -2,8 +2,8 @@
  * The Rust runtime uses memory regions to provide a primitive level of
  * memory management and isolation between tasks, and domains.
  *
- * FIXME: Implement a custom lock-free malloc / free instead of relying solely
- *       on the standard malloc / free. (#2686)
+ * FIXME (#2686): Implement a custom lock-free malloc / free instead of
+ *       relying solely on the standard malloc / free.
  */
 
 #ifndef MEMORY_REGION_H
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index 7a909c57348..67b3bf84938 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -67,8 +67,8 @@ command_line_args : public kernel_owned<command_line_args>
 };
 
 // A global that indicates whether Rust typestate claim statements should be
-// executed. Generated code will read this variable directly (I think).
-// FIXME: This belongs somewhere else (#2670)
+// executed Generated code will read this variable directly (I think).
+// FIXME (#2670): This belongs somewhere else
 int check_claims = 0;
 
 /**
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 3f754a44298..cab1b6b427c 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -232,8 +232,8 @@ rand_free(randctx *rctx) {
 
 /* Debug helpers strictly to verify ABI conformance.
  *
- * FIXME: move these into a testcase when the testsuite
- * understands how to have explicit C files included. (#2688)
+ * FIXME (#2665): move these into a testcase when the testsuite
+ * understands how to have explicit C files included.
  */
 
 struct quad {
@@ -288,19 +288,20 @@ debug_opaque(type_desc *t, uint8_t *front) {
     rust_task *task = rust_get_current_task();
     LOG(task, stdlib, "debug_opaque");
     debug_tydesc_helper(t);
-    // FIXME may want to actually account for alignment.  `front` may not
-    // indeed be the front byte of the passed-in argument. (#2667)
+    // FIXME (#2667) may want to actually account for alignment.
+    // `front` may not indeed be the front byte of the passed-in
+    // argument.
     for (uintptr_t i = 0; i < t->size; ++front, ++i) {
         LOG(task, stdlib, "  byte %" PRIdPTR ": 0x%" PRIx8, i, *front);
     }
 }
 
-// FIXME this no longer reflects the actual structure of boxes! (#2667)
+// FIXME (#2667) this no longer reflects the actual structure of boxes!
 struct rust_box {
     RUST_REFCOUNTED(rust_box)
 
-    // FIXME `data` could be aligned differently from the actual box body data
-    // (#2667)
+    // FIXME (#2667) `data` could be aligned differently from the actual
+    // box body data
     uint8_t data[];
 };
 
@@ -636,7 +637,7 @@ extern "C" CDECL rust_task*
 rust_new_task_in_sched(rust_sched_id id) {
     rust_task *task = rust_get_current_task();
     rust_scheduler *sched = task->kernel->get_scheduler_by_id(id);
-    // FIXME: What if we didn't get the scheduler? (#2668)
+    // FIXME (#2668): What if we didn't get the scheduler?
     return new_task_common(sched, task);
 }
 
diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp
index e75ec46522f..ed31ddd9dad 100644
--- a/src/rt/rust_cc.cpp
+++ b/src/rt/rust_cc.cpp
@@ -79,7 +79,7 @@ class irc : public shape::data<irc,shape::ptr> {
         shape::ptr data_end = sub.end_dp = shape::ptr(data_range.second);
         while (sub.dp < data_end) {
             sub.walk_reset();
-            // FIXME: shouldn't this be 'sub.align = true;'?
+            // FIXME (#2669): shouldn't this be 'sub.align = true;'?
             align = true;
         }
     }
@@ -214,7 +214,7 @@ irc::walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                    variant_ptr_and_end) {
     irc sub(*this, variant_ptr_and_end.first);
 
-    assert(variant_id < 256);   // FIXME: Temporary sanity check.
+    assert(variant_id < 256);   // FIXME (#2666): Temporary sanity check.
 
     const uint8_t *variant_end = variant_ptr_and_end.second;
     while (sub.sp < variant_end) {
@@ -329,7 +329,7 @@ class mark : public shape::data<mark,shape::ptr> {
             return;
 
         if (data_range.second - data_range.first > 100000)
-            abort();    // FIXME: Temporary sanity check.
+            abort();    // FIXME (#2666): Temporary sanity check.
 
         mark sub(*this, shape::ptr(data_range.first));
         shape::ptr data_end = sub.end_dp = shape::ptr(data_range.second);
@@ -454,7 +454,7 @@ mark::walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                    variant_ptr_and_end) {
     mark sub(*this, variant_ptr_and_end.first);
 
-    assert(variant_id < 256);   // FIXME: Temporary sanity check.
+    assert(variant_id < 256);   // FIXME (#2666): Temporary sanity check.
 
     const uint8_t *variant_end = variant_ptr_and_end.second;
     while (sub.sp < variant_end) {
@@ -550,7 +550,9 @@ maybe_cc(rust_task *task) {
         return;
     }
 
-    // FIXME: Needs a snapshot.
+    // FIXME (#1498): depressingly, due to alignment bugs the whole file is
+    // disabled presently unless you're doing testing. Remove the whole thing
+    // when we transition to using a visitor for GC/CC.
 #if 0
     if (task->cc_counter++ > RUST_CC_FREQUENCY) {
         task->cc_counter = 0;
diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h
index f0a03665f75..68f9e3d4519 100644
--- a/src/rt/rust_debug.h
+++ b/src/rt/rust_debug.h
@@ -34,7 +34,7 @@ public:
     flag(const char *in_name) : name(in_name), valid(false) {}
 
     bool operator*() {
-        // FIXME: We ought to lock this. (#2689)
+        // FIXME (#2689): We ought to lock this.
         if (!valid) {
             char *ev = getenv(name);
             value = ev && ev[0] != '\0' && ev[0] != '0';
diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp
index de08436cf3f..b13b1490c0f 100644
--- a/src/rt/rust_kernel.cpp
+++ b/src/rt/rust_kernel.cpp
@@ -184,23 +184,22 @@ rust_kernel::run() {
     return rval;
 }
 
-// FIXME: Fix all these FIXMEs (#2690)
 void
 rust_kernel::fail() {
-    // FIXME: On windows we're getting "Application has requested the
-    // Runtime to terminate it in an unusual way" when trying to shutdown
-    // cleanly.
+    // FIXME (#2671): On windows we're getting "Application has
+    // requested the Runtime to terminate it in an unusual way" when
+    // trying to shutdown cleanly.
     set_exit_status(PROC_FAIL_CODE);
 #if defined(__WIN32__)
     exit(rval);
 #endif
     // Copy the list of schedulers so that we don't hold the lock while
     // running kill_all_tasks.
-    // FIXME: There's a lot that happens under kill_all_tasks, and I don't
-    // know that holding sched_lock here is ok, but we need to hold the
-    // sched lock to prevent the scheduler from being destroyed while
-    // we are using it. Probably we need to make rust_scheduler atomicly
-    // reference counted.
+    // FIXME (#2671): There's a lot that happens under kill_all_tasks,
+    // and I don't know that holding sched_lock here is ok, but we need
+    // to hold the sched lock to prevent the scheduler from being
+    // destroyed while we are using it. Probably we need to make
+    // rust_scheduler atomicly reference counted.
     std::vector<rust_scheduler*> scheds;
     {
         scoped_lock with(sched_lock);
@@ -210,9 +209,9 @@ rust_kernel::fail() {
         }
     }
 
-    // FIXME: This is not a foolproof way to kill all tasks while ensuring
-    // that no new tasks or schedulers are created in the meantime that
-    // keep the scheduler alive.
+    // FIXME (#2671): This is not a foolproof way to kill all tasks
+    // while ensuring that no new tasks or schedulers are created in the
+    // meantime that keep the scheduler alive.
     for (std::vector<rust_scheduler*>::iterator iter = scheds.begin();
          iter != scheds.end(); iter++) {
         (*iter)->kill_all_tasks();
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 6e29d873ed2..5074b1f40c6 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -126,8 +126,8 @@ rust_log::trace_ln(rust_task *task, uint32_t level, char *message) {
         assert(!task->on_rust_stack() && "logging on rust stack");
     }
 
-    // FIXME: The scheduler and task names used to have meaning,
-    // but they are always equal to 'main' currently (#2672)
+    // FIXME (#2672): The scheduler and task names used to have meaning,
+    // but they are always equal to 'main' currently
 #if 0
 
 #if defined(__WIN32__)
@@ -233,8 +233,9 @@ void update_crate_map(const cratemap* map, log_directive* dirs,
     // First update log levels for this crate
     update_module_map(map->entries, dirs, n_dirs, n_matches);
     // Then recurse on linked crates
-    // FIXME this does double work in diamond-shaped deps. could keep
-    // a set of visited addresses, if it turns out to be actually slow (#2673)
+    // FIXME (#2673) this does double work in diamond-shaped deps. could
+    //   keep a set of visited addresses, if it turns out to be actually
+    //   slow
     for (size_t i = 0; map->children[i]; i++) {
         update_crate_map(map->children[i], dirs, n_dirs, n_matches);
     }
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
index b089ac46934..739527b84eb 100644
--- a/src/rt/rust_run_program.cpp
+++ b/src/rt/rust_run_program.cpp
@@ -160,7 +160,7 @@ rust_run_program(const char* argv[],
     for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd);
     if (dir) {
         int result = chdir(dir);
-        // FIXME: need error handling (#2674)
+        // FIXME (#2674): need error handling
         assert(!result && "chdir failed");
     }
 
diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h
index be80a88c30d..61fd8ac05fd 100644
--- a/src/rt/rust_sched_loop.h
+++ b/src/rt/rust_sched_loop.h
@@ -88,6 +88,7 @@ public:
 
     randctx rctx;
     const char *const name; // Used for debugging
+
     // Only a pointer to 'name' is kept, so it must live as long as this
     // domain.
     rust_sched_loop(rust_scheduler *sched, int id);
diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h
index 199c5f4bf64..74e6d6bf2bd 100644
--- a/src/rt/rust_scheduler.h
+++ b/src/rt/rust_scheduler.h
@@ -16,7 +16,7 @@ class rust_sched_launcher;
 class rust_sched_launcher_factory;
 
 class rust_scheduler : public kernel_owned<rust_scheduler> {
-    // FIXME: Make these private
+    // FIXME (#2693): Make these private
 public:
     rust_kernel *kernel;
 private:
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index 699a26aa562..cfac33008b9 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -84,7 +84,7 @@ public:
 
     template<typename T>
     inline T *alloc(size_t count = 1) {
-        // FIXME: align
+        // FIXME: align (probably won't fix before #1498)
         size_t sz = count * sizeof(T);
         T *rv = (T *)ptr;
         ptr += sz;
@@ -894,7 +894,8 @@ public:
     void walk_tag1(tag_info &tinfo);
 
     void walk_struct1(const uint8_t *end_sp) {
-        // FIXME: shouldn't we be aligning to the first element here?
+        // FIXME (probably won't fix before #1498): shouldn't we be aligning
+        // to the first element here?
         static_cast<T *>(this)->walk_struct2(end_sp);
     }
 
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 19785e3a24e..adbd75f1c90 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -59,7 +59,8 @@ rust_task::delete_this()
     DLOG(sched_loop, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
          name, (uintptr_t)this, ref_count);
 
-    // FIXME: We should do this when the task exits, not in the destructor
+    // FIXME (#2677): We should do this when the task exits, not in the
+    // destructor
     {
         scoped_lock with(supervisor_lock);
         if (supervisor) {
@@ -67,7 +68,7 @@ rust_task::delete_this()
         }
     }
 
-    /* FIXME: tighten this up, there are some more
+    /* FIXME (#2677): tighten this up, there are some more
        assertions that hold at task-lifecycle events. */
     assert(ref_count == 0); // ||
     //   (ref_count == 1 && this == sched->root_task));
@@ -114,13 +115,14 @@ cleanup_task(cleanup_args *args) {
         }
     }
 
-    // FIXME: For performance we should do the annihilator instead
-    // of the cycle collector even under normal termination, but
+    // FIXME (#2676): For performance we should do the annihilator
+    // instead of the cycle collector even under normal termination, but
     // since that would hide memory management errors (like not derefing
     // boxes), it needs to be disableable in debug builds.
     if (threw_exception) {
-        // FIXME: When the annihilator is more powerful and successfully
-        // runs resource destructors, etc. we can get rid of this cc
+        // FIXME (#2676): When the annihilator is more powerful and
+        // successfully runs resource destructors, etc. we can get rid
+        // of this cc
         cc::do_cc(task);
         annihilate_boxes(task);
     }
@@ -287,7 +289,7 @@ void
 rust_task::begin_failure(char const *expr, char const *file, size_t line) {
 
     if (expr) {
-        // FIXME: Change this message to be
+        // FIXME (#2678): Change this message to be
         // 'task failed at ...'
         LOG_ERR(this, task, "upcall fail '%s', %s:%" PRIdPTR,
                 expr, file, line);
@@ -301,7 +303,7 @@ rust_task::begin_failure(char const *expr, char const *file, size_t line) {
 #else
     die();
     conclude_failure();
-    // FIXME: Need unwinding on windows. This will end up aborting
+    // FIXME (#908): Need unwinding on windows. This will end up aborting
     sched_loop->fail();
 #endif
 }
@@ -458,7 +460,7 @@ rust_task::calloc(size_t size, const char *tag) {
 
 void
 rust_task::notify(bool success) {
-    // FIXME (1078) Do this in rust code
+    // FIXME (#1078) Do this in rust code
     if(notify_enabled) {
         rust_port *target_port =
             kernel->get_port_by_id(notify_port);
@@ -622,7 +624,7 @@ rust_task::reset_stack_limit() {
     uintptr_t sp = get_sp();
     // Have to do the rest on the C stack because it involves
     // freeing stack segments, logging, etc.
-    // FIXME: This probably doesn't need to happen on the C
+    // FIXME (#2679): This probably doesn't need to happen on the C
     // stack now
     reset_args ra = {this, sp};
     call_on_c_stack(&ra, (void*)reset_stack_limit_on_c_stack);
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h
index 43f1abd190e..2a58725c6a4 100644
--- a/src/rt/rust_task.h
+++ b/src/rt/rust_task.h
@@ -18,10 +18,11 @@
    threads at any time. This may keep the task from being destroyed even after
    the task is dead from a Rust task lifecycle perspective.
 
-   FIXME: The task and the scheduler have an over-complicated, undocumented
-   protocol for shutting down the task, hopefully without races. It would be
-   easier to reason about if other runtime objects could not access the task
-   from arbitrary threads, and didn't need to be atomically refcounted.
+   FIXME (#2696): The task and the scheduler have an over-complicated,
+   undocumented protocol for shutting down the task, hopefully without
+   races. It would be easier to reason about if other runtime objects could
+   not access the task from arbitrary threads, and didn't need to be
+   atomically refcounted.
  */
 
 #ifndef RUST_TASK_H
@@ -42,8 +43,9 @@
 
 // The amount of extra space at the end of each stack segment, available
 // to the rt, compiler and dynamic linker for running small functions
-// FIXME: We want this to be 128 but need to slim the red zone calls down,
-// disable lazy symbol relocation, and other things we haven't discovered yet
+// FIXME (#1509): We want this to be 128 but need to slim the red zone calls
+// down, disable lazy symbol relocation, and other things we haven't
+// discovered yet
 #define RZ_LINUX_32 (1024*2)
 #define RZ_LINUX_64 (1024*2)
 #define RZ_MAC_32   (1024*20)
@@ -303,7 +305,7 @@ public:
     void allow_kill();
 };
 
-// FIXME: It would be really nice to be able to get rid of this.
+// FIXME (#2697): It would be really nice to be able to get rid of this.
 inline void *operator new[](size_t size, rust_task *task, const char *tag) {
     return task->malloc(size, tag);
 }
@@ -360,9 +362,9 @@ sanitize_next_sp(uintptr_t next_sp) {
     // to the amount of stack needed for calling __morestack I've added some
     // extra bytes here.
 
-    // FIXME: On the rust stack this potentially puts is quite far into the
-    // red zone. Might want to just allocate a new rust stack every time we
-    // switch back to rust.
+    // FIXME (#2698): On the rust stack this potentially puts is quite far
+    // into the red zone. Might want to just allocate a new rust stack every
+    // time we switch back to rust.
     const uintptr_t padding = 16;
 
     return align_down(next_sp - padding);
@@ -416,7 +418,7 @@ rust_task::call_on_rust_stack(void *args, void *fn_ptr) {
 
     uintptr_t sp = sanitize_next_sp(next_rust_sp);
 
-    // FIXME(2047): There are times when this is called and needs
+    // FIXME (#2047): There are times when this is called and needs
     // to be able to throw, and we don't account for that.
     __morestack(args, fn_ptr, sp);
 
@@ -529,7 +531,7 @@ rust_task::record_stack_limit() {
 inline rust_task* rust_get_current_task() {
     uintptr_t sp_limit = get_sp_limit();
 
-    // FIXME (1226) - Because of a hack in upcall_call_shim_on_c_stack this
+    // FIXME (#1226) - Because of a hack in upcall_call_shim_on_c_stack this
     // value is sometimes inconveniently set to 0, so we can't use this
     // method of retreiving the task pointer and need to fall back to TLS.
     if (sp_limit == 0)
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 986bc713213..940cf3aa01a 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -49,7 +49,7 @@ extern "C" CDECL void
 upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
     rust_task *task = rust_get_current_task();
 
-    // FIXME (1226) - The shim functions generated by rustc contain the
+    // FIXME (#1226) - The shim functions generated by rustc contain the
     // morestack prologue, so we need to let them know they have enough
     // stack.
     record_sp_limit(0);
@@ -72,9 +72,9 @@ extern "C" CDECL void
 upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
     rust_task *task = rust_get_current_task();
 
-    // FIXME: Because of the hack in the other function that disables the
-    // stack limit when entering the C stack, here we restore the stack limit
-    // again.
+    // FIXME (#2680): Because of the hack in the other function that disables
+    // the stack limit when entering the C stack, here we restore the stack
+    // limit again.
     task->record_stack_limit();
 
     try {
@@ -86,7 +86,7 @@ upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
         assert(false && "Rust task failed after reentering the Rust stack");
     }
 
-    // FIXME: As above
+    // FIXME (#2680): As above
     record_sp_limit(0);
 }
 
@@ -177,7 +177,7 @@ upcall_exchange_malloc(type_desc *td, uintptr_t size) {
     return args.retval;
 }
 
-// FIXME: remove after snapshot (6/21/12)
+// FIXME (#2681): remove after snapshot (6/21/12)
 extern "C" CDECL uintptr_t
 upcall_exchange_malloc_dyn(type_desc *td, uintptr_t size) {
     rust_task *task = rust_get_current_task();
@@ -246,7 +246,7 @@ upcall_malloc(type_desc *td, uintptr_t size) {
     return args.retval;
 }
 
-// FIXME: remove after snapshot (6/21/12)
+// FIXME (#2681): remove after snapshot (6/21/12)
 extern "C" CDECL uintptr_t
 upcall_malloc_dyn(type_desc *td, uintptr_t size) {
     rust_task *task = rust_get_current_task();
diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h
index 2040a641c47..247f253fd9f 100644
--- a/src/rt/rust_util.h
+++ b/src/rt/rust_util.h
@@ -111,7 +111,7 @@ make_str_vec(rust_kernel* kernel, size_t nstrs, char **strs) {
 
 inline size_t get_box_size(size_t body_size, size_t body_align) {
     size_t header_size = sizeof(rust_opaque_box);
-    // FIXME: This alignment calculation is suspicious. Is it right?
+    // FIXME (#2699): This alignment calculation is suspicious. Is it right?
     size_t total_size = align_to(header_size, body_align) + body_size;
     return total_size;
 }
diff --git a/src/rt/sync/lock_and_signal.cpp b/src/rt/sync/lock_and_signal.cpp
index ccc762c2cc9..9558aaa7c06 100644
--- a/src/rt/sync/lock_and_signal.cpp
+++ b/src/rt/sync/lock_and_signal.cpp
@@ -9,7 +9,8 @@
  * if you're using a pthreads cvar+mutex pair.
  */
 
-// FIXME: This is not a portable way of specifying an invalid pthread_t
+// FIXME (#2683): This is not a portable way of specifying an invalid
+// pthread_t
 #define INVALID_THREAD 0
 
 
diff --git a/src/rt/sync/lock_free_queue.h b/src/rt/sync/lock_free_queue.h
index 3ee15d5d3a6..ed11b1aa321 100644
--- a/src/rt/sync/lock_free_queue.h
+++ b/src/rt/sync/lock_free_queue.h
@@ -88,8 +88,8 @@ class lock_free_queue {
         pointer_t *oldValue,
         pointer_t newValue) {
 
-        // FIXME this is requiring us to pass -fno-strict-aliasing to GCC
-        // (possibly there are other, similar problems)
+        // FIXME (#2701) this is requiring us to pass -fno-strict-aliasing
+        // to GCC (possibly there are other, similar problems)
         if (sync::compare_and_swap(
                 (uint64_t*) address,
                 *(uint64_t*) oldValue,
diff --git a/src/rt/sync/timer.cpp b/src/rt/sync/timer.cpp
index 28ee6da2b62..0204517d512 100644
--- a/src/rt/sync/timer.cpp
+++ b/src/rt/sync/timer.cpp
@@ -10,7 +10,7 @@ uint64_t ns_per_s = 1000000000LL;
 timer::timer() {
 #if __WIN32__
     _ticks_per_s = 0LL;
-    // FIXME: assert this works or have a workaround.
+    // FIXME (#2675): assert this works or have a workaround.
     QueryPerformanceFrequency((LARGE_INTEGER *)&_ticks_per_s);
     if (_ticks_per_s == 0LL) {
       _ticks_per_s = 1LL;
diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs
index facb0bcda31..4875fbd69ca 100644
--- a/src/rustc/back/link.rs
+++ b/src/rustc/back/link.rs
@@ -85,13 +85,12 @@ mod write {
             }
         }
         if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
-        // FIXME: This is mostly a copy of the bits of opt's -O2 that are
-        // available in the C api.
-        // FIXME2: We might want to add optimization levels like -O1, -O2,
+        // FIXME (#2396): This is mostly a copy of the bits of opt's -O2 that
+        // are available in the C api.
+        // Also: We might want to add optimization levels like -O1, -O2,
         // -Os, etc
-        // FIXME3: Should we expose and use the pass lists used by the opt
+        // Also: Should we expose and use the pass lists used by the opt
         // tool?
-        // See #2396
 
         if opts.optimize != 0u {
             let fpm = mk_pass_manager();
@@ -668,9 +667,8 @@ fn link_binary(sess: session,
     // Stack growth requires statically linking a __morestack function
     cc_args += ["-lmorestack"];
 
-    // FIXME: At some point we want to rpath our guesses as to where
+    // FIXME (#2397): At some point we want to rpath our guesses as to where
     // native libraries might live, based on the addl_lib_search_paths
-    // #2397
     cc_args += rpath::get_rpath_flags(sess, output);
 
     #debug("%s link args: %s", cc_prog, str::connect(cc_args, " "));
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index 2cd9c392ef4..553db7695a8 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -78,9 +78,9 @@ fn build_configuration(sess: session, argv0: str, input: input) ->
 
 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
 fn parse_cfgspecs(cfgspecs: [str]) -> ast::crate_cfg {
-    // FIXME: It would be nice to use the parser to parse all varieties of
-    // meta_item here. At the moment we just support the meta_word variant.
-    // #2399
+    // FIXME (#2399): It would be nice to use the parser to parse all
+    // varieties of meta_item here. At the moment we just support the
+    // meta_word variant.
     let mut words = [];
     for cfgspecs.each {|s| words += [attr::mk_word_item(@s)]; }
     ret words;
@@ -100,8 +100,7 @@ fn parse_input(sess: session, cfg: ast::crate_cfg, input: input)
         parse::parse_crate_from_file(file, cfg, sess.parse_sess)
       }
       str_input(src) {
-        // FIXME: Don't really want to box the source string
-        // #2319
+        // FIXME (#2319): Don't really want to box the source string
         parse::parse_crate_from_source_str(
             anon_src(), @src, cfg, sess.parse_sess)
       }
@@ -389,9 +388,10 @@ fn host_triple() -> str {
     // idea of the host triple is the same as for the set of libraries we've
     // actually built.  We can't just take LLVM's host triple because they
     // normalize all ix86 architectures to i386.
-    // FIXME: Instead of grabbing the host triple we really should be
-    // grabbing (at compile time) the target triple that this rustc is
-    // built with and calling that (at runtime) the host triple. (#2400)
+
+    // FIXME (#2400): Instead of grabbing the host triple we really should
+    // be grabbing (at compile time) the target triple that this rustc is
+    // built with and calling that (at runtime) the host triple.
     let ht = #env("CFG_HOST_TRIPLE");
     ret if ht != "" {
             ht
@@ -660,10 +660,10 @@ fn build_output_filenames(input: input,
         };
 
         if sess.building_library {
-            // FIXME: We might want to warn here; we're actually not going to
-            // respect the user's choice of library name when it comes time to
-            // link, we'll be linking to lib<basename>-<hash>-<version>.so no
-            // matter what. (#2401)
+            // FIXME (#2401): We might want to warn here; we're actually not
+            // going to respect the user's choice of library name when it
+            // comes time to link, we'll be linking to
+            // lib<basename>-<hash>-<version>.so no matter what.
         }
 
         if odir != none {
diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs
index def4c7d9a83..9645d919b04 100644
--- a/src/rustc/driver/session.rs
+++ b/src/rustc/driver/session.rs
@@ -32,7 +32,7 @@ const stats: uint = 16u;
 const no_asm_comments: uint = 32u;
 const no_verify: uint = 64u;
 const trace: uint = 128u;
-// FIXME: This exists to transition to a Rust crate runtime
+// FIXME (#2377): This exists to transition to a Rust crate runtime
 // It should be removed
 const no_rt: uint = 256u;
 
diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs
index 473d25841b8..2c40db16a45 100644
--- a/src/rustc/front/test.rs
+++ b/src/rustc/front/test.rs
@@ -64,9 +64,10 @@ fn strip_test_functions(crate: @ast::crate) -> @ast::crate {
 fn fold_mod(_cx: test_ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod {
 
     // Remove any defined main function from the AST so it doesn't clash with
-    // the one we're going to add.  FIXME: This is sloppy. Instead we should
-    // have some mechanism to indicate to the translation pass which function
-    // we want to be main. (#2403)
+    // the one we're going to add.
+
+    // FIXME (#2403): This is sloppy. Instead we should have some mechanism to
+    // indicate to the translation pass which function we want to be main.
     fn nomain(&&item: @ast::item) -> option<@ast::item> {
         alt item.node {
           ast::item_fn(_, _, _) {
@@ -338,8 +339,8 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
 }
 
 // Produces a bare function that wraps the test function
-// FIXME: This can go away once fn is the type of bare function
-// (See #1281)
+
+// FIXME (#1281): This can go away once fn is the type of bare function.
 fn mk_test_wrapper(cx: test_ctxt,
                    fn_path_expr: ast::expr,
                    span: span) -> @ast::expr {
diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs
index 97ccb1d3f24..c63d03ce239 100644
--- a/src/rustc/metadata/creader.rs
+++ b/src/rustc/metadata/creader.rs
@@ -261,8 +261,8 @@ fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
           none {
             #debug("need to load it");
             // This is a new one so we've got to load it
-            // FIXME: Need better error reporting than just a bogus span
-            // #2404
+            // FIXME (#2404): Need better error reporting than just a bogus
+            // span.
             let fake_span = ast_util::dummy_sp();
             let local_cnum =
                 resolve_crate(e, cname, cmetas, *dep.hash, fake_span);
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index e8e367656c1..7209d4e6731 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -433,8 +433,7 @@ fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint)
         let m_did = parse_def_id(ebml::doc_data(doc));
         let mth_item = lookup_item(m_did.node, cdata.data);
         rslt += [@{did: translate_def_id(cdata, m_did),
-                    /* FIXME tjc: take a look at this, it may relate
-                     to #2323 */
+                    /* FIXME (maybe #2323) tjc: take a look at this. */
                    n_tps: item_ty_param_count(mth_item) - base_tps,
                    ident: item_name(mth_item)}];
     }
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index e8fb1a3596e..62c4a078952 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -1028,9 +1028,8 @@ fn encode_crate_deps(ebml_w: ebml::writer, cstore: cstore::cstore) {
 
     // We're just going to write a list of crate 'name-hash-version's, with
     // the assumption that they are numbered 1 to n.
-    // FIXME: This is not nearly enough to support correct versioning
+    // FIXME (#2166): This is not nearly enough to support correct versioning
     // but is enough to get transitive crate dependencies working.
-    // See #2166
     ebml_w.start_tag(tag_crate_deps);
     for get_ordered_deps(cstore).each {|dep|
         encode_crate_dep(ebml_w, dep);
diff --git a/src/rustc/metadata/filesearch.rs b/src/rustc/metadata/filesearch.rs
index a5cc6c28d53..eeb44f80fd7 100644
--- a/src/rustc/metadata/filesearch.rs
+++ b/src/rustc/metadata/filesearch.rs
@@ -1,6 +1,6 @@
 // A module for searching for libraries
-// FIXME: I'm not happy how this module turned out. Should probably
-// just be folded into cstore.
+// FIXME (#2658): I'm not happy how this module turned out. Should
+// probably just be folded into cstore.
 
 import result::result;
 export filesearch;
diff --git a/src/rustc/metadata/loader.rs b/src/rustc/metadata/loader.rs
index 2cbf529ecf0..a5874aa29fa 100644
--- a/src/rustc/metadata/loader.rs
+++ b/src/rustc/metadata/loader.rs
@@ -125,8 +125,8 @@ fn crate_name_from_metas(metas: [@ast::meta_item]) -> @str {
       some(i) {
         alt attr::get_meta_item_value_str(i) {
           some(n) { n }
-          // FIXME: Probably want a warning here since the user
-          // is using the wrong type of meta item (#2406)
+          // FIXME (#2406): Probably want a warning here since the user
+          // is using the wrong type of meta item.
           _ { fail }
         }
       }
diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs
index 1745757151c..df46a4cef8f 100644
--- a/src/rustc/middle/borrowck/gather_loans.rs
+++ b/src/rustc/middle/borrowck/gather_loans.rs
@@ -85,12 +85,12 @@ fn req_loans_in_expr(ex: @ast::expr,
                 // is mutable in the caller's frame, thus effectively
                 // passing the buck onto us to enforce this)
                 //
-                // FIXME---this handling is not really adequate.  For
-                // example, if there is a type like, {f: [int]}, we
-                // will ignore it, but we ought to be requiring it to
-                // be immutable (whereas something like {f:int} would
-                // be fine).
-                // (See #2493)
+                // FIXME (#2493): this handling is not really adequate.
+                // For example, if there is a type like, {f: [int]}, we
+                // will ignore it, but we ought to be requiring it to be
+                // immutable (whereas something like {f:int} would be
+                // fine).
+                //
 
                 alt opt_deref_kind(arg_ty.ty) {
                   some(deref_ptr(region_ptr)) |
@@ -130,7 +130,7 @@ fn req_loans_in_expr(ex: @ast::expr,
         // Here, in an overloaded operator, the call is this expression,
         // and hence the scope of the borrow is this call.
         //
-        // FIXME/NOT REALLY---technically we should check the other
+        // FIX? / NOT REALLY---technically we should check the other
         // argument and consider the argument mode.  But how annoying.
         // And this problem when goes away when argument modes are
         // phased out.  So I elect to leave this undone.
diff --git a/src/rustc/middle/const_eval.rs b/src/rustc/middle/const_eval.rs
index 661ad87dfa8..26ffbdc0273 100644
--- a/src/rustc/middle/const_eval.rs
+++ b/src/rustc/middle/const_eval.rs
@@ -1,7 +1,7 @@
 import syntax::ast::*;
 
-// FIXME this doesn't handle big integer/float literals correctly (nor does
-// the rest of our literal handling - issue #33)
+// FIXME (#33): this doesn't handle big integer/float literals correctly
+// (nor does the rest of our literal handling).
 enum const_val {
     const_float(f64),
     const_int(i64),
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 78a0f1bfef7..0ae04c25ccd 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -215,9 +215,9 @@ fn iter_effective_import_paths(vi: ast::view_item,
     iter_export_paths(vi) {|vp|
         alt vp.node {
           ast::view_path_simple(_, _, _) { }
-          // FIXME: support uniform ident-list exports eventually;
-          // at the moment they have half a meaning as reaching into
-          // tags. (but also see #1893)
+          // FIXME (but also see #1893): support uniform ident-list exports
+          // eventually; at the moment they have half a meaning as reaching
+          // into tags.
           ast::view_path_list(_, _, _) {}
           ast::view_path_glob(_,_) {
             f(vp);
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index d308181d8c7..d202ba7a123 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1354,10 +1354,10 @@ fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
 
 fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
                 n_bytes: ValueRef) {
-    // FIXME: Provide LLVM with better alignment information when the
-    // alignment is statically known (it must be nothing more than a constant
-    // int, or LLVM complains -- not even a constant element of a tydesc
-    // works). (Related to #1645, I think?)
+    // FIXME (Related to #1645, I think?): Provide LLVM with better
+    // alignment information when the alignment is statically known (it must
+    // be nothing more than a constant int, or LLVM complains -- not even a
+    // constant element of a tydesc works).
     let _icx = cx.insn_ctxt("call_memmove");
     let ccx = cx.ccx();
     let key = alt ccx.sess.targ_cfg.arch {
@@ -1439,9 +1439,9 @@ fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
 
 // This works like copy_val, except that it deinitializes the source.
 // Since it needs to zero out the source, src also needs to be an lval.
-// FIXME: We always zero out the source. Ideally we would detect the
+// FIXME (#839): We always zero out the source. Ideally we would detect the
 // case where a variable is always deinitialized by block exit and thus
-// doesn't need to be dropped. (Issue #839)
+// doesn't need to be dropped.
 fn move_val(cx: block, action: copy_action, dst: ValueRef,
             src: lval_result, t: ty::t) -> block {
 
@@ -1652,8 +1652,8 @@ fn cast_shift_rhs(op: ast::binop,
         if lhs_sz < rhs_sz {
             trunc(rhs, lhs_llty)
         } else if lhs_sz > rhs_sz {
-            // FIXME: If shifting by negative values becomes not undefined
-            // then this is wrong. (See discussion at #1570)
+            // FIXME (See discussion at #1570): If shifting by negative
+            // values becomes not undefined then this is wrong.
             zext(rhs, lhs_llty)
         } else {
             rhs
@@ -1790,14 +1790,14 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
             bcx, ex.info(), fty,
             expr_ty(bcx, ex),
             {|bcx|
-                // FIXME provide the already-computed address, not the expr
-                // #2528
+                // FIXME (#2528): provide the already-computed address, not
+                // the expr.
                 impl::trans_method_callee(bcx, callee_id, dst, origin)
             },
             arg_exprs([src]), save_in(target));
 
         ret move_val(bcx, DROP_EXISTING, lhs_res.val,
-                     // FIXME: should kind be owned?
+                     // FIXME (#2704): should kind be owned?
                      {bcx: bcx, val: target, kind: owned},
                      dty);
       }
@@ -4759,9 +4759,9 @@ fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
 }
 
 
-// FIXME: this should do some structural hash-consing to avoid
-// duplicate constants. I think. Maybe LLVM has a magical mode
-// that does so later on? (#2530)
+// FIXME (#2530): this should do some structural hash-consing to avoid
+// duplicate constants. I think. Maybe LLVM has a magical mode that does so
+// later on?
 fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
     let _icx = cx.insn_ctxt("trans_const_expr");
     alt e.node {
@@ -4863,9 +4863,9 @@ fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
               ast_map::node_item(@{
                 node: ast::item_const(_, subexpr), _
               }, _) {
-                // FIXME: Instead of recursing here to regenerate the values
-                // for other constants, we should just look up the
-                // already-defined value (#2530)
+                // FIXME (#2530): Instead of recursing here to regenerate
+                // the values for other constants, we should just look up
+                // the already-defined value.
                 trans_const_expr(cx, subexpr)
               }
               _ {
diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs
index f80dd130e0e..e90590f0228 100644
--- a/src/rustc/middle/trans/debuginfo.rs
+++ b/src/rustc/middle/trans/debuginfo.rs
@@ -522,7 +522,7 @@ fn create_ty(_cx: @crate_ctxt, _t: ty::t, _ty: @ast::ty)
       option::none {}
     }*/
 
-    /* FIXME I am disabling this code as part of the patch that moves
+    /* FIXME (#2012): disabled this code as part of the patch that moves
      * recognition of named builtin types into resolve. I tried to fix
      * it, but it seems to already be broken -- it's only called when
      * --xg is given, and compiling with --xg fails on trivial programs.
@@ -531,8 +531,6 @@ fn create_ty(_cx: @crate_ctxt, _t: ty::t, _ty: @ast::ty)
      * needed. It is only done to track spans, but you will not get the
      * right spans anyway -- types tend to refer to stuff defined
      * elsewhere, not be self-contained.
-     *
-     * See Issue #2012
      */
 
     fail;
diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs
index 28536282fad..fcc7f370f74 100644
--- a/src/rustc/middle/trans/native.rs
+++ b/src/rustc/middle/trans/native.rs
@@ -700,8 +700,8 @@ fn trans_native_mod(ccx: @crate_ctxt,
         }
     }
 
-    // FIXME this is very shaky and probably gets ABIs wrong all over
-    // the place (#2535)
+    // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
+    // over the place
     fn build_direct_fn(ccx: @crate_ctxt, decl: ValueRef,
                        item: @ast::native_item, tys: @c_stack_tys,
                        cc: lib::llvm::CallConv) {
diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs
index 9731c34fa82..740d53ed773 100644
--- a/src/rustc/middle/trans/reflect.rs
+++ b/src/rustc/middle/trans/reflect.rs
@@ -163,8 +163,8 @@ impl methods for reflector {
             self.visit("leave_tup", extra);
           }
 
-          // FIXME: fetch constants out of intrinsic:: for the numbers.
-          // (#2594)
+          // FIXME (#2594): fetch constants out of intrinsic:: for the
+          // numbers.
           ty::ty_fn(fty) {
             let pureval = alt fty.purity {
               ast::pure_fn { 0u }
@@ -226,10 +226,10 @@ impl methods for reflector {
             self.visit("leave_class", extra);
           }
 
-          // FIXME: visiting all the variants in turn is probably
-          // not ideal. It'll work but will get costly on big enums.
-          // Maybe let the visitor tell us if it wants to visit only
-          // a particular variant? (#2595)
+          // FIXME (#2595): visiting all the variants in turn is probably
+          // not ideal. It'll work but will get costly on big enums. Maybe
+          // let the visitor tell us if it wants to visit only a particular
+          // variant?
           ty::ty_enum(did, substs) {
             let bcx = self.bcx;
             let tcx = bcx.ccx().tcx;
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index f0d98da5adb..f28d0b53e53 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -491,7 +491,7 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
         // Compute the minimum and maximum size and alignment for each
         // variant.
         //
-        // FIXME: We could do better here; e.g. we know that any
+        // NB: We could do better here; e.g. we know that any
         // variant that contains (T,T) must be as least as large as
         // any variant that contains just T.
         let mut ranges = [];
@@ -500,7 +500,7 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
             let mut min_size = 0u, min_align = 0u;
             for vec::each(variant.args) {|elem_t|
                 if ty::type_has_params(elem_t) {
-                    // FIXME: We could do better here; this causes us to
+                    // NB: We could do better here; this causes us to
                     // conservatively assume that (int, T) has minimum size 0,
                     // when in fact it has minimum size sizeof(int).
                     bounded = false;
@@ -699,7 +699,7 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
 // Computes the static size of a enum, without using mk_tup(), which is
 // bad for performance.
 //
-// FIXME: Migrate trans over to use this.
+// NB: Migrate trans over to use this.
 
 // Computes the size of the data part of an enum.
 fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) -> uint {
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index 164a089dc88..d05629b990f 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -422,8 +422,9 @@ fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t,
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
 
     // Calculate the last pointer address we want to handle.
-    // FIXME: Optimize this when the size of the unit type is statically
-    // known to not use pointer casts, which tend to confuse LLVM. (#2536)
+    // FIXME (#2536): Optimize this when the size of the unit type is
+    // statically known to not use pointer casts, which tend to confuse
+    // LLVM.
     let data_end_ptr = pointer_add(bcx, data_ptr, fill);
 
     // Now perform the iteration.
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index 7f87c6f74e2..628d407fead 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -183,8 +183,8 @@ fn mark_for_expr(cx: ctx, e: @expr) {
         node_type_needs(cx, use_repr, val.id);
       }
       expr_index(base, _) | expr_field(base, _, _) {
-        // FIXME could be more careful and not count fields
-        // after the chosen field (#2537)
+        // FIXME (#2537): could be more careful and not count fields after
+        // the chosen field.
         let base_ty = ty::node_id_to_type(cx.ccx.tcx, base.id);
         type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
 
diff --git a/src/rustc/middle/tstate/ann.rs b/src/rustc/middle/tstate/ann.rs
index a6a46d1e222..f20ad0f73dc 100644
--- a/src/rustc/middle/tstate/ann.rs
+++ b/src/rustc/middle/tstate/ann.rs
@@ -243,8 +243,8 @@ fn trit_str(t: trit) -> str {
     alt t { dont_care { "?" } ttrue { "1" } tfalse { "0" } }
 }
 
-// FIXME: Would be nice to have unit tests for some of these operations, as
-// a step towards formalizing them more rigorously. #2538
+// FIXME (#2538): Would be nice to have unit tests for some of these
+// operations, as a step towards formalizing them more rigorously.
 
 //
 // Local Variables:
diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs
index 1ccb19cd53f..5fb79dc1318 100644
--- a/src/rustc/middle/tstate/auxiliary.rs
+++ b/src/rustc/middle/tstate/auxiliary.rs
@@ -195,8 +195,8 @@ may be the operator in a "check" expression in the source.  */
 
 type constraint = {
     path: @path,
-    // FIXME: really only want it to be mut during collect_locals.
-    // freeze it after that. (#2539)
+    // FIXME (#2539): really only want it to be mut during
+    // collect_locals.  freeze it after that.
     descs: @dvec<pred_args>
 };
 
@@ -494,9 +494,8 @@ fn constraints(fcx: fn_ctxt) -> [norm_constraint] {
     ret rslt;
 }
 
-// FIXME
-// Would rather take an immutable vec as an argument,
-// should freeze it at some earlier point. (#2539)
+// FIXME (#2539): Would rather take an immutable vec as an argument,
+// should freeze it at some earlier point.
 fn match_args(fcx: fn_ctxt, occs: @dvec<pred_args>,
               occ: [@constr_arg_use]) -> uint {
     #debug("match_args: looking at %s",
diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs
index 2948d097ab6..4883422a908 100644
--- a/src/rustc/middle/tstate/states.rs
+++ b/src/rustc/middle/tstate/states.rs
@@ -169,9 +169,9 @@ fn find_pre_post_state_call(fcx: fn_ctxt, pres: prestate, a: @expr,
                             id: node_id, ops: [init_op], bs: [@expr],
                             cf: ret_style) -> bool {
     let mut changed = find_pre_post_state_expr(fcx, pres, a);
-    // FIXME: This could be a typestate constraint (except we're
-    // not using them inside the compiler, I guess... see
-    // discussion at #2178)
+    // FIXME (#2178): This could be a typestate constraint (except we're
+    // not using them inside the compiler, I guess... see discussion in
+    // bug)
     if vec::len(bs) != vec::len(ops) {
         fcx.ccx.tcx.sess.span_bug(a.span,
                                   #fmt["mismatched arg lengths: \
diff --git a/src/rustc/middle/tstate/tritv.rs b/src/rustc/middle/tstate/tritv.rs
index 546a8ae7deb..7bcc4840d25 100644
--- a/src/rustc/middle/tstate/tritv.rs
+++ b/src/rustc/middle/tstate/tritv.rs
@@ -25,10 +25,10 @@ export to_str;
    01 = "this constraint is definitely true"
    00 = "this constraint is definitely false"
    11 should never appear
- FIXME: typestate precondition (uncertain and val must
+ FIXME (#2178): typestate precondition (uncertain and val must
  have the same length; 11 should never appear in a given position)
  (except we're not putting typestate constraints in the compiler, as
- per discussion at #2178).
+ per discussion at).
 */
 
 type t = {uncertain: bitv::bitv, val: bitv::bitv, nbits: uint};
@@ -90,8 +90,8 @@ fn trit_or(a: trit, b: trit) -> trit {
       tfalse {
         alt b {
           ttrue { dont_care }
-          /* FIXME: ??????
-             Again, unit tests would help here -- #2538
+          /* FIXME (#2538): ??????
+             Again, unit tests would help here
            */
           _ {
             tfalse
@@ -101,12 +101,11 @@ fn trit_or(a: trit, b: trit) -> trit {
     }
 }
 
-// FIXME: This still seems kind of dodgy to me (that is,
+// FIXME (#2538): This still seems kind of dodgy to me (that is,
 // that 1 + ? = 1. But it might work out given that
 // all variables start out in a 0 state. Probably I need
 // to make it so that all constraints start out in a 0 state
 // (we consider a constraint false until proven true), too.
-// #2538 would help.
 fn trit_and(a: trit, b: trit) -> trit {
     alt a {
       dont_care { b }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 92ed7da8ace..3083563d220 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -1209,7 +1209,6 @@ pure fn type_is_scalar(ty: t) -> bool {
     }
 }
 
-// FIXME maybe inline this for speed?
 fn type_is_immediate(ty: t) -> bool {
     ret type_is_scalar(ty) || type_is_boxed(ty) ||
         type_is_unique(ty) || type_is_region_ptr(ty);
@@ -1614,7 +1613,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
         param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
       }
       ty_constr(t, _) { type_kind(cx, t) }
-      // FIXME: is self ever const?
+      // FIXME (#2663): is self ever const?
       ty_self { kind_noncopyable() }
       ty_var(_) | ty_var_integral(_) {
         cx.sess.bug("Asked to compute kind of a type variable");
@@ -2038,7 +2037,6 @@ fn hash_type_structure(st: sty) -> uint {
     fn hash_type_constr(id: uint, c: @type_constr) -> uint {
         let mut h = id;
         h = (h << 2u) + hash_def(h, c.node.id);
-        // FIXME this makes little sense
         for c.node.args.each {|a|
             alt a.node {
               carg_base { h += h << 2u; }
@@ -2169,7 +2167,6 @@ fn args_eq<T>(eq: fn(T, T) -> bool,
 fn constr_eq(c: @constr, d: @constr) -> bool {
     fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; }
     ret path_to_str(c.node.path) == path_to_str(d.node.path) &&
-            // FIXME: hack
             args_eq(eq_int, c.node.args, d.node.args);
 }
 
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 249c0105bea..b693ddb8492 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -25,8 +25,8 @@ import rscope::*;
 
 fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
 
-    // FIXME: hooking into the "intrinsic" root module is crude.
-    // there ought to be a better approach. Attributes? (#2592)
+    // FIXME (#2592): hooking into the "intrinsic" root module is crude.
+    // There ought to be a better approach. Attributes?
 
     for crate.node.module.items.each {|crate_item|
         if *crate_item.ident == "intrinsic" {
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index d545702048f..e948e999e5c 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -387,10 +387,10 @@ fn can_mk_assignty(cx: infer_ctxt, anmnt: assignment,
     #debug["can_mk_assignty(%? / %s <: %s)",
            anmnt, a.to_str(cx), b.to_str(cx)];
 
-    // FIXME---this will not unroll any entries we make in the
-    // borrowings table.  But this is OK for the moment because this
-    // is only used in method lookup, and there must be exactly one
-    // match or an error is reported. Still, it should be fixed. (#2593)
+    // FIXME (#2593): this will not unroll any entries we make in the
+    // borrowings table.  But this is OK for the moment because this is only
+    // used in method lookup, and there must be exactly one match or an
+    // error is reported. Still, it should be fixed.
 
     indent {|| cx.probe {||
         cx.assign_tys(anmnt, a, b)
@@ -1707,16 +1707,16 @@ fn super_fns<C:combine>(
             argvecs(self, a_f.inputs, b_f.inputs).chain {|inputs|
                 self.tys(a_f.output, b_f.output).chain {|output|
                     self.purities(a_f.purity, b_f.purity).chain {|purity|
-                    //FIXME self.infcx().constrvecs(a_f.constraints,
-                    //FIXME                         b_f.constraints).then {||
-                    // (Fix this if #2588 doesn't get accepted)
+                    // FIXME: uncomment if #2588 doesn't get accepted:
+                    // self.infcx().constrvecs(a_f.constraints,
+                    //                         b_f.constraints).then {||
                         ok({purity: purity,
                             proto: p,
                             inputs: inputs,
                             output: output,
                             ret_style: rs,
                             constraints: a_f.constraints})
-                    //FIXME }
+                    // }
                     }
                 }
             }
diff --git a/src/rustc/util/common.rs b/src/rustc/util/common.rs
index e12aa98b67a..6e6c5fa740e 100644
--- a/src/rustc/util/common.rs
+++ b/src/rustc/util/common.rs
@@ -70,8 +70,8 @@ fn local_rhs_span(l: @ast::local, def: span) -> span {
 }
 
 fn is_main_name(path: syntax::ast_map::path) -> bool {
-    // FIXME: path should be a constrained type, so we know
-    // the call to last doesn't fail (#34)
+    // FIXME (#34): path should be a constrained type, so we know
+    // the call to last doesn't fail.
     vec::last(path) == syntax::ast_map::path_name(@"main")
 }
 
diff --git a/src/rustdoc/demo.rs b/src/rustdoc/demo.rs
index dff9bfbc257..f39fe1f8120 100644
--- a/src/rustdoc/demo.rs
+++ b/src/rustdoc/demo.rs
@@ -8,7 +8,7 @@
     for testing purposes. It doesn't surve any functional
     purpose. This here, for instance, is just some filler text.
 
-    FIXME (1654): It would be nice if we could run some automated
+    FIXME (#1654): It would be nice if we could run some automated
     tests on this file
 
 "];
diff --git a/src/rustdoc/doc.rs b/src/rustdoc/doc.rs
index 7f4c8aa6988..84d7c8c31fd 100644
--- a/src/rustdoc/doc.rs
+++ b/src/rustdoc/doc.rs
@@ -20,9 +20,9 @@ type section = {
     body: str
 };
 
-// FIXME: We currently give topmod the name of the crate.  There would
-// probably be fewer special cases if the crate had its own name and
-// topmod's name was the empty string. (#2596)
+// FIXME (#2596): We currently give topmod the name of the crate.  There
+// would probably be fewer special cases if the crate had its own name
+// and topmod's name was the empty string.
 type cratedoc = {
     topmod: moddoc,
 };

From a350bea3130c985e9005ddcbf9819c0f811bbd57 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 16:50:45 -0700
Subject: [PATCH 46/50] Fix linker problem in issue 2214 test case

---
 src/test/run-pass/issue-2214.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 src/test/run-pass/issue-2214.rs

diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs
new file mode 100644
index 00000000000..5f06967cf3a
--- /dev/null
+++ b/src/test/run-pass/issue-2214.rs
@@ -0,0 +1,19 @@
+import libc::{c_double, c_int};
+import f64::*;
+
+fn lgamma(n: c_double, value: &mut int) -> c_double {
+  ret m::lgamma(n, value as &mut c_int);
+}
+
+#[link_name = "m"]
+#[abi = "cdecl"]
+native mod m {
+    #[link_name="lgamma_r"] fn lgamma(n: c_double, sign: &mut c_int)
+      -> c_double;
+}
+
+fn main() {
+  let mut y: int = 5;
+  let x: &mut int = &mut y;
+  assert (lgamma(1.0 as c_double, x) == 0.0 as c_double);
+}
\ No newline at end of file

From a06398214a6e2e9a431309e198e00e0f2dfe397d Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 16:58:04 -0700
Subject: [PATCH 47/50] Add test for issue 2467

---
 src/test/compile-fail/issue-2467.rs | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 src/test/compile-fail/issue-2467.rs

diff --git a/src/test/compile-fail/issue-2467.rs b/src/test/compile-fail/issue-2467.rs
new file mode 100644
index 00000000000..2429273e1ec
--- /dev/null
+++ b/src/test/compile-fail/issue-2467.rs
@@ -0,0 +1,6 @@
+enum test { thing = 3u } //! ERROR mismatched types
+//!^ ERROR expected signed integer constant
+fn main() {
+    log(error, thing as int);
+    assert(thing as int == 3);
+}

From cc323d8637c36a8762bebaedad98cc916f4fcc1f Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 17:41:40 -0700
Subject: [PATCH 48/50] Make liveness print out a proper error message for
 moves out of a self field

This was a call to span_bug() before. I'm not sure about the other cases,
but the test case shows that the `vk_self` case can certainly arise with
a bad program, so it should be a span_err() thing and not a span_bug() thing.

Closes #2590
---
 src/rustc/middle/liveness.rs        |  9 ++++++++-
 src/test/compile-fail/issue-2590.rs | 13 +++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
 create mode 100644 src/test/compile-fail/issue-2590.rs

diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs
index cc8b0383e36..9ad4009c513 100644
--- a/src/rustc/middle/liveness.rs
+++ b/src/rustc/middle/liveness.rs
@@ -1669,7 +1669,14 @@ impl check_methods for @liveness {
                     #fmt["illegal move from field `%s`", *name]);
                 ret;
               }
-              vk_local(*) | vk_self | vk_implicit_ret {
+              vk_self {
+                self.tcx.sess.span_err(
+                    move_span,
+                    "illegal move from self (cannot move out of a field of \
+                       self)");
+                ret;
+              }
+              vk_local(*) | vk_implicit_ret {
                 self.tcx.sess.span_bug(
                     move_span,
                     #fmt["illegal reader (%?) for `%?`",
diff --git a/src/test/compile-fail/issue-2590.rs b/src/test/compile-fail/issue-2590.rs
new file mode 100644
index 00000000000..c27fee9f8a8
--- /dev/null
+++ b/src/test/compile-fail/issue-2590.rs
@@ -0,0 +1,13 @@
+import dvec::dvec;
+
+type parser = {
+    tokens: dvec<int>,
+};
+
+impl parser for parser {
+    fn parse() -> [mut int] {
+        dvec::unwrap(self.tokens) //! ERROR illegal move from self
+    }
+}
+
+fn main() {}

From be8a08b2afac770c0b932619419bd08cd0550d85 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 17:54:56 -0700
Subject: [PATCH 49/50] Hopefully make issue 2214 test case work on Windows --
 sigh

---
 src/test/run-pass/issue-2214.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs
index 5f06967cf3a..6795375e869 100644
--- a/src/test/run-pass/issue-2214.rs
+++ b/src/test/run-pass/issue-2214.rs
@@ -8,8 +8,13 @@ fn lgamma(n: c_double, value: &mut int) -> c_double {
 #[link_name = "m"]
 #[abi = "cdecl"]
 native mod m {
+    #[cfg(unix)]
     #[link_name="lgamma_r"] fn lgamma(n: c_double, sign: &mut c_int)
       -> c_double;
+    #[cfg(windows)]
+    #[link_name="__lgamma_r"] fn lgamma(n: c_double,
+                                        sign: &mut c_int) -> c_double;
+
 }
 
 fn main() {

From b8710de5fffdc45c19ccc27ad8ed98c1ee51c025 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Thu, 21 Jun 2012 19:58:52 -0700
Subject: [PATCH 50/50] Add test cases

issue-912 is xfailed. issue-2111 is already fixed, but it's good to
have the test case.
---
 src/test/compile-fail/issue-2111.rs | 11 +++++++++++
 src/test/run-pass/issue-912.rs      |  8 ++++++++
 2 files changed, 19 insertions(+)
 create mode 100644 src/test/compile-fail/issue-2111.rs
 create mode 100644 src/test/run-pass/issue-912.rs

diff --git a/src/test/compile-fail/issue-2111.rs b/src/test/compile-fail/issue-2111.rs
new file mode 100644
index 00000000000..5e289af9f51
--- /dev/null
+++ b/src/test/compile-fail/issue-2111.rs
@@ -0,0 +1,11 @@
+fn foo(a: option<uint>, b: option<uint>) {
+  alt (a,b) { //! ERROR: non-exhaustive patterns: none not covered
+    (some(a), some(b)) if a == b { }
+    (some(_), none) |
+    (none, some(_)) { }
+  }
+}
+
+fn main() {
+  foo(none, none);
+}
\ No newline at end of file
diff --git a/src/test/run-pass/issue-912.rs b/src/test/run-pass/issue-912.rs
new file mode 100644
index 00000000000..77a349b4ec9
--- /dev/null
+++ b/src/test/run-pass/issue-912.rs
@@ -0,0 +1,8 @@
+// xfail-test
+fn find<T>(_f: fn(@T) -> bool, _v: [@T]) {}
+
+fn main() {
+    let x = 10, arr = [];
+    find({|f| f.id == x}, arr);
+    arr += [{id: 20}]; // This assigns a type to arr
+}