about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libextra/fileinput.rs17
-rw-r--r--src/libextra/num/bigint.rs12
-rw-r--r--src/libextra/rc.rs2
-rw-r--r--src/libextra/term.rs4
-rw-r--r--src/libextra/terminfo/parm.rs4
-rw-r--r--src/libextra/treemap.rs10
-rw-r--r--src/libextra/workcache.rs4
-rw-r--r--src/librustc/back/passes.rs6
-rw-r--r--src/librustc/driver/driver.rs1
-rw-r--r--src/librustc/metadata/loader.rs4
-rw-r--r--src/librustc/middle/astencode.rs11
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs91
-rw-r--r--src/librustc/middle/borrowck/gather_loans/lifetime.rs10
-rw-r--r--src/librustc/middle/borrowck/gather_loans/mod.rs129
-rw-r--r--src/librustc/middle/borrowck/gather_loans/restrictions.rs2
-rw-r--r--src/librustc/middle/borrowck/mod.rs6
-rw-r--r--src/librustc/middle/borrowck/move_data.rs18
-rw-r--r--src/librustc/middle/check_match.rs22
-rw-r--r--src/librustc/middle/const_eval.rs1
-rw-r--r--src/librustc/middle/dataflow.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs49
-rw-r--r--src/librustc/middle/moves.rs39
-rw-r--r--src/librustc/middle/trans/_match.rs329
-rw-r--r--src/librustc/middle/trans/base.rs294
-rw-r--r--src/librustc/middle/trans/build.rs10
-rw-r--r--src/librustc/middle/trans/cabi.rs4
-rw-r--r--src/librustc/middle/trans/callee.rs18
-rw-r--r--src/librustc/middle/trans/closure.rs2
-rw-r--r--src/librustc/middle/trans/common.rs4
-rw-r--r--src/librustc/middle/trans/context.rs4
-rw-r--r--src/librustc/middle/trans/controlflow.rs3
-rw-r--r--src/librustc/middle/trans/datum.rs26
-rw-r--r--src/librustc/middle/trans/expr.rs66
-rw-r--r--src/librustc/middle/trans/foreign.rs7
-rw-r--r--src/librustc/middle/trans/glue.rs2
-rw-r--r--src/librustc/middle/trans/meth.rs3
-rw-r--r--src/librustc/middle/trans/reflect.rs2
-rw-r--r--src/librustc/middle/trans/tvec.rs4
-rw-r--r--src/librustc/middle/trans/write_guard.rs5
-rw-r--r--src/librustc/middle/typeck/check/_match.rs20
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs5
-rw-r--r--src/librustc/middle/typeck/coherence.rs4
-rw-r--r--src/librustpkg/package_source.rs2
-rw-r--r--src/librustpkg/path_util.rs12
-rw-r--r--src/librustpkg/util.rs6
-rw-r--r--src/libstd/ptr.rs50
-rw-r--r--src/libstd/run.rs22
-rw-r--r--src/libstd/vec.rs136
-rw-r--r--src/libsyntax/ext/deriving/generic.rs36
-rw-r--r--src/libsyntax/ext/pipes/pipec.rs2
-rw-r--r--src/libsyntax/ext/pipes/proto.rs4
-rw-r--r--src/libsyntax/parse/parser.rs2
-rw-r--r--src/libsyntax/print/pprust.rs56
-rw-r--r--src/rt/boxed_region.cpp4
-rw-r--r--src/test/bench/shootout-k-nucleotide-pipes.rs4
-rw-r--r--src/test/compile-fail/borrowck-move-in-irrefut-pat.rs16
-rw-r--r--src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs22
-rw-r--r--src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs22
-rw-r--r--src/test/compile-fail/borrowck-move-out-of-vec-tail.rs2
-rw-r--r--src/test/compile-fail/borrowck-vec-pattern-nesting.rs37
-rw-r--r--src/test/compile-fail/regions-ref-in-fn-arg.rs11
-rw-r--r--src/test/run-pass-fulldeps/qquote.rs2
-rw-r--r--src/test/run-pass/borrowck-newtype-issue-2573.rs32
-rw-r--r--src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs6
-rw-r--r--src/test/run-pass/func-arg-incomplete-pattern.rs20
-rw-r--r--src/test/run-pass/func-arg-ref-pattern.rs24
-rw-r--r--src/test/run-pass/func-arg-wild-pattern.rs10
-rw-r--r--src/test/run-pass/let-destruct-ref.rs5
-rw-r--r--src/test/run-pass/match-drop-strs-issue-4541.rs27
-rw-r--r--src/test/run-pass/match-pattern-drop.rs4
-rw-r--r--src/test/run-pass/reflect-visit-type.rs4
-rw-r--r--src/test/run-pass/vec-tail-matching.rs2
72 files changed, 1141 insertions, 697 deletions
diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs
index f91260f4752..27c8051afac 100644
--- a/src/libextra/fileinput.rs
+++ b/src/libextra/fileinput.rs
@@ -418,8 +418,8 @@ mod test {
     fn make_file(path : &Path, contents: &[~str]) {
         let file = io::file_writer(path, [io::Create, io::Truncate]).get();
 
-        for contents.iter().advance |&str| {
-            file.write_str(str);
+        for contents.iter().advance |str| {
+            file.write_str(*str);
             file.write_char('\n');
         }
     }
@@ -445,7 +445,7 @@ mod test {
             |i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true);
 
         // 3 files containing 0\n, 1\n, and 2\n respectively
-        for filenames.iter().enumerate().advance |(i, &filename)| {
+        for filenames.iter().enumerate().advance |(i, filename)| {
             make_file(filename.get_ref(), [fmt!("%u", i)]);
         }
 
@@ -475,7 +475,7 @@ mod test {
             |i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true);
 
         // 3 files containing 1\n, 2\n, and 3\n respectively
-        for filenames.iter().enumerate().advance |(i, &filename)| {
+        for filenames.iter().enumerate().advance |(i, filename)| {
             make_file(filename.get_ref(), [fmt!("%u", i)]);
         }
 
@@ -495,10 +495,11 @@ mod test {
             3,
             |i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true);
 
-        for filenames.iter().enumerate().advance |(i, &filename)| {
+        for filenames.iter().enumerate().advance |(i, filename)| {
             let contents =
                 vec::from_fn(3, |j| fmt!("%u %u", i, j));
             make_file(filename.get_ref(), contents);
+            debug!("contents=%?", contents);
             all_lines.push_all(contents);
         }
 
@@ -515,7 +516,7 @@ mod test {
             3,
             |i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true);
 
-        for filenames.iter().enumerate().advance |(i, &filename)| {
+        for filenames.iter().enumerate().advance |(i, filename)| {
             let contents =
                 vec::from_fn(3, |j| fmt!("%u %u", i, j + 1));
             make_file(filename.get_ref(), contents);
@@ -579,10 +580,10 @@ mod test {
             3,
             |i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true);
 
-        for filenames.iter().enumerate().advance |(i, &filename)| {
+        for filenames.iter().enumerate().advance |(i, filename)| {
             let contents =
                 vec::from_fn(3, |j| fmt!("%u %u", i, j + 1));
-            make_file(&filename.get(), contents);
+            make_file(filename.get_ref(), contents);
         }
 
         let in = FileInput::from_vec(filenames);
diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs
index a0b95924e09..5867b13f556 100644
--- a/src/libextra/num/bigint.rs
+++ b/src/libextra/num/bigint.rs
@@ -1571,10 +1571,10 @@ mod biguint_tests {
     fn test_to_str_radix() {
         let r = to_str_pairs();
         for r.iter().advance |num_pair| {
-            let &(n, rs) = num_pair;
+            let &(ref n, ref rs) = num_pair;
             for rs.iter().advance |str_pair| {
-                let &(radix, str) = str_pair;
-                assert_eq!(n.to_str_radix(radix), str);
+                let &(ref radix, ref str) = str_pair;
+                assert_eq!(&n.to_str_radix(*radix), str);
             }
         }
     }
@@ -1583,10 +1583,10 @@ mod biguint_tests {
     fn test_from_str_radix() {
         let r = to_str_pairs();
         for r.iter().advance |num_pair| {
-            let &(n, rs) = num_pair;
+            let &(ref n, ref rs) = num_pair;
             for rs.iter().advance |str_pair| {
-                let &(radix, str) = str_pair;
-                assert_eq!(&n, &FromStrRadix::from_str_radix(str, radix).get());
+                let &(ref radix, ref str) = str_pair;
+                assert_eq!(n, &FromStrRadix::from_str_radix(*str, *radix).get());
             }
         }
 
diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs
index 86080b343c7..7cc8bca8910 100644
--- a/src/libextra/rc.rs
+++ b/src/libextra/rc.rs
@@ -73,7 +73,7 @@ impl<T> Drop for Rc<T> {
             if self.ptr.is_not_null() {
                 (*self.ptr).count -= 1;
                 if (*self.ptr).count == 0 {
-                    ptr::replace_ptr(self.ptr, intrinsics::uninit());
+                    ptr::read_ptr(self.ptr);
                     free(self.ptr as *c_void)
                 }
             }
diff --git a/src/libextra/term.rs b/src/libextra/term.rs
index 55626622775..cd226e2ad32 100644
--- a/src/libextra/term.rs
+++ b/src/libextra/term.rs
@@ -119,8 +119,8 @@ impl Terminal {
     pub fn reset(&self) {
         let mut vars = Variables::new();
         let s = do self.ti.strings.find_equiv(&("op"))
-                       .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| {
-                           expand(op, [], &mut vars)
+                       .map_consume_default(Err(~"can't find terminfo capability `op`")) |op| {
+                           expand(copy *op, [], &mut vars)
                        };
         if s.is_ok() {
             self.out.write(s.unwrap());
diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs
index b7d21ea0ee3..f25d192cc0a 100644
--- a/src/libextra/terminfo/parm.rs
+++ b/src/libextra/terminfo/parm.rs
@@ -81,8 +81,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
 
     // Copy parameters into a local vector for mutability
     let mut mparams = [Number(0), ..9];
-    for mparams.mut_iter().zip(params.iter()).advance |(dst, &src)| {
-        *dst = src;
+    for mparams.mut_iter().zip(params.iter()).advance |(dst, src)| {
+        *dst = copy *src;
     }
 
     for cap.iter().transform(|&x| x).advance |c| {
diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs
index a5f7479d41a..f2dea8b9bba 100644
--- a/src/libextra/treemap.rs
+++ b/src/libextra/treemap.rs
@@ -773,15 +773,15 @@ mod test_treemap {
                                             map: &TreeMap<K, V>) {
         assert_eq!(ctrl.is_empty(), map.is_empty());
         for ctrl.iter().advance |x| {
-            let &(k, v) = x;
-            assert!(map.find(&k).unwrap() == &v)
+            let &(ref k, ref v) = x;
+            assert!(map.find(k).unwrap() == v)
         }
         for map.iter().advance |(map_k, map_v)| {
             let mut found = false;
             for ctrl.iter().advance |x| {
-                let &(ctrl_k, ctrl_v) = x;
-                if *map_k == ctrl_k {
-                    assert!(*map_v == ctrl_v);
+                let &(ref ctrl_k, ref ctrl_v) = x;
+                if *map_k == *ctrl_k {
+                    assert!(*map_v == *ctrl_v);
                     found = true;
                     break;
                 }
diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs
index 503bd05b733..e7bec2fbd8d 100644
--- a/src/libextra/workcache.rs
+++ b/src/libextra/workcache.rs
@@ -157,8 +157,8 @@ impl<D:Decoder> Decodable<D> for WorkMap {
     fn decode(d: &mut D) -> WorkMap {
         let v : ~[(WorkKey,~str)] = Decodable::decode(d);
         let mut w = WorkMap::new();
-        for v.iter().advance |&(k, v)| {
-            w.insert(copy k, copy v);
+        for v.iter().advance |pair| {
+            w.insert(pair.first(), pair.second());
         }
         w
     }
diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs
index c1192707c1c..f9dc88074d3 100644
--- a/src/librustc/back/passes.rs
+++ b/src/librustc/back/passes.rs
@@ -165,10 +165,10 @@ pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
 }
 
 pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
-    for pass_list.iter().advance |&nm| {
-        match create_pass(nm) {
+    for pass_list.iter().advance |nm| {
+        match create_pass(*nm) {
             Some(p) => pm.add_pass(p),
-            None    => sess.warn(fmt!("Unknown pass %s", nm))
+            None    => sess.warn(fmt!("Unknown pass %s", *nm))
         }
     }
 }
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 3c507547448..e8ef95b811e 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -314,7 +314,6 @@ pub fn compile_rest(sess: Session,
             method_map: method_map,
             vtable_map: vtable_map,
             write_guard_map: write_guard_map,
-            moves_map: moves_map,
             capture_map: capture_map
         };
 
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 31577e47267..9aefb8fdb55 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -127,7 +127,9 @@ fn find_library_crate_aux(
             cx.diag.span_err(
                     cx.span, fmt!("multiple matching crates for `%s`", crate_name));
                 cx.diag.handler().note("candidates:");
-                for matches.iter().advance |&(ident, data)| {
+                for matches.iter().advance |pair| {
+                    let ident = pair.first();
+                    let data = pair.second();
                     cx.diag.handler().note(fmt!("path: %s", ident));
                     let attrs = decoder::get_crate_attributes(data);
                     note_linkage_attrs(cx.intr, cx.diag, attrs);
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 72b6f8e1c80..7412eba1156 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -53,7 +53,6 @@ pub struct Maps {
     method_map: middle::typeck::method_map,
     vtable_map: middle::typeck::vtable_map,
     write_guard_map: middle::borrowck::write_guard_map,
-    moves_map: middle::moves::MovesMap,
     capture_map: middle::moves::CaptureMap,
 }
 
@@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         }
     }
 
-    if maps.moves_map.contains(&id) {
-        do ebml_w.tag(c::tag_table_moves_map) |ebml_w| {
-            ebml_w.id(id);
-        }
-    }
-
     {
         let r = maps.capture_map.find(&id);
         for r.iter().advance |&cap_vars| {
@@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
                 xcx.dcx.tcx.sess.bug(
                     fmt!("unknown tag found in side tables: %x", tag));
             }
-            Some(value) => if value == c::tag_table_moves_map {
-                dcx.maps.moves_map.insert(id);
-            } else {
+            Some(value) => {
                 let val_doc = entry_doc.get(c::tag_table_val as uint);
                 let mut val_dsr = reader::Decoder(val_doc);
                 let val_dsr = &mut val_dsr;
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index b2e303d40ee..a455bdc436c 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -65,7 +65,7 @@ pub fn check_loans(bccx: @BorrowckCtxt,
 
 enum MoveError {
     MoveOk,
-    MoveWhileBorrowed(/*move*/@LoanPath, /*loan*/@LoanPath, /*loan*/span)
+    MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span)
 }
 
 impl<'self> CheckLoanCtxt<'self> {
@@ -348,7 +348,7 @@ impl<'self> CheckLoanCtxt<'self> {
                         cmt = b;
                     }
 
-                    mc::cat_rvalue |
+                    mc::cat_rvalue(*) |
                     mc::cat_static_item |
                     mc::cat_implicit_self |
                     mc::cat_copied_upvar(*) |
@@ -547,45 +547,50 @@ impl<'self> CheckLoanCtxt<'self> {
                  self.bccx.loan_path_to_str(loan_path)));
     }
 
-    pub fn check_move_out_from_expr(&self, ex: @ast::expr) {
-        match ex.node {
-            ast::expr_paren(*) => {
-                /* In the case of an expr_paren(), the expression inside
-                 * the parens will also be marked as being moved.  Ignore
-                 * the parents then so as not to report duplicate errors. */
+    fn check_move_out_from_expr(&self, expr: @ast::expr) {
+        match expr.node {
+            ast::expr_fn_block(*) => {
+                // moves due to capture clauses are checked
+                // in `check_loans_in_fn`, so that we can
+                // give a better error message
             }
             _ => {
-                let cmt = self.bccx.cat_expr(ex);
-                match self.analyze_move_out_from_cmt(cmt) {
-                    MoveOk => {}
-                    MoveWhileBorrowed(move_path, loan_path, loan_span) => {
-                        self.bccx.span_err(
-                            cmt.span,
-                            fmt!("cannot move out of `%s` \
-                                  because it is borrowed",
-                                 self.bccx.loan_path_to_str(move_path)));
-                        self.bccx.span_note(
-                            loan_span,
-                            fmt!("borrow of `%s` occurs here",
-                                 self.bccx.loan_path_to_str(loan_path)));
-                    }
+                self.check_move_out_from_id(expr.id, expr.span)
+            }
+        }
+    }
+
+    fn check_move_out_from_id(&self, id: ast::node_id, span: span) {
+        for self.move_data.each_path_moved_by(id) |_, move_path| {
+            match self.analyze_move_out_from(id, move_path) {
+                MoveOk => {}
+                MoveWhileBorrowed(loan_path, loan_span) => {
+                    self.bccx.span_err(
+                        span,
+                        fmt!("cannot move out of `%s` \
+                              because it is borrowed",
+                             self.bccx.loan_path_to_str(move_path)));
+                    self.bccx.span_note(
+                        loan_span,
+                        fmt!("borrow of `%s` occurs here",
+                             self.bccx.loan_path_to_str(loan_path)));
                 }
             }
         }
     }
 
-    pub fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError {
-        debug!("analyze_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx()));
+    pub fn analyze_move_out_from(&self,
+                                 expr_id: ast::node_id,
+                                 move_path: @LoanPath) -> MoveError {
+        debug!("analyze_move_out_from(expr_id=%?, move_path=%s)",
+               expr_id, move_path.repr(self.tcx()));
 
         // FIXME(#4384) inadequare if/when we permit `move a.b`
 
         // check for a conflicting loan:
-        let r = opt_loan_path(cmt);
-        for r.iter().advance |&lp| {
-            for self.each_in_scope_restriction(cmt.id, lp) |loan, _| {
-                // Any restriction prevents moves.
-                return MoveWhileBorrowed(lp, loan.loan_path, loan.span);
-            }
+        for self.each_in_scope_restriction(expr_id, move_path) |loan, _| {
+            // Any restriction prevents moves.
+            return MoveWhileBorrowed(loan.loan_path, loan.span);
         }
 
         MoveOk
@@ -652,13 +657,11 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind,
                                  closure_id: ast::node_id,
                                  cap_var: &moves::CaptureVar) {
             let var_id = ast_util::def_id_of_def(cap_var.def).node;
-            let ty = ty::node_id_to_type(this.tcx(), var_id);
-            let cmt = this.bccx.cat_def(closure_id, cap_var.span,
-                                        ty, cap_var.def);
-            let move_err = this.analyze_move_out_from_cmt(cmt);
+            let move_path = @LpVar(var_id);
+            let move_err = this.analyze_move_out_from(closure_id, move_path);
             match move_err {
                 MoveOk => {}
-                MoveWhileBorrowed(move_path, loan_path, loan_span) => {
+                MoveWhileBorrowed(loan_path, loan_span) => {
                     this.bccx.span_err(
                         cap_var.span,
                         fmt!("cannot move `%s` into closure \
@@ -689,10 +692,7 @@ fn check_loans_in_expr<'a>(expr: @ast::expr,
            expr.repr(this.tcx()));
 
     this.check_for_conflicting_loans(expr.id);
-
-    if this.bccx.moves_map.contains(&expr.id) {
-        this.check_move_out_from_expr(expr);
-    }
+    this.check_move_out_from_expr(expr);
 
     match expr.node {
       ast::expr_self |
@@ -742,18 +742,7 @@ fn check_loans_in_pat<'a>(pat: @ast::pat,
                                        visit::vt<@mut CheckLoanCtxt<'a>>))
 {
     this.check_for_conflicting_loans(pat.id);
-
-    // Note: moves out of pattern bindings are not checked by
-    // the borrow checker, at least not directly.  What happens
-    // is that if there are any moved bindings, the discriminant
-    // will be considered a move, and this will be checked as
-    // normal.  Then, in `middle::check_match`, we will check
-    // that no move occurs in a binding that is underneath an
-    // `@` or `&`.  Together these give the same guarantees as
-    // `check_move_out_from_expr()` without requiring us to
-    // rewalk the patterns and rebuild the pattern
-    // categorizations.
-
+    this.check_move_out_from_id(pat.id, pat.span);
     visit::visit_pat(pat, (this, vt));
 }
 
diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs
index 05fc139305c..5d91916d004 100644
--- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs
@@ -67,7 +67,7 @@ impl GuaranteeLifetimeContext {
         //! Main routine. Walks down `cmt` until we find the "guarantor".
 
         match cmt.cat {
-            mc::cat_rvalue |
+            mc::cat_rvalue(*) |
             mc::cat_implicit_self |
             mc::cat_copied_upvar(*) |                  // L-Local
             mc::cat_local(*) |                         // L-Local
@@ -179,7 +179,7 @@ impl GuaranteeLifetimeContext {
         //! lvalue.
 
         cmt.mutbl.is_immutable() || match cmt.guarantor().cat {
-            mc::cat_rvalue => true,
+            mc::cat_rvalue(*) => true,
             _ => false
         }
     }
@@ -299,7 +299,7 @@ impl GuaranteeLifetimeContext {
             mc::cat_arg(id) => {
                 self.bccx.moved_variables_set.contains(&id)
             }
-            mc::cat_rvalue |
+            mc::cat_rvalue(*) |
             mc::cat_static_item |
             mc::cat_implicit_self |
             mc::cat_copied_upvar(*) |
@@ -325,8 +325,8 @@ impl GuaranteeLifetimeContext {
         // See the SCOPE(LV) function in doc.rs
 
         match cmt.cat {
-            mc::cat_rvalue => {
-                ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id))
+            mc::cat_rvalue(cleanup_scope_id) => {
+                ty::re_scope(cleanup_scope_id)
             }
             mc::cat_implicit_self |
             mc::cat_copied_upvar(_) => {
diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs
index 26fa4924ccb..23451e0f36e 100644
--- a/src/librustc/middle/borrowck/gather_loans/mod.rs
+++ b/src/librustc/middle/borrowck/gather_loans/mod.rs
@@ -73,6 +73,7 @@ struct GatherLoanCtxt {
 }
 
 pub fn gather_loans(bccx: @BorrowckCtxt,
+                    decl: &ast::fn_decl,
                     body: &ast::blk)
                     -> (id_range, @mut ~[Loan], @mut move_data::MoveData) {
     let glcx = @mut GatherLoanCtxt {
@@ -83,6 +84,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt,
         repeating_ids: ~[body.node.id],
         move_data: @mut MoveData::new()
     };
+    glcx.gather_fn_arg_patterns(decl, body);
     let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr,
                                           visit_block: gather_loans_in_block,
                                           visit_fn: gather_loans_in_fn,
@@ -124,6 +126,7 @@ fn gather_loans_in_fn(fk: &visit::fn_kind,
             this.push_repeating_id(body.node.id);
             visit::visit_fn(fk, decl, body, sp, id, (this, v));
             this.pop_repeating_id(body.node.id);
+            this.gather_fn_arg_patterns(decl, body);
         }
     }
 }
@@ -138,26 +141,33 @@ fn gather_loans_in_block(blk: &ast::blk,
 fn gather_loans_in_local(local: @ast::local,
                          (this, vt): (@mut GatherLoanCtxt,
                                       visit::vt<@mut GatherLoanCtxt>)) {
-    if local.node.init.is_none() {
-        // Variable declarations without initializers are considered "moves":
-        let tcx = this.bccx.tcx;
-        do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| {
-            gather_moves::gather_decl(this.bccx,
-                                      this.move_data,
-                                      id,
-                                      span,
-                                      id);
+    match local.node.init {
+        None => {
+            // Variable declarations without initializers are considered "moves":
+            let tcx = this.bccx.tcx;
+            do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+                |_, id, span, _| {
+                gather_moves::gather_decl(this.bccx,
+                                          this.move_data,
+                                          id,
+                                          span,
+                                          id);
+            }
         }
-    } else {
-        // Variable declarations with initializers are considered "assigns":
-        let tcx = this.bccx.tcx;
-        do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| {
-            gather_moves::gather_assignment(this.bccx,
-                                            this.move_data,
-                                            id,
-                                            span,
-                                            @LpVar(id),
-                                            id);
+        Some(init) => {
+            // Variable declarations with initializers are considered "assigns":
+            let tcx = this.bccx.tcx;
+            do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+                |_, id, span, _| {
+                gather_moves::gather_assignment(this.bccx,
+                                                this.move_data,
+                                                id,
+                                                span,
+                                                @LpVar(id),
+                                                id);
+            }
+            let init_cmt = this.bccx.cat_expr(init);
+            this.gather_pat(init_cmt, local.node.pat, None);
         }
     }
 
@@ -230,7 +240,7 @@ fn gather_loans_in_expr(ex: @ast::expr,
         let cmt = this.bccx.cat_expr(ex_v);
         for arms.iter().advance |arm| {
             for arm.pats.iter().advance |pat| {
-                this.gather_pat(cmt, *pat, arm.body.node.id, ex.id);
+                this.gather_pat(cmt, *pat, Some((arm.body.node.id, ex.id)));
             }
         }
         visit::visit_expr(ex, (this, vt));
@@ -596,11 +606,40 @@ impl GatherLoanCtxt {
         }
     }
 
-    pub fn gather_pat(&mut self,
-                      discr_cmt: mc::cmt,
-                      root_pat: @ast::pat,
-                      arm_body_id: ast::node_id,
-                      match_id: ast::node_id) {
+    fn gather_fn_arg_patterns(&mut self,
+                              decl: &ast::fn_decl,
+                              body: &ast::blk) {
+        /*!
+         * Walks the patterns for fn arguments, checking that they
+         * do not attempt illegal moves or create refs that outlive
+         * the arguments themselves. Just a shallow wrapper around
+         * `gather_pat()`.
+         */
+
+        let mc_ctxt = self.bccx.mc_ctxt();
+        for decl.inputs.iter().advance |arg| {
+            let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id);
+
+            let arg_cmt = mc_ctxt.cat_rvalue(
+                arg.id,
+                arg.pat.span,
+                body.node.id, // Arguments live only as long as the fn body.
+                arg_ty);
+
+            self.gather_pat(arg_cmt, arg.pat, None);
+        }
+    }
+
+    fn gather_pat(&mut self,
+                  discr_cmt: mc::cmt,
+                  root_pat: @ast::pat,
+                  arm_match_ids: Option<(ast::node_id, ast::node_id)>) {
+        /*!
+         * Walks patterns, examining the bindings to determine if they
+         * cause borrows (`ref` bindings, vector patterns) or
+         * moves (non-`ref` bindings with linear type).
+         */
+
         do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| {
             match pat.node {
               ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => {
@@ -621,15 +660,19 @@ impl GatherLoanCtxt {
                     // with a cat_discr() node.  There is a detailed
                     // discussion of the function of this node in
                     // `lifetime.rs`:
-                    let arm_scope = ty::re_scope(arm_body_id);
-                    if self.bccx.is_subregion_of(scope_r, arm_scope) {
-                        let cmt_discr = self.bccx.cat_discr(cmt, match_id);
-                        self.guarantee_valid(pat.id, pat.span,
-                                             cmt_discr, mutbl, scope_r);
-                    } else {
-                        self.guarantee_valid(pat.id, pat.span,
-                                             cmt, mutbl, scope_r);
-                    }
+                    let cmt_discr = match arm_match_ids {
+                        None => cmt,
+                        Some((arm_id, match_id)) => {
+                            let arm_scope = ty::re_scope(arm_id);
+                            if self.bccx.is_subregion_of(scope_r, arm_scope) {
+                                self.bccx.cat_discr(cmt, match_id)
+                            } else {
+                                cmt
+                            }
+                        }
+                    };
+                    self.guarantee_valid(pat.id, pat.span,
+                                         cmt_discr, mutbl, scope_r);
                   }
                   ast::bind_infer => {
                       // No borrows here, but there may be moves
@@ -652,6 +695,24 @@ impl GatherLoanCtxt {
                       self.vec_slice_info(slice_pat, slice_ty);
                   let mcx = self.bccx.mc_ctxt();
                   let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
+
+                  // Note: We declare here that the borrow occurs upon
+                  // entering the `[...]` pattern. This implies that
+                  // something like `[a, ..b]` where `a` is a move is
+                  // illegal, because the borrow is already in effect.
+                  // In fact such a move would be safe-ish, but it
+                  // effectively *requires* that we use the nulling
+                  // out semantics to indicate when a value has been
+                  // moved, which we are trying to move away from.
+                  // Otherwise, how can we indicate that the first
+                  // element in the vector has been moved?
+                  // Eventually, we could perhaps modify this rule to
+                  // permit `[..a, b]` where `b` is a move, because in
+                  // that case we can adjust the length of the
+                  // original vec accordingly, but we'd have to make
+                  // trans do the right thing, and it would only work
+                  // for `~` vectors. It seems simpler to just require
+                  // that people call `vec.pop()` or `vec.unshift()`.
                   self.guarantee_valid(pat.id, pat.span,
                                        cmt_index, slice_mutbl, slice_r);
               }
diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs
index d5377aeb618..e568da5eedf 100644
--- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs
@@ -64,7 +64,7 @@ impl RestrictionsContext {
         }
 
         match cmt.cat {
-            mc::cat_rvalue => {
+            mc::cat_rvalue(*) => {
                 // Effectively, rvalues are stored into a
                 // non-aliasable temporary on the stack. Since they
                 // are inherently non-aliasable, they can only be
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 2e3813f57e0..47d35d73df0 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -124,7 +124,7 @@ fn borrowck_fn(fk: &visit::fn_kind,
 
             // Check the body of fn items.
             let (id_range, all_loans, move_data) =
-                gather_loans::gather_loans(this, body);
+                gather_loans::gather_loans(this, decl, body);
             let mut loan_dfcx =
                 DataFlowContext::new(this.tcx,
                                      this.method_map,
@@ -264,7 +264,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
     //! traverses the CMT.
 
     match cmt.cat {
-        mc::cat_rvalue |
+        mc::cat_rvalue(*) |
         mc::cat_static_item |
         mc::cat_copied_upvar(_) |
         mc::cat_implicit_self => {
@@ -485,7 +485,7 @@ impl BorrowckCtxt {
 
     pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt {
         mc::mem_categorization_ctxt {tcx: self.tcx,
-                                 method_map: self.method_map}
+                                     method_map: self.method_map}
     }
 
     pub fn cat_pattern(&self,
diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs
index 73adade7a5d..7ec1ff3c628 100644
--- a/src/librustc/middle/borrowck/move_data.rs
+++ b/src/librustc/middle/borrowck/move_data.rs
@@ -474,6 +474,24 @@ impl FlowedMoveData {
         }
     }
 
+    pub fn each_path_moved_by(&self,
+                              id: ast::node_id,
+                              f: &fn(&Move, @LoanPath) -> bool)
+                              -> bool {
+        /*!
+         * Iterates through each path moved by `id`
+         */
+
+        for self.dfcx_moves.each_gen_bit_frozen(id) |index| {
+            let move = &self.move_data.moves[index];
+            let moved_path = move.path;
+            if !f(move, self.move_data.path(moved_path).loan_path) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     pub fn each_move_of(&self,
                         id: ast::node_id,
                         loan_path: @LoanPath,
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 0baeb8ce57c..02f7294ffcd 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -49,23 +49,13 @@ pub fn check_crate(tcx: ty::ctxt,
     tcx.sess.abort_if_errors();
 }
 
-pub fn expr_is_non_moving_lvalue(cx: &MatchCheckCtxt, expr: &expr) -> bool {
-    if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) {
-        return false;
-    }
-
-    !cx.moves_map.contains(&expr.id)
-}
-
 pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) {
     visit::visit_expr(ex, (s, v));
     match ex.node {
       expr_match(scrut, ref arms) => {
         // First, check legality of move bindings.
-        let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex);
         for arms.iter().advance |arm| {
             check_legality_of_move_bindings(cx,
-                                            is_non_moving_lvalue,
                                             arm.guard.is_some(),
                                             arm.pats);
         }
@@ -758,11 +748,7 @@ pub fn check_local(cx: &MatchCheckCtxt,
     }
 
     // Check legality of move bindings.
-    let is_lvalue = match loc.node.init {
-        Some(init) => expr_is_non_moving_lvalue(cx, init),
-        None => true
-    };
-    check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]);
+    check_legality_of_move_bindings(cx, false, [ loc.node.pat ]);
 }
 
 pub fn check_fn(cx: &MatchCheckCtxt,
@@ -821,7 +807,6 @@ pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool {
 // Legality of move bindings checking
 
 pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
-                                       is_lvalue: bool,
                                        has_guard: bool,
                                        pats: &[@pat]) {
     let tcx = cx.tcx;
@@ -861,11 +846,6 @@ pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
             tcx.sess.span_note(
                 by_ref_span.get(),
                 "by-ref binding occurs here");
-        } else if is_lvalue {
-            tcx.sess.span_err(
-                p.span,
-                "cannot bind by-move when \
-                 matching an lvalue");
         }
     };
 
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index bf91b6771dc..af39dea6d79 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -187,7 +187,6 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
             method_map: @mut HashMap::new(),
             vtable_map: @mut HashMap::new(),
             write_guard_map: @mut HashSet::new(),
-            moves_map: @mut HashSet::new(),
             capture_map: @mut HashMap::new()
         };
         match csearch::maybe_get_item_ast(tcx, def_id,
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index e054b84984d..ec375eaba0e 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -422,8 +422,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
                  loop_scopes: &mut ~[LoopScope]) {
         match decl.node {
             ast::decl_local(local) => {
-                self.walk_pat(local.node.pat, in_out, loop_scopes);
                 self.walk_opt_expr(local.node.init, in_out, loop_scopes);
+                self.walk_pat(local.node.pat, in_out, loop_scopes);
             }
 
             ast::decl_item(_) => {}
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index fd36858ba68..ac7805146e4 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -60,7 +60,7 @@ use syntax::print::pprust;
 
 #[deriving(Eq)]
 pub enum categorization {
-    cat_rvalue,                        // result of eval'ing some misc expr
+    cat_rvalue(ast::node_id),          // temporary val, argument is its scope
     cat_static_item,
     cat_implicit_self,
     cat_copied_upvar(CopiedUpvar),     // upvar copied into @fn or ~fn env
@@ -350,7 +350,7 @@ impl mem_categorization_ctxt {
                 // Convert a bare fn to a closure by adding NULL env.
                 // Result is an rvalue.
                 let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
-                self.cat_rvalue(expr, expr_ty)
+                self.cat_rvalue_node(expr, expr_ty)
             }
 
             Some(
@@ -360,7 +360,7 @@ impl mem_categorization_ctxt {
                 // Equivalent to &*expr or something similar.
                 // Result is an rvalue.
                 let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
-                self.cat_rvalue(expr, expr_ty)
+                self.cat_rvalue_node(expr, expr_ty)
             }
 
             Some(
@@ -390,7 +390,7 @@ impl mem_categorization_ctxt {
         match expr.node {
           ast::expr_unary(_, ast::deref, e_base) => {
             if self.method_map.contains_key(&expr.id) {
-                return self.cat_rvalue(expr, expr_ty);
+                return self.cat_rvalue_node(expr, expr_ty);
             }
 
             let base_cmt = self.cat_expr(e_base);
@@ -408,7 +408,7 @@ impl mem_categorization_ctxt {
 
           ast::expr_index(_, base, _) => {
             if self.method_map.contains_key(&expr.id) {
-                return self.cat_rvalue(expr, expr_ty);
+                return self.cat_rvalue_node(expr, expr_ty);
             }
 
             let base_cmt = self.cat_expr(base);
@@ -433,7 +433,7 @@ impl mem_categorization_ctxt {
           ast::expr_match(*) | ast::expr_lit(*) | ast::expr_break(*) |
           ast::expr_mac(*) | ast::expr_again(*) | ast::expr_struct(*) |
           ast::expr_repeat(*) | ast::expr_inline_asm(*) => {
-            return self.cat_rvalue(expr, expr_ty);
+            return self.cat_rvalue_node(expr, expr_ty);
           }
         }
     }
@@ -577,11 +577,24 @@ impl mem_categorization_ctxt {
         }
     }
 
-    pub fn cat_rvalue<N:ast_node>(&self, elt: N, expr_ty: ty::t) -> cmt {
+    pub fn cat_rvalue_node<N:ast_node>(&self,
+                                       node: N,
+                                       expr_ty: ty::t) -> cmt {
+        self.cat_rvalue(node.id(),
+                        node.span(),
+                        self.tcx.region_maps.cleanup_scope(node.id()),
+                        expr_ty)
+    }
+
+    pub fn cat_rvalue(&self,
+                      cmt_id: ast::node_id,
+                      span: span,
+                      cleanup_scope_id: ast::node_id,
+                      expr_ty: ty::t) -> cmt {
         @cmt_ {
-            id:elt.id(),
-            span:elt.span(),
-            cat:cat_rvalue,
+            id:cmt_id,
+            span:span,
+            cat:cat_rvalue(cleanup_scope_id),
             mutbl:McDeclared,
             ty:expr_ty
         }
@@ -970,7 +983,7 @@ impl mem_categorization_ctxt {
               }
               for slice.iter().advance |&slice_pat| {
                   let slice_ty = self.pat_ty(slice_pat);
-                  let slice_cmt = self.cat_rvalue(pat, slice_ty);
+                  let slice_cmt = self.cat_rvalue_node(pat, slice_ty);
                   self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y));
               }
               for after.iter().advance |&after_pat| {
@@ -1003,7 +1016,7 @@ impl mem_categorization_ctxt {
           cat_copied_upvar(_) => {
               ~"captured outer variable in a heap closure"
           }
-          cat_rvalue => {
+          cat_rvalue(*) => {
               ~"non-lvalue"
           }
           cat_local(_) => {
@@ -1100,7 +1113,7 @@ impl cmt_ {
         //! determines how long the value in `self` remains live.
 
         match self.cat {
-            cat_rvalue |
+            cat_rvalue(*) |
             cat_static_item |
             cat_implicit_self |
             cat_copied_upvar(*) |
@@ -1187,11 +1200,13 @@ impl Repr for categorization {
         match *self {
             cat_static_item |
             cat_implicit_self |
-            cat_rvalue |
+            cat_rvalue(*) |
             cat_copied_upvar(*) |
             cat_local(*) |
             cat_self(*) |
-            cat_arg(*) => fmt!("%?", *self),
+            cat_arg(*) => {
+                fmt!("%?", *self)
+            }
             cat_deref(cmt, derefs, ptr) => {
                 fmt!("%s->(%s, %u)", cmt.cat.repr(tcx),
                      ptr_sigil(ptr), derefs)
@@ -1205,7 +1220,9 @@ impl Repr for categorization {
                 fmt!("%s->(enum)", cmt.cat.repr(tcx))
             }
             cat_stack_upvar(cmt) |
-            cat_discr(cmt, _) => cmt.cat.repr(tcx)
+            cat_discr(cmt, _) => {
+                cmt.cat.repr(tcx)
+            }
         }
     }
 }
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index f3d4abcdf31..07bdee07c0f 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -193,7 +193,9 @@ pub fn compute_moves(tcx: ty::ctxt,
                      crate: &crate) -> MoveMaps
 {
     let visitor = visit::mk_vt(@visit::Visitor {
+        visit_fn: compute_modes_for_fn,
         visit_expr: compute_modes_for_expr,
+        visit_local: compute_modes_for_local,
         .. *visit::default_visitor()
     });
     let visit_cx = VisitContext {
@@ -220,9 +222,31 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option<node_id> {
     }
 }
 
-// ______________________________________________________________________
+///////////////////////////////////////////////////////////////////////////
 // Expressions
 
+fn compute_modes_for_local<'a>(local: @local,
+                               (cx, v): (VisitContext,
+                                         vt<VisitContext>)) {
+    cx.use_pat(local.node.pat);
+    for local.node.init.iter().advance |&init| {
+        cx.use_expr(init, Read, v);
+    }
+}
+
+fn compute_modes_for_fn(fk: &visit::fn_kind,
+                        decl: &fn_decl,
+                        body: &blk,
+                        span: span,
+                        id: node_id,
+                        (cx, v): (VisitContext,
+                                  vt<VisitContext>)) {
+    for decl.inputs.iter().advance |a| {
+        cx.use_pat(a.pat);
+    }
+    visit::visit_fn(fk, decl, body, span, id, (cx, v));
+}
+
 fn compute_modes_for_expr(expr: @expr,
                           (cx, v): (VisitContext,
                                     vt<VisitContext>))
@@ -522,7 +546,10 @@ impl VisitContext {
                 self.use_expr(base, comp_mode, visitor);
             }
 
-            expr_fn_block(_, ref body) => {
+            expr_fn_block(ref decl, ref body) => {
+                for decl.inputs.iter().advance |a| {
+                    self.use_pat(a.pat);
+                }
                 let cap_vars = self.compute_captures(expr.id);
                 self.move_maps.capture_map.insert(expr.id, cap_vars);
                 self.consume_block(body, visitor);
@@ -580,13 +607,15 @@ impl VisitContext {
          * into itself or not based on its type and annotation.
          */
 
-        do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, _path| {
+        do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| {
             let binding_moves = match bm {
                 bind_by_ref(_) => false,
                 bind_infer => {
                     let pat_ty = ty::node_id_to_type(self.tcx, id);
-                    debug!("pattern %? type is %s",
-                           id, pat_ty.repr(self.tcx));
+                    debug!("pattern %? %s type is %s",
+                           id,
+                           ast_util::path_to_ident(path).repr(self.tcx),
+                           pat_ty.repr(self.tcx));
                     ty::type_moves_by_default(self.tcx, pat_ty)
                 }
             };
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index b7168cbfdec..d5d0cde1ee0 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -268,7 +268,7 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result {
         }
         lit(UnitLikeStructLit(pat_id)) => {
             let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id);
-            let datumblock = datum::scratch_datum(bcx, struct_ty, true);
+            let datumblock = datum::scratch_datum(bcx, struct_ty, "", true);
             return single_result(datumblock.to_result(bcx));
         }
         lit(ConstLit(lit_id)) => {
@@ -316,7 +316,7 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id)
 }
 
 pub enum TransBindingMode {
-    TrByValue(/*ismove:*/ bool, /*llbinding:*/ ValueRef),
+    TrByValue(/*llbinding:*/ ValueRef),
     TrByRef,
 }
 
@@ -927,7 +927,7 @@ pub fn extract_vec_elems(bcx: block,
             ty::mt {ty: vt.unit_ty, mutbl: ast::m_imm},
             ty::vstore_slice(ty::re_static)
         );
-        let scratch = scratch_datum(bcx, slice_ty, false);
+        let scratch = scratch_datum(bcx, slice_ty, "", false);
         Store(bcx, slice_begin,
             GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])
         );
@@ -1095,9 +1095,9 @@ pub fn compare_values(cx: block,
 
     match ty::get(rhs_t).sty {
         ty::ty_estr(ty::vstore_uniq) => {
-            let scratch_lhs = alloca(cx, val_ty(lhs));
+            let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs");
             Store(cx, lhs, scratch_lhs);
-            let scratch_rhs = alloca(cx, val_ty(rhs));
+            let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs");
             Store(cx, rhs, scratch_rhs);
             let did = cx.tcx().lang_items.uniq_str_eq_fn();
             let result = callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None);
@@ -1138,18 +1138,11 @@ fn store_non_ref_bindings(bcx: block,
     let mut bcx = bcx;
     for bindings_map.each_value |&binding_info| {
         match binding_info.trmode {
-            TrByValue(is_move, lldest) => {
+            TrByValue(lldest) => {
                 let llval = Load(bcx, binding_info.llmatch); // get a T*
                 let datum = Datum {val: llval, ty: binding_info.ty,
                                    mode: ByRef(ZeroMem)};
-                bcx = {
-                    if is_move {
-                        datum.move_to(bcx, INIT, lldest)
-                    } else {
-                        datum.copy_to(bcx, INIT, lldest)
-                    }
-                };
-
+                bcx = datum.store_to(bcx, INIT, lldest);
                 do opt_temp_cleanups.mutate |temp_cleanups| {
                     add_clean_temp_mem(bcx, lldest, binding_info.ty);
                     temp_cleanups.push(lldest);
@@ -1181,7 +1174,7 @@ fn insert_lllocals(bcx: block,
         let llval = match binding_info.trmode {
             // By value bindings: use the stack slot that we
             // copied/moved the value into
-            TrByValue(_, lldest) => {
+            TrByValue(lldest) => {
                 if add_cleans {
                     add_clean(bcx, lldest, binding_info.ty);
                 }
@@ -1245,7 +1238,7 @@ pub fn compile_guard(bcx: block,
         let mut bcx = bcx;
         for data.bindings_map.each_value |&binding_info| {
             match binding_info.trmode {
-                TrByValue(_, llval) => {
+                TrByValue(llval) => {
                     bcx = glue::drop_ty(bcx, llval, binding_info.ty);
                 }
                 TrByRef => {}
@@ -1636,12 +1629,12 @@ fn create_bindings_map(bcx: block, pat: @ast::pat) -> BindingsMap {
                 // in this case, the final type of the variable will be T,
                 // but during matching we need to store a *T as explained
                 // above
-                let is_move = ccx.maps.moves_map.contains(&p_id);
-                llmatch = alloca(bcx, llvariable_ty.ptr_to());
-                trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
+                llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
+                trmode = TrByValue(alloca(bcx, llvariable_ty,
+                                          bcx.ident(ident)));
             }
             ast::bind_by_ref(_) => {
-                llmatch = alloca(bcx, llvariable_ty);
+                llmatch = alloca(bcx, llvariable_ty, bcx.ident(ident));
                 trmode = TrByRef;
             }
         };
@@ -1737,53 +1730,205 @@ pub enum IrrefutablePatternBindingMode {
     BindArgument
 }
 
-// Not match-related, but similar to the pattern-munging code above
-pub fn bind_irrefutable_pat(bcx: block,
-                            pat: @ast::pat,
-                            val: ValueRef,
-                            make_copy: bool,
-                            binding_mode: IrrefutablePatternBindingMode)
-                         -> block {
-    let _icx = push_ctxt("match::bind_irrefutable_pat");
-    let ccx = bcx.fcx.ccx;
+pub fn store_local(bcx: block,
+                   pat: @ast::pat,
+                   opt_init_expr: Option<@ast::expr>)
+                               -> block {
+    /*!
+     * Generates code for a local variable declaration like
+     * `let <pat>;` or `let <pat> = <opt_init_expr>`.
+     */
+    let _icx = push_ctxt("match::store_local");
     let mut bcx = bcx;
 
-    // Necessary since bind_irrefutable_pat is called outside trans_match
-    match pat.node {
-        ast::pat_ident(_, _, ref inner) => {
-            if pat_is_variant_or_struct(bcx.tcx().def_map, pat) {
-                return bcx;
+    return match opt_init_expr {
+        Some(init_expr) => {
+            // Optimize the "let x = expr" case. This just writes
+            // the result of evaluating `expr` directly into the alloca
+            // for `x`. Often the general path results in similar or the
+            // same code post-optimization, but not always. In particular,
+            // in unsafe code, you can have expressions like
+            //
+            //    let x = intrinsics::uninit();
+            //
+            // In such cases, the more general path is unsafe, because
+            // it assumes it is matching against a valid value.
+            match simple_identifier(pat) {
+                Some(path) => {
+                    return mk_binding_alloca(
+                        bcx, pat.id, path, BindLocal,
+                        |bcx, _, llval| expr::trans_into(bcx, init_expr,
+                                                         expr::SaveIn(llval)));
+                }
+
+                None => {}
             }
 
-            if make_copy {
-                let binding_ty = node_id_type(bcx, pat.id);
-                let datum = Datum {val: val, ty: binding_ty,
-                                   mode: ByRef(RevokeClean)};
-                let scratch = scratch_datum(bcx, binding_ty, false);
-                datum.copy_to_datum(bcx, INIT, scratch);
-                match binding_mode {
-                    BindLocal => {
-                        bcx.fcx.lllocals.insert(pat.id, scratch.val);
-                    }
-                    BindArgument => {
-                        bcx.fcx.llargs.insert(pat.id, scratch.val);
-                    }
-                }
-                add_clean(bcx, scratch.val, binding_ty);
+            // General path.
+            let init_datum =
+                unpack_datum!(
+                    bcx,
+                    expr::trans_to_datum(bcx, init_expr));
+            if ty::type_is_bot(expr_ty(bcx, init_expr)) {
+                create_dummy_locals(bcx, pat)
             } else {
-                match binding_mode {
-                    BindLocal => {
-                        bcx.fcx.lllocals.insert(pat.id, val);
-                    }
-                    BindArgument => {
-                        bcx.fcx.llargs.insert(pat.id, val);
-                    }
+                if bcx.sess().asm_comments() {
+                    add_comment(bcx, "creating zeroable ref llval");
                 }
+                let llptr = init_datum.to_zeroable_ref_llval(bcx);
+                return bind_irrefutable_pat(bcx, pat, llptr, BindLocal);
+            }
+        }
+        None => {
+            create_dummy_locals(bcx, pat)
+        }
+    };
+
+    fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block {
+        // create dummy memory for the variables if we have no
+        // value to store into them immediately
+        let tcx = bcx.tcx();
+        do pat_bindings(tcx.def_map, pat) |_, p_id, _, path| {
+            bcx = mk_binding_alloca(
+                bcx, p_id, path, BindLocal,
+                |bcx, var_ty, llval| { zero_mem(bcx, llval, var_ty); bcx });
+        }
+        bcx
+    }
+}
+
+pub fn store_arg(mut bcx: block,
+                 pat: @ast::pat,
+                 llval: ValueRef)
+                 -> block {
+    /*!
+     * Generates code for argument patterns like `fn foo(<pat>: T)`.
+     * Creates entries in the `llargs` map for each of the bindings
+     * in `pat`.
+     *
+     * # Arguments
+     *
+     * - `pat` is the argument pattern
+     * - `llval` is a pointer to the argument value (in other words,
+     *   if the argument type is `T`, then `llval` is a `T*`). In some
+     *   cases, this code may zero out the memory `llval` points at.
+     */
+    let _icx = push_ctxt("match::store_arg");
+
+    // We always need to cleanup the argument as we exit the fn scope.
+    // Note that we cannot do it before for fear of a fn like
+    //    fn getaddr(~ref x: ~uint) -> *uint {....}
+    // (From test `run-pass/func-arg-ref-pattern.rs`)
+    let arg_ty = node_id_type(bcx, pat.id);
+    add_clean(bcx, llval, arg_ty);
+
+    match simple_identifier(pat) {
+        Some(_) => {
+            // Optimized path for `x: T` case. This just adopts
+            // `llval` wholesale as the pointer for `x`, avoiding the
+            // general logic which may copy out of `llval`.
+            bcx.fcx.llargs.insert(pat.id, llval);
+        }
+
+        None => {
+            // General path. Copy out the values that are used in the
+            // pattern.
+            bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument);
+        }
+    }
+
+    return bcx;
+}
+
+fn mk_binding_alloca(mut bcx: block,
+                     p_id: ast::node_id,
+                     path: &ast::Path,
+                     binding_mode: IrrefutablePatternBindingMode,
+                     populate: &fn(block, ty::t, ValueRef) -> block) -> block {
+    let var_ty = node_id_type(bcx, p_id);
+    let ident = ast_util::path_to_ident(path);
+    let llval = alloc_ty(bcx, var_ty, bcx.ident(ident));
+    bcx = populate(bcx, var_ty, llval);
+    let llmap = match binding_mode {
+        BindLocal => bcx.fcx.lllocals,
+        BindArgument => bcx.fcx.llargs
+    };
+    llmap.insert(p_id, llval);
+    add_clean(bcx, llval, var_ty);
+    return bcx;
+}
+
+fn bind_irrefutable_pat(bcx: block,
+                        pat: @ast::pat,
+                        val: ValueRef,
+                        binding_mode: IrrefutablePatternBindingMode)
+                        -> block {
+    /*!
+     * A simple version of the pattern matching code that only handles
+     * irrefutable patterns. This is used in let/argument patterns,
+     * not in match statements. Unifying this code with the code above
+     * sounds nice, but in practice it produces very inefficient code,
+     * since the match code is so much more general. In most cases,
+     * LLVM is able to optimize the code, but it causes longer compile
+     * times and makes the generated code nigh impossible to read.
+     *
+     * # Arguments
+     * - bcx: starting basic block context
+     * - pat: the irrefutable pattern being matched.
+     * - val: a pointer to the value being matched. If pat matches a value
+     *   of type T, then this is a T*. If the value is moved from `pat`,
+     *   then `*pat` will be zeroed; otherwise, it's existing cleanup
+     *   applies.
+     * - binding_mode: is this for an argument or a local variable?
+     */
+
+    debug!("bind_irrefutable_pat(bcx=%s, pat=%s, binding_mode=%?)",
+           bcx.to_str(),
+           pat_to_str(pat, bcx.sess().intr()),
+           binding_mode);
+
+    if bcx.sess().asm_comments() {
+        add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)",
+                              pat_to_str(pat, bcx.sess().intr())));
+    }
+
+    let _indenter = indenter();
+
+    let _icx = push_ctxt("alt::bind_irrefutable_pat");
+    let mut bcx = bcx;
+    let tcx = bcx.tcx();
+    let ccx = bcx.ccx();
+    match pat.node {
+        ast::pat_ident(pat_binding_mode, ref path, inner) => {
+            if pat_is_binding(tcx.def_map, pat) {
+                // Allocate the stack slot where the value of this
+                // binding will live and place it into the appropriate
+                // map.
+                bcx = mk_binding_alloca(
+                    bcx, pat.id, path, binding_mode,
+                    |bcx, variable_ty, llvariable_val| {
+                        match pat_binding_mode {
+                            ast::bind_infer => {
+                                // By value binding: move the value that `val`
+                                // points at into the binding's stack slot.
+                                let datum = Datum {val: val,
+                                                   ty: variable_ty,
+                                                   mode: ByRef(ZeroMem)};
+                                datum.store_to(bcx, INIT, llvariable_val)
+                            }
+
+                            ast::bind_by_ref(_) => {
+                                // By ref binding: the value of the variable
+                                // is the pointer `val` itself.
+                                Store(bcx, val, llvariable_val);
+                                bcx
+                            }
+                        }
+                    });
             }
 
-            for inner.iter().advance |inner_pat| {
-                bcx = bind_irrefutable_pat(
-                    bcx, *inner_pat, val, true, binding_mode);
+            for inner.iter().advance |&inner_pat| {
+                bcx = bind_irrefutable_pat(bcx, inner_pat, val, binding_mode);
             }
         }
         ast::pat_enum(_, ref sub_pats) => {
@@ -1799,11 +1944,8 @@ pub fn bind_irrefutable_pat(bcx: block,
                                                     val);
                     for sub_pats.iter().advance |sub_pat| {
                         for args.vals.iter().enumerate().advance |(i, argval)| {
-                            bcx = bind_irrefutable_pat(bcx,
-                                                       sub_pat[i],
-                                                       *argval,
-                                                       make_copy,
-                                                       binding_mode);
+                            bcx = bind_irrefutable_pat(bcx, sub_pat[i],
+                                                       *argval, binding_mode);
                         }
                     }
                 }
@@ -1818,19 +1960,14 @@ pub fn bind_irrefutable_pat(bcx: block,
                             let repr = adt::represent_node(bcx, pat.id);
                             for elems.iter().enumerate().advance |(i, elem)| {
                                 let fldptr = adt::trans_field_ptr(bcx, repr,
-                                                            val, 0, i);
-                                bcx = bind_irrefutable_pat(bcx,
-                                                           *elem,
-                                                           fldptr,
-                                                           make_copy,
-                                                           binding_mode);
+                                                                  val, 0, i);
+                                bcx = bind_irrefutable_pat(bcx, *elem,
+                                                           fldptr, binding_mode);
                             }
                         }
                     }
                 }
                 Some(&ast::def_static(_, false)) => {
-                    bcx = bind_irrefutable_pat(bcx, pat, val, make_copy,
-                                               binding_mode);
                 }
                 _ => {
                     // Nothing to do here.
@@ -1845,12 +1982,8 @@ pub fn bind_irrefutable_pat(bcx: block,
                 for fields.iter().advance |f| {
                     let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
                     let fldptr = adt::trans_field_ptr(bcx, pat_repr, val,
-                                                discr, ix);
-                    bcx = bind_irrefutable_pat(bcx,
-                                               f.pat,
-                                               fldptr,
-                                               make_copy,
-                                               binding_mode);
+                                                      discr, ix);
+                    bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode);
                 }
             }
         }
@@ -1858,11 +1991,7 @@ pub fn bind_irrefutable_pat(bcx: block,
             let repr = adt::represent_node(bcx, pat.id);
             for elems.iter().enumerate().advance |(i, elem)| {
                 let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i);
-                bcx = bind_irrefutable_pat(bcx,
-                                           *elem,
-                                           fldptr,
-                                           make_copy,
-                                           binding_mode);
+                bcx = bind_irrefutable_pat(bcx, *elem, fldptr, binding_mode);
             }
         }
         ast::pat_box(inner) | ast::pat_uniq(inner) => {
@@ -1872,22 +2001,30 @@ pub fn bind_irrefutable_pat(bcx: block,
                 ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox,
                     _ => GEPi(bcx, llbox, [0u, abi::box_field_body])
             };
-            bcx = bind_irrefutable_pat(bcx,
-                                       inner,
-                                       unboxed,
-                                       true,
-                                       binding_mode);
+            bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode);
         }
         ast::pat_region(inner) => {
             let loaded_val = Load(bcx, val);
-            bcx = bind_irrefutable_pat(bcx,
-                                       inner,
-                                       loaded_val,
-                                       true,
-                                       binding_mode);
-        }
-        ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
-        ast::pat_vec(*) => ()
+            bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode);
+        }
+        ast::pat_vec(*) => {
+            bcx.tcx().sess.span_bug(
+                pat.span,
+                fmt!("vector patterns are never irrefutable!"));
+        }
+        ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => ()
     }
     return bcx;
 }
+
+fn simple_identifier<'a>(pat: &'a ast::pat) -> Option<&'a ast::Path> {
+    match pat.node {
+        ast::pat_ident(ast::bind_infer, ref path, None) => {
+            Some(path)
+        }
+        _ => {
+            None
+        }
+    }
+}
+
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 577f1c68960..80fc3803ae7 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -59,6 +59,7 @@ use middle::trans::type_of::*;
 use middle::ty;
 use util::common::indenter;
 use util::ppaux::{Repr, ty_to_str};
+use middle::pat_util;
 
 use middle::trans::type_::Type;
 
@@ -75,7 +76,7 @@ use extra::time;
 use extra::sort;
 use syntax::ast::ident;
 use syntax::ast_map::{path, path_elt_to_str, path_name};
-use syntax::ast_util::{local_def, path_to_ident};
+use syntax::ast_util::{local_def};
 use syntax::attr;
 use syntax::codemap::span;
 use syntax::parse::token;
@@ -111,8 +112,8 @@ impl Drop for _InsnCtxt {
     fn drop(&self) {
         unsafe {
             do local_data::local_data_modify(task_local_insn_key) |c| {
-                do c.map_consume |@ctx| {
-                    let mut ctx = ctx;
+                do c.map_consume |ctx| {
+                    let mut ctx = copy *ctx;
                     ctx.pop();
                     @ctx
                 }
@@ -125,8 +126,8 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
     debug!("new InsnCtxt: %s", s);
     unsafe {
         do local_data::local_data_modify(task_local_insn_key) |c| {
-            do c.map_consume |@ctx| {
-                let mut ctx = ctx;
+            do c.map_consume |ctx| {
+                let mut ctx = copy *ctx;
                 ctx.push(s);
                 @ctx
             }
@@ -1012,7 +1013,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
     match bcx.fcx.personality {
       Some(addr) => Store(pad_bcx, llretval, addr),
       None => {
-        let addr = alloca(pad_bcx, val_ty(llretval));
+        let addr = alloca(pad_bcx, val_ty(llretval), "");
         bcx.fcx.personality = Some(addr);
         Store(pad_bcx, llretval, addr);
       }
@@ -1056,7 +1057,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
     if ty::type_is_bot(t) {
         return C_null(Type::i8p());
     }
-    let llptr = alloc_ty(bcx, t);
+    let llptr = alloc_ty(bcx, t, "");
     Store(bcx, v, llptr);
     return llptr;
 }
@@ -1064,7 +1065,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
 // Since this function does *not* root, it is the caller's responsibility to
 // ensure that the referent is pointed to by a root.
 pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef {
-    let llptr = alloca(cx, val_ty(v));
+    let llptr = alloca(cx, val_ty(v), "");
     Store(cx, v, llptr);
     return llptr;
 }
@@ -1121,9 +1122,6 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
     let _indenter = indenter();
 
     let _icx = push_ctxt("init_local");
-    let ty = node_id_type(bcx, local.node.id);
-
-    debug!("ty=%s", bcx.ty_to_str(ty));
 
     if ignore_lhs(bcx, local) {
         // Handle let _ = e; just like e;
@@ -1135,36 +1133,7 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
         }
     }
 
-    let llptr = match bcx.fcx.lllocals.find_copy(&local.node.id) {
-        Some(v) => v,
-        _ => {
-            bcx.tcx().sess.span_bug(local.span,
-                                    "init_local: Someone forgot to document why it's\
-                                     safe to assume local.node.init must be local_mem!");
-        }
-    };
-
-    let mut bcx = bcx;
-    match local.node.init {
-        Some(init) => {
-            bcx = expr::trans_into(bcx, init, expr::SaveIn(llptr));
-        }
-        _ => {
-            zero_mem(bcx, llptr, ty);
-        }
-    }
-
-    // Make a note to drop this slot on the way out.
-    debug!("adding clean for %?/%s to bcx=%s",
-           local.node.id, bcx.ty_to_str(ty),
-           bcx.to_str());
-    add_clean(bcx, llptr, ty);
-
-    return _match::bind_irrefutable_pat(bcx,
-                                       local.node.pat,
-                                       llptr,
-                                       false,
-                                       _match::BindLocal);
+    _match::store_local(bcx, local.node.pat, local.node.init)
 }
 
 pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
@@ -1469,28 +1438,6 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) {
     }
 }
 
-pub fn alloc_local(cx: block, local: &ast::local) -> block {
-    let _icx = push_ctxt("alloc_local");
-    let t = node_id_type(cx, local.node.id);
-    let simple_name = match local.node.pat.node {
-      ast::pat_ident(_, ref pth, None) => Some(path_to_ident(pth)),
-      _ => None
-    };
-    let val = alloc_ty(cx, t);
-    if cx.sess().opts.debuginfo {
-        for simple_name.iter().advance |name| {
-            str::as_c_str(cx.ccx().sess.str_of(*name), |buf| {
-                unsafe {
-                    llvm::LLVMSetValueName(val, buf)
-                }
-            });
-        }
-    }
-    cx.fcx.lllocals.insert(local.node.id, val);
-    cx
-}
-
-
 pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block {
     let _icx = push_ctxt("with_cond");
     let next_cx = base::sub_block(bcx, "next");
@@ -1561,20 +1508,20 @@ pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
     Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
 }
 
-pub fn alloc_ty(bcx: block, t: ty::t) -> ValueRef {
+pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef {
     let _icx = push_ctxt("alloc_ty");
     let ccx = bcx.ccx();
     let ty = type_of::type_of(ccx, t);
     assert!(!ty::type_has_params(t), "Type has params: %s", ty_to_str(ccx.tcx, t));
-    let val = alloca(bcx, ty);
+    let val = alloca(bcx, ty, name);
     return val;
 }
 
-pub fn alloca(cx: block, ty: Type) -> ValueRef {
-    alloca_maybe_zeroed(cx, ty, false)
+pub fn alloca(cx: block, ty: Type, name: &str) -> ValueRef {
+    alloca_maybe_zeroed(cx, ty, name, false)
 }
 
-pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef {
+pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> ValueRef {
     let _icx = push_ctxt("alloca");
     if cx.unreachable {
         unsafe {
@@ -1582,7 +1529,7 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef {
         }
     }
     let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas);
-    let p = Alloca(initcx, ty);
+    let p = Alloca(initcx, ty, name);
     if zero { memzero(initcx, p, ty); }
     p
 }
@@ -1623,7 +1570,8 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
             llvm::LLVMGetParam(fcx.llfn, 0)
         } else {
             let lloutputtype = type_of::type_of(fcx.ccx, output_type);
-            alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype)
+            alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype,
+                   "__make_return_pointer")
         }
     }
 }
@@ -1738,6 +1686,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt,
             let arg = &args[i];
             let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
 
+            // FIXME #7260: aliasing should be determined by monomorphized ty::t
             match arg.ty.node {
                 // `~` pointers never alias other parameters, because ownership was transferred
                 ast::ty_uniq(_) => {
@@ -1766,7 +1715,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
             let self_val = if slf.is_copy
                     && datum::appropriate_mode(bcx.tcx(), slf.t).is_by_value() {
                 let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t));
-                let alloc = alloc_ty(bcx, slf.t);
+                let alloc = alloc_ty(bcx, slf.t, "__self");
                 Store(bcx, tmp, alloc);
                 alloc
             } else {
@@ -1782,7 +1731,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
     for uint::range(0, arg_tys.len()) |arg_n| {
         let arg_ty = arg_tys[arg_n];
         let raw_llarg = raw_llargs[arg_n];
-        let arg_id = args[arg_n].id;
 
         // For certain mode/type combinations, the raw llarg values are passed
         // by value.  However, within the fn body itself, we want to always
@@ -1793,22 +1741,13 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
         // the event it's not truly needed.
         // only by value if immediate:
         let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() {
-            let alloc = alloc_ty(bcx, arg_ty);
+            let alloc = alloc_ty(bcx, arg_ty, "__arg");
             Store(bcx, raw_llarg, alloc);
             alloc
         } else {
             raw_llarg
         };
-
-        add_clean(bcx, llarg, arg_ty);
-
-        bcx = _match::bind_irrefutable_pat(bcx,
-                                          args[arg_n].pat,
-                                          llarg,
-                                          false,
-                                          _match::BindArgument);
-
-        fcx.llargs.insert(arg_id, llarg);
+        bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
 
         if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
             debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span);
@@ -1967,81 +1906,51 @@ pub fn trans_fn(ccx: @mut CrateContext,
                   |_bcx| { });
 }
 
+fn insert_synthetic_type_entries(bcx: block,
+                                 fn_args: &[ast::arg],
+                                 arg_tys: &[ty::t])
+{
+    /*!
+     * For tuple-like structs and enum-variants, we generate
+     * synthetic AST nodes for the arguments.  These have no types
+     * in the type table and no entries in the moves table,
+     * so the code in `copy_args_to_allocas` and `bind_irrefutable_pat`
+     * gets upset. This hack of a function bridges the gap by inserting types.
+     *
+     * This feels horrible. I think we should just have a special path
+     * for these functions and not try to use the generic code, but
+     * that's not the problem I'm trying to solve right now. - nmatsakis
+     */
+
+    let tcx = bcx.tcx();
+    for uint::range(0, fn_args.len()) |i| {
+        debug!("setting type of argument %u (pat node %d) to %s",
+               i, fn_args[i].pat.id, bcx.ty_to_str(arg_tys[i]));
+
+        let pat_id = fn_args[i].pat.id;
+        let arg_ty = arg_tys[i];
+        tcx.node_types.insert(pat_id as uint, arg_ty);
+    }
+}
+
 pub fn trans_enum_variant(ccx: @mut CrateContext,
-                          enum_id: ast::node_id,
+                          _enum_id: ast::node_id,
                           variant: &ast::variant,
                           args: &[ast::variant_arg],
                           disr: int,
                           param_substs: Option<@param_substs>,
                           llfndecl: ValueRef) {
     let _icx = push_ctxt("trans_enum_variant");
-    // Translate variant arguments to function arguments.
-    let fn_args = do args.map |varg| {
-        ast::arg {
-            is_mutbl: false,
-            ty: copy varg.ty,
-            pat: ast_util::ident_to_pat(
-                ccx.tcx.sess.next_node_id(),
-                codemap::dummy_sp(),
-                special_idents::arg),
-            id: varg.id,
-        }
-    };
-
-    let ty_param_substs = match param_substs {
-        Some(ref substs) => { copy substs.tys }
-        None => ~[]
-    };
-    let enum_ty = ty::subst_tps(ccx.tcx,
-                                ty_param_substs,
-                                None,
-                                ty::node_id_to_type(ccx.tcx, enum_id));
-    let fcx = new_fn_ctxt_w_id(ccx,
-                               ~[],
-                               llfndecl,
-                               variant.node.id,
-                               enum_ty,
-                               param_substs,
-                               None);
-
-    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
-    let bcx = top_scope_block(fcx, None);
-    let lltop = bcx.llbb;
-    let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
-    let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
-
-    // XXX is there a better way to reconstruct the ty::t?
-    let repr = adt::represent_type(ccx, enum_ty);
-
-    debug!("trans_enum_variant: name=%s tps=%s repr=%? enum_ty=%s",
-           unsafe { str::raw::from_c_str(llvm::LLVMGetValueName(llfndecl)) },
-           ~"[" + ty_param_substs.map(|&t| ty_to_str(ccx.tcx, t)).connect(", ") + "]",
-           repr, ty_to_str(ccx.tcx, enum_ty));
 
-    adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
-    for args.iter().enumerate().advance |(i, va)| {
-        let lldestptr = adt::trans_field_ptr(bcx,
-                                             repr,
-                                             fcx.llretptr.get(),
-                                             disr,
-                                             i);
-
-        // If this argument to this function is a enum, it'll have come in to
-        // this function as an opaque blob due to the way that type_of()
-        // works. So we have to cast to the destination's view of the type.
-        let llarg = match fcx.llargs.find(&va.id) {
-            Some(&x) => x,
-            _ => fail!("trans_enum_variant: how do we know this works?"),
-        };
-        let arg_ty = arg_tys[i];
-        memcpy_ty(bcx, lldestptr, llarg, arg_ty);
-    }
-    build_return(bcx);
-    finish_fn(fcx, lltop);
+    trans_enum_variant_or_tuple_like_struct(
+        ccx,
+        variant.node.id,
+        args,
+        disr,
+        param_substs,
+        llfndecl);
 }
 
-// NB: In theory this should be merged with the function above. But the AST
-// structures are completely different, so very little code would be shared.
 pub fn trans_tuple_struct(ccx: @mut CrateContext,
                           fields: &[@ast::struct_field],
                           ctor_id: ast::node_id,
@@ -2049,37 +1958,72 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
                           llfndecl: ValueRef) {
     let _icx = push_ctxt("trans_tuple_struct");
 
-    // Translate struct fields to function arguments.
-    let fn_args = do fields.map |field| {
+    trans_enum_variant_or_tuple_like_struct(
+        ccx,
+        ctor_id,
+        fields,
+        0,
+        param_substs,
+        llfndecl);
+}
+
+trait IdAndTy {
+    fn id(&self) -> ast::node_id;
+    fn ty<'a>(&'a self) -> &'a ast::Ty;
+}
+
+impl IdAndTy for ast::variant_arg {
+    fn id(&self) -> ast::node_id { self.id }
+    fn ty<'a>(&'a self) -> &'a ast::Ty { &self.ty }
+}
+
+impl IdAndTy for @ast::struct_field {
+    fn id(&self) -> ast::node_id { self.node.id }
+    fn ty<'a>(&'a self) -> &'a ast::Ty { &self.node.ty }
+}
+
+pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
+    ccx: @mut CrateContext,
+    ctor_id: ast::node_id,
+    args: &[A],
+    disr: int,
+    param_substs: Option<@param_substs>,
+    llfndecl: ValueRef)
+{
+    // Translate variant arguments to function arguments.
+    let fn_args = do args.map |varg| {
         ast::arg {
             is_mutbl: false,
-            ty: copy field.node.ty,
-            pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(),
-                                        codemap::dummy_sp(),
-                                        special_idents::arg),
-            id: field.node.id
+            ty: copy *varg.ty(),
+            pat: ast_util::ident_to_pat(
+                ccx.tcx.sess.next_node_id(),
+                codemap::dummy_sp(),
+                special_idents::arg),
+            id: varg.id(),
         }
     };
 
-    // XXX is there a better way to reconstruct the ty::t?
     let ty_param_substs = match param_substs {
         Some(ref substs) => { copy substs.tys }
         None => ~[]
     };
+
     let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None,
                                 ty::node_id_to_type(ccx.tcx, ctor_id));
-    let tup_ty = match ty::get(ctor_ty).sty {
+
+    let result_ty = match ty::get(ctor_ty).sty {
         ty::ty_bare_fn(ref bft) => bft.sig.output,
-        _ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \
-                                return type %s",
-                               ty_to_str(ccx.tcx, ctor_ty)))
+        _ => ccx.sess.bug(
+            fmt!("trans_enum_variant_or_tuple_like_struct: \
+                  unexpected ctor return type %s",
+                 ty_to_str(ccx.tcx, ctor_ty)))
     };
 
     let fcx = new_fn_ctxt_w_id(ccx,
                                ~[],
                                llfndecl,
                                ctor_id,
-                               tup_ty,
+                               result_ty,
                                param_substs,
                                None);
 
@@ -2087,23 +2031,23 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
 
     let bcx = top_scope_block(fcx, None);
     let lltop = bcx.llbb;
-    let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
-    let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
+    let arg_tys = ty::ty_fn_args(ctor_ty);
 
-    let repr = adt::represent_type(ccx, tup_ty);
-    adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0);
+    insert_synthetic_type_entries(bcx, fn_args, arg_tys);
+    let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
 
-    for fields.iter().enumerate().advance |(i, field)| {
+    let repr = adt::represent_type(ccx, result_ty);
+    adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
+    for fn_args.iter().enumerate().advance |(i, fn_arg)| {
         let lldestptr = adt::trans_field_ptr(bcx,
                                              repr,
                                              fcx.llretptr.get(),
-                                             0,
+                                             disr,
                                              i);
-        let llarg = fcx.llargs.get_copy(&field.node.id);
+        let llarg = fcx.llargs.get_copy(&fn_arg.pat.id);
         let arg_ty = arg_tys[i];
         memcpy_ty(bcx, lldestptr, llarg, arg_ty);
     }
-
     build_return(bcx);
     finish_fn(fcx, lltop);
 }
@@ -3033,13 +2977,17 @@ pub fn trans_crate(sess: session::Session,
         do sort::quick_sort(ccx.stats.fn_stats) |&(_, _, insns_a), &(_, _, insns_b)| {
             insns_a > insns_b
         }
-        for ccx.stats.fn_stats.iter().advance |&(name, ms, insns)| {
-            io::println(fmt!("%u insns, %u ms, %s", insns, ms, name));
+        for ccx.stats.fn_stats.iter().advance |tuple| {
+            match *tuple {
+                (ref name, ms, insns) => {
+                    io::println(fmt!("%u insns, %u ms, %s", insns, ms, *name));
+                }
+            }
         }
     }
     if ccx.sess.count_llvm_insns() {
-        for ccx.stats.llvm_insns.iter().advance |(&k, &v)| {
-            io::println(fmt!("%-7u %s", v, k));
+        for ccx.stats.llvm_insns.iter().advance |(k, v)| {
+            io::println(fmt!("%-7u %s", *v, *k));
         }
     }
 
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index b62b73423e9..db5553ca939 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -505,11 +505,17 @@ pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
     }
 }
 
-pub fn Alloca(cx: block, Ty: Type) -> ValueRef {
+pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef {
     unsafe {
         if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
         count_insn(cx, "alloca");
-        return llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname());
+        if name.is_empty() {
+            llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname())
+        } else {
+            str::as_c_str(
+                name,
+                |c| llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), c))
+        }
     }
 }
 
diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs
index d0047919430..8d741369e1a 100644
--- a/src/librustc/middle/trans/cabi.rs
+++ b/src/librustc/middle/trans/cabi.rs
@@ -130,10 +130,10 @@ impl FnType {
             j = 1u;
             get_param(llwrapfn, 0u)
         } else if self.ret_ty.cast {
-            let retptr = alloca(bcx, self.ret_ty.ty);
+            let retptr = alloca(bcx, self.ret_ty.ty, "");
             BitCast(bcx, retptr, ret_ty.ptr_to())
         } else {
-            alloca(bcx, ret_ty)
+            alloca(bcx, ret_ty, "")
         };
 
         let mut i = 0u;
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 473afda48e6..22adc4aa24b 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -600,7 +600,7 @@ pub fn trans_call_inner(in_cx: block,
         let mut bcx = callee.bcx;
         let ccx = cx.ccx();
         let ret_flag = if ret_in_loop {
-            let flag = alloca(bcx, Type::bool());
+            let flag = alloca(bcx, Type::bool(), "__ret_flag");
             Store(bcx, C_bool(false), flag);
             Some(flag)
         } else {
@@ -675,7 +675,7 @@ pub fn trans_call_inner(in_cx: block,
                 unsafe {
                     if ty::type_needs_drop(bcx.tcx(), ret_ty) {
                         if ty::type_is_immediate(bcx.tcx(), ret_ty) {
-                            let llscratchptr = alloc_ty(bcx, ret_ty);
+                            let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
                             Store(bcx, llresult, llscratchptr);
                             bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
                         } else {
@@ -733,7 +733,7 @@ pub fn trans_ret_slot(bcx: block, fn_ty: ty::t, dest: Option<expr::Dest>)
                     llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
                 }
             } else {
-                alloc_ty(bcx, retty)
+                alloc_ty(bcx, retty, "__trans_ret_slot")
             }
         }
     }
@@ -823,7 +823,7 @@ pub fn trans_arg_expr(bcx: block,
                         _
                     }) => {
                     let scratch_ty = expr_ty(bcx, arg_expr);
-                    let scratch = alloc_ty(bcx, scratch_ty);
+                    let scratch = alloc_ty(bcx, scratch_ty, "__ret_flag");
                     let arg_ty = expr_ty(bcx, arg_expr);
                     let sigil = ty::ty_closure_sigil(arg_ty);
                     let bcx = closure::trans_expr_fn(
@@ -860,8 +860,6 @@ pub fn trans_arg_expr(bcx: block,
         // FIXME(#3548) use the adjustments table
         match autoref_arg {
             DoAutorefArg => {
-                assert!(!
-                    bcx.ccx().maps.moves_map.contains(&arg_expr.id));
                 val = arg_datum.to_ref_llval(bcx);
             }
             DontAutorefArg => {
@@ -875,10 +873,10 @@ pub fn trans_arg_expr(bcx: block,
                         //    &arg_expr.id);
                         debug!("by ref arg with type %s, storing to scratch",
                                bcx.ty_to_str(arg_datum.ty));
-                        let scratch = scratch_datum(bcx, arg_datum.ty, false);
+                        let scratch = scratch_datum(bcx, arg_datum.ty,
+                                                    "__self", false);
 
                         arg_datum.store_to_datum(bcx,
-                                                 arg_expr.id,
                                                  INIT,
                                                  scratch);
 
@@ -895,10 +893,10 @@ pub fn trans_arg_expr(bcx: block,
                                 arg_datum.appropriate_mode(bcx.tcx()).is_by_ref() {
                             debug!("by copy arg with type %s, storing to scratch",
                                    bcx.ty_to_str(arg_datum.ty));
-                            let scratch = scratch_datum(bcx, arg_datum.ty, false);
+                            let scratch = scratch_datum(bcx, arg_datum.ty,
+                                                        "__arg", false);
 
                             arg_datum.store_to_datum(bcx,
-                                                     arg_expr.id,
                                                      INIT,
                                                      scratch);
 
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index 4c63b8dc844..5b0212cc05c 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -193,7 +193,7 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t)
         }
         ast::BorrowedSigil => {
             let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
-            let llbox = alloc_ty(bcx, cbox_ty);
+            let llbox = alloc_ty(bcx, cbox_ty, "__closure");
             nuke_ref_count(bcx, llbox);
             rslt(bcx, llbox)
         }
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 973a124c48a..24648ada893 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -608,6 +608,10 @@ impl block_ {
     pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx }
     pub fn sess(&self) -> Session { self.fcx.ccx.sess }
 
+    pub fn ident(&self, ident: ident) -> @str {
+        token::ident_to_str(&ident)
+    }
+
     pub fn node_id_to_str(&self, id: ast::node_id) -> ~str {
         ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr())
     }
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index ebaa3179442..2880c68c1e0 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -96,7 +96,7 @@ pub struct CrateContext {
      all_llvm_symbols: HashSet<@str>,
      tcx: ty::ctxt,
      maps: astencode::Maps,
-     stats: Stats,
+     stats: @mut Stats,
      upcalls: @upcall::Upcalls,
      tydesc_type: Type,
      int_type: Type,
@@ -201,7 +201,7 @@ impl CrateContext {
                   all_llvm_symbols: HashSet::new(),
                   tcx: tcx,
                   maps: maps,
-                  stats: Stats {
+                  stats: @mut Stats {
                     n_static_tydescs: 0u,
                     n_glues_created: 0u,
                     n_null_glues: 0u,
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 8ca4253ead8..904e6e14e28 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -35,9 +35,6 @@ use syntax::codemap::span;
 pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
     let _icx = push_ctxt("trans_block");
     let mut bcx = bcx;
-    do block_locals(b) |local| {
-        bcx = alloc_local(bcx, local);
-    };
     for b.node.stmts.iter().advance |s| {
         debuginfo::update_source_pos(bcx, b.span);
         bcx = trans_stmt(bcx, *s);
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index e86709d72b3..1de619433af 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -70,8 +70,8 @@
  *   This is a "shallow" clone.  After `move_to()`, the current datum
  *   is invalid and should no longer be used.
  *
- * - `store_to()` either performs a copy or a move by consulting the
- *   moves_map computed by `middle::moves`.
+ * - `store_to()` either performs a copy or a move depending on the
+ *   Rust type of the datum.
  *
  * # Scratch datum
  *
@@ -173,19 +173,19 @@ pub fn immediate_rvalue_bcx(bcx: block,
     return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)};
 }
 
-pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum {
+pub fn scratch_datum(bcx: block, ty: ty::t, name: &str, zero: bool) -> Datum {
     /*!
-     *
      * Allocates temporary space on the stack using alloca() and
      * returns a by-ref Datum pointing to it.  If `zero` is true, the
      * space will be zeroed when it is allocated; this is normally not
      * necessary, but in the case of automatic rooting in match
      * statements it is possible to have temporaries that may not get
      * initialized if a certain arm is not taken, so we must zero
-     * them. You must arrange any cleanups etc yourself! */
+     * them. You must arrange any cleanups etc yourself!
+     */
 
     let llty = type_of::type_of(bcx.ccx(), ty);
-    let scratch = alloca_maybe_zeroed(bcx, llty, zero);
+    let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
     Datum { val: scratch, ty: ty, mode: ByRef(RevokeClean) }
 }
 
@@ -208,7 +208,6 @@ pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
 impl Datum {
     pub fn store_to(&self,
                     bcx: block,
-                    id: ast::node_id,
                     action: CopyAction,
                     dst: ValueRef)
                     -> block {
@@ -218,7 +217,7 @@ impl Datum {
          * `id` is located in the move table, but copies otherwise.
          */
 
-        if bcx.ccx().maps.moves_map.contains(&id) {
+        if ty::type_moves_by_default(bcx.tcx(), self.ty) {
             self.move_to(bcx, action, dst)
         } else {
             self.copy_to(bcx, action, dst)
@@ -227,7 +226,6 @@ impl Datum {
 
     pub fn store_to_dest(&self,
                          bcx: block,
-                         id: ast::node_id,
                          dest: expr::Dest)
                          -> block {
         match dest {
@@ -235,21 +233,20 @@ impl Datum {
                 return bcx;
             }
             expr::SaveIn(addr) => {
-                return self.store_to(bcx, id, INIT, addr);
+                return self.store_to(bcx, INIT, addr);
             }
         }
     }
 
     pub fn store_to_datum(&self,
                           bcx: block,
-                          id: ast::node_id,
                           action: CopyAction,
                           datum: Datum)
                           -> block {
         debug!("store_to_datum(self=%s, action=%?, datum=%s)",
                self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
         assert!(datum.mode.is_by_ref());
-        self.store_to(bcx, id, action, datum.val)
+        self.store_to(bcx, action, datum.val)
     }
 
     pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
@@ -476,7 +473,7 @@ impl Datum {
                 if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) {
                     C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to())
                 } else {
-                    let slot = alloc_ty(bcx, self.ty);
+                    let slot = alloc_ty(bcx, self.ty, "");
                     Store(bcx, self.val, slot);
                     slot
                 }
@@ -828,11 +825,10 @@ impl DatumBlock {
     }
 
     pub fn store_to(&self,
-                    id: ast::node_id,
                     action: CopyAction,
                     dst: ValueRef)
                     -> block {
-        self.datum.store_to(self.bcx, id, action, dst)
+        self.datum.store_to(self.bcx, action, dst)
     }
 
     pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 0180eeb3d22..19a0f7262ff 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -23,7 +23,8 @@ This will generate code that evaluates `expr`, storing the result into
 `Dest`, which must either be the special flag ignore (throw the result
 away) or be a pointer to memory of the same type/size as the
 expression.  It returns the resulting basic block.  This form will
-handle all automatic adjustments and moves for you.
+handle all automatic adjustments for you. The value will be moved if
+its type is linear and copied otherwise.
 
 ## Translation to a datum
 
@@ -42,18 +43,18 @@ This function generates code to evaluate the expression and return a
 tries to return its result in the most efficient way possible, without
 introducing extra copies or sacrificing information.  Therefore, for
 lvalue expressions, you always get a by-ref `Datum` in return that
-points at the memory for this lvalue (almost, see [1]).  For rvalue
-expressions, we will return a by-value `Datum` whenever possible, but
-it is often necessary to allocate a stack slot, store the result of
-the rvalue in there, and then return a pointer to the slot (see the
-discussion later on about the different kinds of rvalues).
+points at the memory for this lvalue.  For rvalue expressions, we will
+return a by-value `Datum` whenever possible, but it is often necessary
+to allocate a stack slot, store the result of the rvalue in there, and
+then return a pointer to the slot (see the discussion later on about
+the different kinds of rvalues).
 
 NB: The `trans_to_datum()` function does perform adjustments, but
 since it returns a pointer to the value "in place" it does not handle
-any moves that may be relevant.  If you are transing an expression
-whose result should be moved, you should either use the Datum methods
-`move_to()` (for unconditional moves) or `store_to()` (for moves
-conditioned on the type of the expression) at some point.
+moves.  If you wish to copy/move the value returned into a new
+location, you should use the Datum method `store_to()` (move or copy
+depending on type). You can also use `move_to()` (force move) or
+`copy_to()` (force copy) for special situations.
 
 ## Translating local variables
 
@@ -110,13 +111,6 @@ generate phi nodes).
 Finally, statement rvalues are rvalues that always produce a nil
 return type, such as `while` loops or assignments (`a = b`).
 
-## Caveats
-
-[1] Actually, some lvalues are only stored by value and not by
-reference.  An example (as of this writing) would be immutable
-arguments or pattern bindings of immediate type.  However, mutable
-lvalues are *never* stored by value.
-
 */
 
 
@@ -274,7 +268,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
                                    ty::mt { ty: unit_ty, mutbl: ast::m_imm },
                                    ty::vstore_slice(ty::re_static));
 
-        let scratch = scratch_datum(bcx, slice_ty, false);
+        let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
         Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
         Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
         DatumBlock {bcx: bcx, datum: scratch}
@@ -290,7 +284,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
         let tcx = bcx.tcx();
         let closure_ty = expr_ty_adjusted(bcx, expr);
         debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx));
-        let scratch = scratch_datum(bcx, closure_ty, false);
+        let scratch = scratch_datum(bcx, closure_ty, "__adjust", false);
         let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
         assert_eq!(datum.appropriate_mode(tcx), ByValue);
         Store(bcx, datum.to_appropriate_llval(bcx), llfn);
@@ -315,7 +309,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
         let datumblock = trans_to_datum(bcx, expr);
         return match dest {
             Ignore => datumblock.bcx,
-            SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
+            SaveIn(lldest) => datumblock.store_to(INIT, lldest)
         };
     }
 
@@ -343,7 +337,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
             let datumblock = trans_lvalue_unadjusted(bcx, expr);
             match dest {
                 Ignore => datumblock.bcx,
-                SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
+                SaveIn(lldest) => datumblock.store_to(INIT, lldest)
             }
         }
         ty::RvalueDatumExpr => {
@@ -351,8 +345,9 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
             match dest {
                 Ignore => datumblock.drop_val(),
 
-                // NB: We always do `move_to()` regardless of the
-                // moves_map because we're processing an rvalue
+                // When processing an rvalue, the value will be newly
+                // allocated, so we always `move_to` so as not to
+                // unnecessarily inc ref counts and so forth:
                 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
             }
         }
@@ -386,11 +381,11 @@ fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
 
 fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
     /*!
-     *
      * Translates an expression into a datum.  If this expression
      * is an rvalue, this will result in a temporary value being
-     * created.  If you already know where the result should be stored,
-     * you should use `trans_into()` instead. */
+     * created.  If you plan to store the value somewhere else,
+     * you should prefer `trans_into()` instead.
+     */
 
     let mut bcx = bcx;
 
@@ -423,7 +418,7 @@ fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
                 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
                 return nil(bcx, ty);
             } else {
-                let scratch = scratch_datum(bcx, ty, false);
+                let scratch = scratch_datum(bcx, ty, "", false);
                 bcx = trans_rvalue_dps_unadjusted(
                     bcx, expr, SaveIn(scratch.val));
 
@@ -535,7 +530,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
             let dst_datum = unpack_datum!(
                 bcx, trans_lvalue(bcx, dst));
             return src_datum.store_to_datum(
-                bcx, src.id, DROP_EXISTING, dst_datum);
+                bcx, DROP_EXISTING, dst_datum);
         }
         ast::expr_assign_op(callee_id, op, dst, src) => {
             return trans_assign_op(bcx, expr, callee_id, op, dst, src);
@@ -638,7 +633,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
             return trans_into(bcx, blk, dest);
         }
         ast::expr_copy(a) => {
-            return trans_into(bcx, a, dest);
+            // If we just called `trans_into(bcx, a, dest)`, then this
+            // might *move* the value into `dest` if the value is
+            // non-copyable. So first get a datum and then do an
+            // explicit copy.
+            let datumblk = trans_to_datum(bcx, a);
+            return match dest {
+                Ignore => datumblk.bcx,
+                SaveIn(llval) => datumblk.copy_to(INIT, llval)
+            };
         }
         ast::expr_call(f, ref args, _) => {
             return callee::trans_call(
@@ -1221,6 +1224,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
                 bcx = trans_into(bcx, e, Ignore);
             }
             for optbase.iter().advance |sbi| {
+                // FIXME #7261: this moves entire base, not just certain fields
                 bcx = trans_into(bcx, sbi.expr, Ignore);
             }
             return bcx;
@@ -1245,7 +1249,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
                 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
             };
             let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
-            bcx = datum.store_to(bcx, base.expr.id, INIT, dest);
+            bcx = datum.store_to(bcx, INIT, dest);
         }
     }
 
@@ -1687,7 +1691,7 @@ fn trans_assign_op(bcx: block,
     // A user-defined operator method
     if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
         // FIXME(#2528) evaluates the receiver twice!!
-        let scratch = scratch_datum(bcx, dst_datum.ty, false);
+        let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false);
         let bcx = trans_overloaded_op(bcx,
                                       expr,
                                       callee_id,
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 2c505853d5e..bdae2220598 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -195,14 +195,15 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
     if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
         let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
         fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas),
-                                   lloutputtype));
+                                   lloutputtype,
+                                   ""));
     }
 
     let bcx = top_scope_block(fcx, None);
     let lltop = bcx.llbb;
 
     // Allocate the struct and write the arguments into it.
-    let llargbundle = alloca(bcx, tys.bundle_ty);
+    let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
     arg_builder(bcx, tys, llwrapfn, llargbundle);
 
     // Create call itself.
@@ -732,7 +733,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
 
                 let llsrcval = get_param(decl, first_real_arg);
                 let llsrcptr = if ty::type_is_immediate(ccx.tcx, in_type) {
-                    let llsrcptr = alloca(bcx, llintype);
+                    let llsrcptr = alloca(bcx, llintype, "__llsrcptr");
                     Store(bcx, llsrcval, llsrcptr);
                     llsrcptr
                 } else {
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index bc493bfa23e..25e73fd640d 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -132,7 +132,7 @@ pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
       ty::ty_evec(_, ty::vstore_box) |
       ty::ty_estr(ty::vstore_box) |
       ty::ty_opaque_closure_ptr(_) => {
-        let vp = alloca(bcx, type_of(bcx.ccx(), t));
+        let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
         Store(bcx, v, vp);
         free_ty(bcx, vp, t)
       }
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index 14cc822b5a5..0914e61d58f 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -614,7 +614,8 @@ pub fn trans_trait_callee_from_llval(bcx: block,
     }
 
     llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
-    let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false);
+    let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()),
+                                "__trait_callee", false);
     Store(bcx, llself, scratch.val);
     scratch.add_clean(bcx);
 
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index cc4111aa194..a3b544dbc61 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -57,7 +57,7 @@ impl Reflector {
         let bcx = self.bcx;
         let str_vstore = ty::vstore_slice(ty::re_static);
         let str_ty = ty::mk_estr(bcx.tcx(), str_vstore);
-        let scratch = scratch_datum(bcx, str_ty, false);
+        let scratch = scratch_datum(bcx, str_ty, "", false);
         let len = C_uint(bcx.ccx(), s.len() + 1);
         let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p());
         Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ]));
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index 41dbe320d2d..825320b9ff6 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -332,7 +332,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::e
                     let llptrval = PointerCast(bcx, llptrval, Type::i8p());
                     let llsizeval = C_uint(bcx.ccx(), s.len());
                     let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq);
-                    let lldestval = scratch_datum(bcx, typ, false);
+                    let lldestval = scratch_datum(bcx, typ, "", false);
                     let bcx = callee::trans_lang_call(
                         bcx,
                         bcx.tcx().lang_items.strdup_uniq_fn(),
@@ -454,7 +454,7 @@ pub fn write_content(bcx: block,
 
                     let loop_counter = {
                         // i = 0
-                        let i = alloca(loop_bcx, bcx.ccx().int_type);
+                        let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
                         Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
 
                         Br(loop_bcx, cond_bcx.llbb);
diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs
index bd22e41aff8..1804a7334f2 100644
--- a/src/librustc/middle/trans/write_guard.rs
+++ b/src/librustc/middle/trans/write_guard.rs
@@ -120,7 +120,7 @@ fn root(datum: &Datum,
     // First, root the datum. Note that we must zero this value,
     // because sometimes we root on one path but not another.
     // See e.g. #4904.
-    let scratch = scratch_datum(bcx, datum.ty, true);
+    let scratch = scratch_datum(bcx, datum.ty, "__write_guard", true);
     datum.copy_to_datum(bcx, INIT, scratch);
     let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope);
     add_clean_temp_mem_in_scope(cleanup_bcx, root_info.scope, scratch.val, scratch.ty);
@@ -135,7 +135,8 @@ fn root(datum: &Datum,
             // scratch.val will be NULL should the cleanup get
             // called without the freezing actually occurring, and
             // return_to_mut checks for this condition.
-            let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false);
+            let scratch_bits = scratch_datum(bcx, ty::mk_uint(),
+                                             "__write_guard_bits", false);
 
             let freeze_did = match freeze_kind {
                 DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(),
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index 1f7946576db..ac7a9db99e9 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
                 None => {
                     fcx.infcx().type_error_message_str_with_expected(pat.span,
                                                        |expected, actual| {
-                                                       expected.map_default(~"", |&e| {
+                                                       expected.map_default(~"", |e| {
                         fmt!("mismatched types: expected `%s` but found %s",
-                             e, actual)})},
+                             *e, actual)})},
                              Some(expected), ~"a structure pattern",
                              None);
                     fcx.write_error(pat.id);
@@ -200,9 +200,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
         _ => {
             fcx.infcx().type_error_message_str_with_expected(pat.span,
                                                |expected, actual| {
-                                               expected.map_default(~"", |&e| {
+                                               expected.map_default(~"", |e| {
                     fmt!("mismatched types: expected `%s` but found %s",
-                         e, actual)})},
+                         *e, actual)})},
                     Some(expected), ~"an enum or structure pattern",
                     None);
             fcx.write_error(pat.id);
@@ -534,9 +534,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
                     _ => ty::terr_mismatch
                 };
                 fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
-                expected.map_default(~"", |&e| {
+                expected.map_default(~"", |e| {
                     fmt!("mismatched types: expected `%s` but found %s",
-                                     e, actual)})}, Some(expected), ~"tuple", Some(&type_error));
+                                     *e, actual)})}, Some(expected), ~"tuple", Some(&type_error));
                 fcx.write_error(pat.id);
             }
         }
@@ -583,9 +583,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
               fcx.infcx().type_error_message_str_with_expected(
                   pat.span,
                   |expected, actual| {
-                      expected.map_default(~"", |&e| {
+                      expected.map_default(~"", |e| {
                           fmt!("mismatched types: expected `%s` but found %s",
-                               e, actual)})},
+                               *e, actual)})},
                   Some(expected),
                   ~"a vector pattern",
                   None);
@@ -641,9 +641,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt,
             fcx.infcx().type_error_message_str_with_expected(
                 span,
                 |expected, actual| {
-                    expected.map_default(~"", |&e| {
+                    expected.map_default(~"", |e| {
                         fmt!("mismatched types: expected `%s` but found %s",
-                             e, actual)})},
+                             *e, actual)})},
                 Some(expected),
                 fmt!("%s pattern", match pointer_kind {
                     Managed => "an @-box",
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index e5248e01ed7..d59c8e5e894 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -350,10 +350,7 @@ pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt,
                                    self_info.self_id);
     }
     for decl.inputs.iter().advance |arg| {
-        do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat)
-                |_bm, pat_id, span, _path| {
-            resolve_type_vars_for_node(wbcx, span, pat_id);
-        }
+        (visit.visit_pat)(arg.pat, (wbcx, visit));
         // Privacy needs the type for the whole pattern, not just each binding
         if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) {
             resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id);
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 473d5b8e6e8..7ee731d4f46 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -209,7 +209,7 @@ impl CoherenceChecker {
                 match item.node {
                     item_impl(_, ref opt_trait, _, _) => {
                         let opt_trait : ~[trait_ref] = opt_trait.iter()
-                                                                .transform(|&x| x)
+                                                                .transform(|x| copy *x)
                                                                 .collect();
                         self.check_implementation(item, opt_trait);
                     }
@@ -270,7 +270,7 @@ impl CoherenceChecker {
         // We only want to generate one Impl structure. When we generate one,
         // we store it here so that we don't recreate it.
         let mut implementation_opt = None;
-        for associated_traits.iter().advance |&associated_trait| {
+        for associated_traits.iter().advance |associated_trait| {
             let trait_ref =
                 ty::node_id_to_trait_ref(
                     self.crate_context.tcx,
diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs
index b2f608bd352..54ad888e2ae 100644
--- a/src/librustpkg/package_source.rs
+++ b/src/librustpkg/package_source.rs
@@ -202,7 +202,7 @@ impl PkgSrc {
                     crates: &[Crate],
                     cfgs: &[~str],
                     what: OutputType) {
-        for crates.iter().advance |&crate| {
+        for crates.iter().advance |crate| {
             let path = &src_dir.push_rel(&crate.file).normalize();
             note(fmt!("build_crates: compiling %s", path.to_str()));
             note(fmt!("build_crates: destination dir is %s", dst_dir.to_str()));
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs
index b8f77ceecec..c6f7735b204 100644
--- a/src/librustpkg/path_util.rs
+++ b/src/librustpkg/path_util.rs
@@ -71,8 +71,8 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
 pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
     let src_dir = workspace.push("src");
     let dirs = os::list_dir(&src_dir);
-    for dirs.iter().advance |&p| {
-        let p = Path(p);
+    for dirs.iter().advance |p| {
+        let p = Path(copy *p);
         debug!("=> p = %s", p.to_str());
         if !os::path_is_dir(&src_dir.push_rel(&p)) {
             loop;
@@ -84,8 +84,8 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
         }
         else {
             let pf = p.filename();
-            for pf.iter().advance |&pf| {
-                let f_ = copy pf;
+            for pf.iter().advance |pf| {
+                let f_ = copy *pf;
                 let g = f_.to_str();
                 match split_version_general(g, '-') {
                     Some((ref might_match, ref vers)) => {
@@ -217,10 +217,10 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target,
     debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
 
     let mut result_filename = None;
-    for dir_contents.iter().advance |&p| {
+    for dir_contents.iter().advance |p| {
         let mut which = 0;
         let mut hash = None;
-        let p_path = Path(p);
+        let p_path = Path(copy *p);
         let extension = p_path.filetype();
         debug!("p = %s, p's extension is %?", p.to_str(), extension);
         match extension {
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 900ef4896ca..da5c98680b9 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -194,7 +194,7 @@ pub fn compile_input(ctxt: &Ctx,
                               Main => ~[]
                           }
                           + flags
-                          + cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
+                          + cfgs.flat_map(|c| { ~[~"--cfg", copy *c] }),
                           driver::optgroups()).get();
     let options = @session::options {
         crate_type: crate_type,
@@ -311,8 +311,8 @@ pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId,
                      what: OutputType) -> bool {
     debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str());
     debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
-    for flags.iter().advance |&fl| {
-        debug!("+++ %s", fl);
+    for flags.iter().advance |fl| {
+        debug!("+++ %s", *fl);
     }
     compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what)
 }
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
index aee6f1bd204..2b42c085009 100644
--- a/src/libstd/ptr.rs
+++ b/src/libstd/ptr.rs
@@ -143,6 +143,30 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
 }
 
 /**
+ * Zeroes out `count * size_of::<T>` bytes of memory at `dst`
+ */
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
+    set_memory(dst, 0, count);
+}
+
+/**
+ * Zeroes out `count * size_of::<T>` bytes of memory at `dst`
+ */
+#[inline]
+#[cfg(stage0)]
+pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
+    let mut count = count * sys::size_of::<T>();
+    let mut dst = dst as *mut u8;
+    while count > 0 {
+        *dst = 0;
+        dst = mut_offset(dst, 1);
+        count -= 1;
+    }
+}
+
+/**
  * Swap the values at two mutable locations of the same type, without
  * deinitialising or copying either one.
  */
@@ -172,6 +196,32 @@ pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T {
     src
 }
 
+/**
+ * Reads the value from `*src` and returns it. Does not copy `*src`.
+ */
+#[inline(always)]
+pub unsafe fn read_ptr<T>(src: *mut T) -> T {
+    let mut tmp: T = intrinsics::uninit();
+    let t: *mut T = &mut tmp;
+    copy_memory(t, src, 1);
+    tmp
+}
+
+/**
+ * Reads the value from `*src` and nulls it out.
+ * This currently prevents destructors from executing.
+ */
+#[inline(always)]
+pub unsafe fn read_and_zero_ptr<T>(dest: *mut T) -> T {
+    // Copy the data out from `dest`:
+    let tmp = read_ptr(dest);
+
+    // Now zero out `dest`:
+    zero_memory(dest, 1);
+
+    tmp
+}
+
 /// Transform a region pointer - &T - to an unsafe pointer - *T.
 #[inline]
 pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index 7e051b62171..17dc604a178 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -715,10 +715,16 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
         let mut tmps = ~[];
         let mut ptrs = ~[];
 
-        for es.iter().advance |&(k, v)| {
-            let kv = @fmt!("%s=%s", k, v);
-            tmps.push(kv);
-            ptrs.push(str::as_c_str(*kv, |b| b));
+        for es.iter().advance |pair| {
+            // Use of match here is just to workaround limitations
+            // in the stage0 irrefutable pattern impl.
+            match pair {
+                &(ref k, ref v) => {
+                    let kv = @fmt!("%s=%s", *k, *v);
+                    tmps.push(kv);
+                    ptrs.push(str::as_c_str(*kv, |b| b));
+                }
+            }
         }
 
         ptrs.push(ptr::null());
@@ -738,8 +744,8 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
     match env {
       Some(es) => {
         let mut blk = ~[];
-        for es.iter().advance |&(k, v)| {
-            let kv = fmt!("%s=%s", k, v);
+        for es.iter().advance |pair| {
+            let kv = fmt!("%s=%s", pair.first(), pair.second());
             blk.push_all(kv.as_bytes_with_null_consume());
         }
         blk.push(0);
@@ -1294,9 +1300,9 @@ mod tests {
         let output = str::from_bytes(prog.finish_with_output().output);
 
         let r = os::env();
-        for r.iter().advance |&(k, v)| {
+        for r.iter().advance |&(ref k, ref v)| {
             // don't check windows magical empty-named variables
-            assert!(k.is_empty() || output.contains(fmt!("%s=%s", k, v)));
+            assert!(k.is_empty() || output.contains(fmt!("%s=%s", *k, *v)));
         }
     }
     #[test]
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 33857556548..a69ffca026b 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -281,16 +281,16 @@ pub trait VectorVector<T> {
 impl<'self, T:Copy> VectorVector<T> for &'self [~[T]] {
     /// Flattens a vector of slices of T into a single vector of T.
     pub fn concat_vec(&self) -> ~[T] {
-        self.flat_map(|&inner| inner)
+        self.flat_map(|inner| copy *inner)
     }
 
     /// Concatenate a vector of vectors, placing a given separator between each.
     pub fn connect_vec(&self, sep: &T) -> ~[T] {
         let mut r = ~[];
         let mut first = true;
-        for self.iter().advance |&inner| {
+        for self.iter().advance |inner| {
             if first { first = false; } else { r.push(copy *sep); }
-            r.push_all(inner);
+            r.push_all(copy *inner);
         }
         r
     }
@@ -1256,16 +1256,15 @@ impl<T> OwnedVector<T> for ~[T] {
     /// ~~~
     #[inline]
     fn push_all_move(&mut self, mut rhs: ~[T]) {
-        let new_len = self.len() + rhs.len();
+        let self_len = self.len();
+        let rhs_len = rhs.len();
+        let new_len = self_len + rhs_len;
         self.reserve(new_len);
-        unsafe {
-            do rhs.as_mut_buf |p, len| {
-                for uint::range(0, len) |i| {
-                    let x = ptr::replace_ptr(ptr::mut_offset(p, i),
-                                             intrinsics::uninit());
-                    self.push(x);
-                }
-            }
+        unsafe { // Note: infallible.
+            let self_p = vec::raw::to_mut_ptr(*self);
+            let rhs_p = vec::raw::to_ptr(rhs);
+            ptr::copy_memory(ptr::mut_offset(self_p, self_len), rhs_p, rhs_len);
+            raw::set_len(self, new_len);
             raw::set_len(&mut rhs, 0);
         }
     }
@@ -1277,9 +1276,8 @@ impl<T> OwnedVector<T> for ~[T] {
             ln => {
                 let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]);
                 unsafe {
-                    let val = ptr::replace_ptr(valptr, intrinsics::init());
                     raw::set_len(self, ln - 1u);
-                    Some(val)
+                    Some(ptr::read_ptr(valptr))
                 }
             }
         }
@@ -1410,7 +1408,7 @@ impl<T> OwnedVector<T> for ~[T] {
             unsafe {
                 // This loop is optimized out for non-drop types.
                 for uint::range(newlen, oldlen) |i| {
-                    ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit());
+                    ptr::read_and_zero_ptr(ptr::mut_offset(p, i));
                 }
             }
         }
@@ -1555,37 +1553,93 @@ pub trait OwnedEqVector<T:Eq> {
 
 impl<T:Eq> OwnedEqVector<T> for ~[T] {
     /**
-     * Remove consecutive repeated elements from a vector; if the vector is
-     * sorted, this removes all duplicates.
-     */
+    * Remove consecutive repeated elements from a vector; if the vector is
+    * sorted, this removes all duplicates.
+    */
     pub fn dedup(&mut self) {
         unsafe {
-            if self.len() == 0 { return; }
-            let mut last_written = 0;
-            let mut next_to_read = 1;
-            do self.as_mut_buf |p, ln| {
-                // last_written < next_to_read <= ln
-                while next_to_read < ln {
-                    // last_written < next_to_read < ln
-                    if *ptr::mut_offset(p, next_to_read) ==
-                        *ptr::mut_offset(p, last_written) {
-                        ptr::replace_ptr(ptr::mut_offset(p, next_to_read),
-                                         intrinsics::uninit());
-                    } else {
-                        last_written += 1;
-                        // last_written <= next_to_read < ln
-                        if next_to_read != last_written {
-                            ptr::swap_ptr(ptr::mut_offset(p, last_written),
-                                          ptr::mut_offset(p, next_to_read));
-                        }
+            // Although we have a mutable reference to `self`, we cannot make
+            // *arbitrary* changes. There exists the possibility that this
+            // vector is contained with an `@mut` box and hence is still
+            // readable by the outside world during the `Eq` comparisons.
+            // Moreover, those comparisons could fail, so we must ensure
+            // that the vector is in a valid state at all time.
+            //
+            // The way that we handle this is by using swaps; we iterate
+            // over all the elements, swapping as we go so that at the end
+            // the elements we wish to keep are in the front, and those we
+            // wish to reject are at the back. We can then truncate the
+            // vector. This operation is still O(n).
+            //
+            // Example: We start in this state, where `r` represents "next
+            // read" and `w` represents "next_write`.
+            //
+            //           r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //           w
+            //
+            // Comparing self[r] against self[w-1], tis is not a duplicate, so
+            // we swap self[r] and self[w] (no effect as r==w) and then increment both
+            // r and w, leaving us with:
+            //
+            //               r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //               w
+            //
+            // Comparing self[r] against self[w-1], this value is a duplicate,
+            // so we increment `r` but leave everything else unchanged:
+            //
+            //                   r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //               w
+            //
+            // Comparing self[r] against self[w-1], this is not a duplicate,
+            // so swap self[r] and self[w] and advance r and w:
+            //
+            //                       r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 2 | 1 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //                   w
+            //
+            // Not a duplicate, repeat:
+            //
+            //                           r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 2 | 3 | 1 | 3 |
+            //     +---+---+---+---+---+---+
+            //                       w
+            //
+            // Duplicate, advance r. End of vec. Truncate to w.
+
+            let ln = self.len();
+            if ln < 1 { return; }
+
+            // Avoid bounds checks by using unsafe pointers.
+            let p = vec::raw::to_mut_ptr(*self);
+            let mut r = 1;
+            let mut w = 1;
+
+            while r < ln {
+                let p_r = ptr::mut_offset(p, r);
+                let p_wm1 = ptr::mut_offset(p, w - 1);
+                if *p_r != *p_wm1 {
+                    if r != w {
+                        let p_w = ptr::mut_offset(p_wm1, 1);
+                        util::swap(&mut *p_r, &mut *p_w);
                     }
-                    // last_written <= next_to_read < ln
-                    next_to_read += 1;
-                    // last_written < next_to_read <= ln
+                    w += 1;
                 }
+                r += 1;
             }
-            // last_written < next_to_read == ln
-            raw::set_len(self, last_written + 1);
+
+            self.truncate(w);
         }
     }
 }
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index 01769482d08..3bc16477c80 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -519,8 +519,8 @@ impl<'self> MethodDef<'self> {
         // create the generics that aren't for Self
         let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
 
-        let args = do arg_types.map |&(id, ty)| {
-            cx.arg(span, id, ty)
+        let args = do arg_types.map |pair| {
+            cx.arg(span, pair.first(), pair.second())
         };
 
         let ret_type = self.get_ret_ty(cx, span, generics, type_ident);
@@ -589,7 +589,7 @@ impl<'self> MethodDef<'self> {
 
         // transpose raw_fields
         let fields = match raw_fields {
-            [self_arg, .. rest] => {
+            [ref self_arg, .. rest] => {
                 do self_arg.iter().enumerate().transform |(i, &(opt_id, field))| {
                     let other_fields = do rest.map |l| {
                         match &l[i] {
@@ -738,16 +738,20 @@ impl<'self> MethodDef<'self> {
 
                     let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]);
 
-                    for matches_so_far.tail().iter().advance |&(_, _, other_fields)| {
-                        for other_fields.iter().enumerate().advance |(i, &(_, other_field))| {
-                            enum_matching_fields[i].push(other_field);
+                    for matches_so_far.tail().iter().advance |triple| {
+                        match triple {
+                            &(_, _, ref other_fields) => {
+                                for other_fields.iter().enumerate().advance |(i, pair)| {
+                                    enum_matching_fields[i].push(pair.second());
+                                }
+                            }
                         }
                     }
                     let field_tuples =
                         do self_vec.iter()
                            .zip(enum_matching_fields.iter())
-                           .transform |(&(id, self_f), &other)| {
-                        (id, self_f, other)
+                           .transform |(&(id, self_f), other)| {
+                        (id, self_f, copy *other)
                     }.collect();
                     substructure = EnumMatching(variant_index, variant, field_tuples);
                 }
@@ -892,8 +896,8 @@ pub fn create_subpatterns(cx: @ExtCtxt,
                           field_paths: ~[ast::Path],
                           mutbl: ast::mutability)
                    -> ~[@ast::pat] {
-    do field_paths.map |&path| {
-        cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), path, None))
+    do field_paths.map |path| {
+        cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), copy *path, None))
     }
 }
 
@@ -1015,7 +1019,8 @@ left-to-right (`true`) or right-to-left (`false`).
 pub fn cs_fold(use_foldl: bool,
                f: &fn(@ExtCtxt, span,
                       old: @expr,
-                      self_f: @expr, other_fs: &[@expr]) -> @expr,
+                      self_f: @expr,
+                      other_fs: &[@expr]) -> @expr,
                base: @expr,
                enum_nonmatch_f: EnumNonMatchFunc,
                cx: @ExtCtxt, span: span,
@@ -1023,11 +1028,13 @@ pub fn cs_fold(use_foldl: bool,
     match *substructure.fields {
         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
             if use_foldl {
-                do all_fields.iter().fold(base) |old, &(_, self_f, other_fs)| {
+                do all_fields.iter().fold(base) |old, triple| {
+                    let (_, self_f, other_fs) = copy *triple;
                     f(cx, span, old, self_f, other_fs)
                 }
             } else {
-                do all_fields.rev_iter().fold(base) |old, &(_, self_f, other_fs)| {
+                do all_fields.rev_iter().fold(base) |old, triple| {
+                    let (_, self_f, other_fs) = copy *triple;
                     f(cx, span, old, self_f, other_fs)
                 }
             }
@@ -1059,7 +1066,8 @@ pub fn cs_same_method(f: &fn(@ExtCtxt, span, ~[@expr]) -> @expr,
     match *substructure.fields {
         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
             // call self_n.method(other_1_n, other_2_n, ...)
-            let called = do all_fields.map |&(_, self_field, other_fields)| {
+            let called = do all_fields.map |triple| {
+                let (_, self_field, other_fields) = copy *triple;
                 cx.expr_method_call(span,
                                     self_field,
                                     substructure.method_ident,
diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs
index 98fc9aa6178..478c0861990 100644
--- a/src/libsyntax/ext/pipes/pipec.rs
+++ b/src/libsyntax/ext/pipes/pipec.rs
@@ -137,7 +137,7 @@ impl gen_send for message {
                 let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str());
 
                 let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter())
-                    .transform(|(&n, t)| cx.arg(span, cx.ident_of(n), copy *t)).collect();
+                    .transform(|(n, t)| cx.arg(span, cx.ident_of(*n), copy *t)).collect();
 
                 let args_ast = vec::append(
                     ~[cx.arg(span,
diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs
index 2fe8456c274..75424b60390 100644
--- a/src/libsyntax/ext/pipes/proto.rs
+++ b/src/libsyntax/ext/pipes/proto.rs
@@ -215,8 +215,8 @@ pub fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>(
 
     // the copy keywords prevent recursive use of dvec
     let states: ~[Tstate] = do (copy proto.states).iter().transform |&s| {
-        let messages: ~[Tmessage] = do (copy s.messages).iter().transform |&m| {
-            let message(name, span, tys, this, next) = m;
+        let messages: ~[Tmessage] = do (copy s.messages).iter().transform |m| {
+            let message(name, span, tys, this, next) = copy *m;
             visitor.visit_message(name, span, tys, this, next)
         }.collect();
         visitor.visit_state(s, messages)
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c43b350abdb..8666c84bbef 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3914,7 +3914,7 @@ impl Parser {
         };
         let full_path = full_path.normalize();
 
-        let maybe_i = do self.sess.included_mod_stack.iter().position |&p| { p == full_path };
+        let maybe_i = do self.sess.included_mod_stack.iter().position |p| { *p == full_path };
         match maybe_i {
             Some(i) => {
                 let stack = &self.sess.included_mod_stack;
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b545c56778e..c3710853615 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -147,7 +147,7 @@ pub fn ty_to_str(ty: &ast::Ty, intr: @ident_interner) -> ~str {
 }
 
 pub fn pat_to_str(pat: &ast::pat, intr: @ident_interner) -> ~str {
-    to_str(pat, print_irrefutable_pat, intr)
+    to_str(pat, print_pat, intr)
 }
 
 pub fn expr_to_str(e: &ast::expr, intr: @ident_interner) -> ~str {
@@ -1240,7 +1240,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) {
                 if first {
                     first = false;
                 } else { space(s.s); word_space(s, "|"); }
-                print_refutable_pat(s, *p);
+                print_pat(s, *p);
             }
             space(s.s);
             match arm.guard {
@@ -1434,7 +1434,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) {
 }
 
 pub fn print_local_decl(s: @ps, loc: &ast::local) {
-    print_irrefutable_pat(s, loc.node.pat);
+    print_pat(s, loc.node.pat);
     match loc.node.ty.node {
       ast::ty_infer => (),
       _ => { word_space(s, ":"); print_type(s, &loc.node.ty); }
@@ -1526,15 +1526,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path,
     print_path_(s, path, false, bounds)
 }
 
-pub fn print_irrefutable_pat(s: @ps, pat: &ast::pat) {
-    print_pat(s, pat, false)
-}
-
-pub fn print_refutable_pat(s: @ps, pat: &ast::pat) {
-    print_pat(s, pat, true)
-}
-
-pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
+pub fn print_pat(s: @ps, pat: &ast::pat) {
     maybe_print_comment(s, pat.span.lo);
     let ann_node = node_pat(s, pat);
     (s.ann.pre)(ann_node);
@@ -1543,20 +1535,18 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
     match pat.node {
       ast::pat_wild => word(s.s, "_"),
       ast::pat_ident(binding_mode, ref path, sub) => {
-          if refutable {
-              match binding_mode {
-                  ast::bind_by_ref(mutbl) => {
-                      word_nbsp(s, "ref");
-                      print_mutability(s, mutbl);
-                  }
-                  ast::bind_infer => {}
+          match binding_mode {
+              ast::bind_by_ref(mutbl) => {
+                  word_nbsp(s, "ref");
+                  print_mutability(s, mutbl);
               }
+              ast::bind_infer => {}
           }
           print_path(s, path, true);
           match sub {
               Some(p) => {
                   word(s.s, "@");
-                  print_pat(s, p, refutable);
+                  print_pat(s, p);
               }
               None => ()
           }
@@ -1569,7 +1559,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
             if !args.is_empty() {
               popen(s);
               commasep(s, inconsistent, *args,
-                       |s, &p| print_pat(s, p, refutable));
+                       |s, &p| print_pat(s, p));
               pclose(s);
             } else { }
           }
@@ -1578,16 +1568,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
       ast::pat_struct(ref path, ref fields, etc) => {
         print_path(s, path, true);
         word(s.s, "{");
-        fn print_field(s: @ps, f: &ast::field_pat, refutable: bool) {
+        fn print_field(s: @ps, f: &ast::field_pat) {
             cbox(s, indent_unit);
             print_ident(s, f.ident);
             word_space(s, ":");
-            print_pat(s, f.pat, refutable);
+            print_pat(s, f.pat);
             end(s);
         }
         fn get_span(f: &ast::field_pat) -> codemap::span { return f.pat.span; }
         commasep_cmnt(s, consistent, *fields,
-                      |s, f| print_field(s,f,refutable),
+                      |s, f| print_field(s,f),
                       get_span);
         if etc {
             if fields.len() != 0u { word_space(s, ","); }
@@ -1597,7 +1587,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
       }
       ast::pat_tup(ref elts) => {
         popen(s);
-        commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p, refutable));
+        commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p));
         if elts.len() == 1 {
             word(s.s, ",");
         }
@@ -1605,15 +1595,15 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
       }
       ast::pat_box(inner) => {
           word(s.s, "@");
-          print_pat(s, inner, refutable);
+          print_pat(s, inner);
       }
       ast::pat_uniq(inner) => {
           word(s.s, "~");
-          print_pat(s, inner, refutable);
+          print_pat(s, inner);
       }
       ast::pat_region(inner) => {
           word(s.s, "&");
-          print_pat(s, inner, refutable);
+          print_pat(s, inner);
       }
       ast::pat_lit(e) => print_expr(s, e),
       ast::pat_range(begin, end) => {
@@ -1625,16 +1615,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) {
       ast::pat_vec(ref before, slice, ref after) => {
         word(s.s, "[");
         do commasep(s, inconsistent, *before) |s, &p| {
-            print_pat(s, p, refutable);
+            print_pat(s, p);
         }
         for slice.iter().advance |&p| {
             if !before.is_empty() { word_space(s, ","); }
             word(s.s, "..");
-            print_pat(s, p, refutable);
+            print_pat(s, p);
             if !after.is_empty() { word_space(s, ","); }
         }
         do commasep(s, inconsistent, *after) |s, &p| {
-            print_pat(s, p, refutable);
+            print_pat(s, p);
         }
         word(s.s, "]");
       }
@@ -1888,7 +1878,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
         word_space(s, "mut");
     }
     match input.ty.node {
-      ast::ty_infer => print_irrefutable_pat(s, input.pat),
+      ast::ty_infer => print_pat(s, input.pat),
       _ => {
         match input.pat.node {
             ast::pat_ident(_, ref path, _) if
@@ -1897,7 +1887,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
                 // Do nothing.
             }
             _ => {
-                print_irrefutable_pat(s, input.pat);
+                print_pat(s, input.pat);
                 word(s.s, ":");
                 space(s.s);
             }
diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp
index a49b52bffe1..012333b931e 100644
--- a/src/rt/boxed_region.cpp
+++ b/src/rt/boxed_region.cpp
@@ -39,10 +39,6 @@ rust_opaque_box *boxed_region::malloc(type_desc *td, size_t body_size) {
 rust_opaque_box *boxed_region::realloc(rust_opaque_box *box,
                                        size_t new_size) {
 
-    // We also get called on the unique-vec-in-managed-heap path.
-    assert(box->ref_count == 1 ||
-           box->ref_count == (size_t)(-2));
-
     size_t total_size = new_size + sizeof(rust_opaque_box);
     rust_opaque_box *new_box =
         (rust_opaque_box*)backing_region->realloc(box, total_size);
diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs
index 974cdb0a0ef..919c4daeb25 100644
--- a/src/test/bench/shootout-k-nucleotide-pipes.rs
+++ b/src/test/bench/shootout-k-nucleotide-pipes.rs
@@ -56,8 +56,8 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str {
    let mut pairs = ~[];
 
    // map -> [(k,%)]
-   for mm.iter().advance |(&key, &val)| {
-      pairs.push((key, pct(val, total)));
+   for mm.iter().advance |(key, &val)| {
+      pairs.push((copy *key, pct(val, total)));
    }
 
    let pairs_sorted = sortKV(pairs);
diff --git a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs
new file mode 100644
index 00000000000..c99a1ee60d7
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs
@@ -0,0 +1,16 @@
+fn with(f: &fn(&~str)) {}
+
+fn arg_item(&_x: &~str) {}
+    //~^ ERROR cannot move out of dereference of & pointer
+
+fn arg_closure() {
+    with(|&_x| ())
+    //~^ ERROR cannot move out of dereference of & pointer
+}
+
+fn let_pat() {
+    let &_x = &~"hi";
+    //~^ ERROR cannot move out of dereference of & pointer
+}
+
+pub fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs
new file mode 100644
index 00000000000..4407329f497
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs
@@ -0,0 +1,22 @@
+struct S {f:~str}
+impl Drop for S {
+    fn drop(&self) { println(self.f); }
+}
+
+fn move_in_match() {
+    match S {f:~"foo"} {
+        S {f:_s} => {}
+        //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    }
+}
+
+fn move_in_let() {
+    let S {f:_s} = S {f:~"foo"};
+    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+}
+
+fn move_in_fn_arg(S {f:_s}: S) {
+    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs
new file mode 100644
index 00000000000..400a4f07951
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs
@@ -0,0 +1,22 @@
+struct S(~str);
+impl Drop for S {
+    fn drop(&self) { println(**self); }
+}
+
+fn move_in_match() {
+    match S(~"foo") {
+        S(_s) => {}
+        //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    }
+}
+
+fn move_in_let() {
+    let S(_s) = S(~"foo");
+    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+}
+
+fn move_in_fn_arg(S(_s): S) {
+    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs
index dec976e0a60..91a3d843cd4 100644
--- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs
+++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs
@@ -11,7 +11,7 @@ pub fn main() {
         Foo { string: ~"baz" }
     ];
     match x {
-        [first, ..tail] => {
+        [_, ..tail] => {
             match tail {
                 [Foo { string: a }, Foo { string: b }] => {
                     //~^ ERROR cannot move out of dereference of & pointer
diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs
index 81f052918ed..36ae5f88208 100644
--- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs
+++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs
@@ -17,4 +17,41 @@ fn b() {
     }
 }
 
+fn c() {
+    let mut vec = [~1, ~2, ~3];
+    match vec {
+        [_a, .._b] => {
+            //~^ ERROR cannot move out
+
+            // Note: `_a` is *moved* here, but `b` is borrowing,
+            // hence illegal.
+            //
+            // See comment in middle/borrowck/gather_loans/mod.rs
+            // in the case covering these sorts of vectors.
+        }
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR use of partially moved value: `vec`
+}
+
+fn d() {
+    let mut vec = [~1, ~2, ~3];
+    match vec {
+        [.._a, _b] => {
+            //~^ ERROR cannot move out
+        }
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR use of partially moved value: `vec`
+}
+
+fn e() {
+    let mut vec = [~1, ~2, ~3];
+    match vec {
+        [_a, _b, _c] => {}
+        _ => {}
+    }
+    let a = vec[0]; //~ ERROR use of partially moved value: `vec`
+}
+
 fn main() {}
diff --git a/src/test/compile-fail/regions-ref-in-fn-arg.rs b/src/test/compile-fail/regions-ref-in-fn-arg.rs
new file mode 100644
index 00000000000..f90fe924587
--- /dev/null
+++ b/src/test/compile-fail/regions-ref-in-fn-arg.rs
@@ -0,0 +1,11 @@
+fn arg_item(~ref x: ~int) -> &'static int {
+    x //~^ ERROR borrowed value does not live long enough
+}
+
+fn with<R>(f: &fn(~int) -> R) -> R { f(~3) }
+
+fn arg_closure() -> &'static int {
+    with(|~ref x| x) //~ ERROR borrowed value does not live long enough
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs
index 9a3ba32390c..92344aae73e 100644
--- a/src/test/run-pass-fulldeps/qquote.rs
+++ b/src/test/run-pass-fulldeps/qquote.rs
@@ -68,7 +68,7 @@ fn main() {
     check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;");
 
     let pat = quote_pat!(Some(_));
-    check_pp(ext_cx, pat, pprust::print_refutable_pat, ~"Some(_)");
+    check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)");
 
 }
 
diff --git a/src/test/run-pass/borrowck-newtype-issue-2573.rs b/src/test/run-pass/borrowck-newtype-issue-2573.rs
deleted file mode 100644
index 5f0c7cad619..00000000000
--- a/src/test/run-pass/borrowck-newtype-issue-2573.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct foo {bar: baz}
-
-struct baz_ {baz: int}
-
-type baz = @mut baz_;
-
-trait frob {
-    fn frob(&self);
-}
-
-impl frob for foo {
-    fn frob(&self) {
-        really_impure(self.bar);
-    }
-}
-
-// Override default mode so that we are passing by value
-fn really_impure(bar: baz) {
-    bar.baz = 3;
-}
-
-pub fn main() {}
diff --git a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs
index 056397f55ff..5da7a6f2b56 100644
--- a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs
+++ b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs
@@ -28,12 +28,12 @@
 
 
 fn main() {
-    let a = @mut [3i];
+    let a = @mut 3i;
     let b = @mut [a];
-    let c = @mut b;
+    let c = @mut [3];
 
     // this should freeze `a` only
-    let _x: &mut [int] = c[0];
+    let _x: &mut int = a;
 
     // hence these writes should not fail:
     b[0] = b[0];
diff --git a/src/test/run-pass/func-arg-incomplete-pattern.rs b/src/test/run-pass/func-arg-incomplete-pattern.rs
new file mode 100644
index 00000000000..b08d3beae1b
--- /dev/null
+++ b/src/test/run-pass/func-arg-incomplete-pattern.rs
@@ -0,0 +1,20 @@
+// Test that we do not leak when the arg pattern must drop part of the
+// argument (in this case, the `y` field).
+
+struct Foo {
+    x: ~uint,
+    y: ~uint,
+}
+
+fn foo(Foo {x, _}: Foo) -> *uint {
+    let addr: *uint = &*x;
+    addr
+}
+
+fn main() {
+    let obj = ~1;
+    let objptr: *uint = &*obj;
+    let f = Foo {x: obj, y: ~2};
+    let xptr = foo(f);
+    assert_eq!(objptr, xptr);
+}
\ No newline at end of file
diff --git a/src/test/run-pass/func-arg-ref-pattern.rs b/src/test/run-pass/func-arg-ref-pattern.rs
new file mode 100644
index 00000000000..84c2b3acf35
--- /dev/null
+++ b/src/test/run-pass/func-arg-ref-pattern.rs
@@ -0,0 +1,24 @@
+// exec-env:RUST_POISON_ON_FREE=1
+
+// Test argument patterns where we create refs to the inside of `~`
+// boxes. Make sure that we don't free the box as we match the
+// pattern.
+
+fn getaddr(~ref x: ~uint) -> *uint {
+    let addr: *uint = &*x;
+    addr
+}
+
+fn checkval(~ref x: ~uint) -> uint {
+    *x
+}
+
+fn main() {
+    let obj = ~1;
+    let objptr: *uint = &*obj;
+    let xptr = getaddr(obj);
+    assert_eq!(objptr, xptr);
+
+    let obj = ~22;
+    assert_eq!(checkval(obj), 22);
+}
diff --git a/src/test/run-pass/func-arg-wild-pattern.rs b/src/test/run-pass/func-arg-wild-pattern.rs
new file mode 100644
index 00000000000..c2d60c85329
--- /dev/null
+++ b/src/test/run-pass/func-arg-wild-pattern.rs
@@ -0,0 +1,10 @@
+// Test that we can compile code that uses a `_` in function argument
+// patterns.
+
+fn foo((x, _): (int, int)) -> int {
+    x
+}
+
+fn main() {
+    assert_eq!(foo((22, 23)), 22);
+}
diff --git a/src/test/run-pass/let-destruct-ref.rs b/src/test/run-pass/let-destruct-ref.rs
new file mode 100644
index 00000000000..7f3f9110b1c
--- /dev/null
+++ b/src/test/run-pass/let-destruct-ref.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let x = ~"hello";
+    let ref y = x;
+    assert_eq!(x.slice(0, x.len()), y.slice(0, y.len()));
+}
diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs
new file mode 100644
index 00000000000..2a629b62534
--- /dev/null
+++ b/src/test/run-pass/match-drop-strs-issue-4541.rs
@@ -0,0 +1,27 @@
+// Tests a tricky scenario involving string matching,
+// copying, and moving to ensure that we don't segfault
+// or double-free, as we were wont to do in the past.
+
+use std::io;
+use std::os;
+
+fn parse_args() -> ~str {
+    let args = os::args();
+    let mut n = 0;
+
+    while n < args.len() {
+        match copy args[n] {
+            ~"-v" => (),
+            s => {
+                return s;
+            }
+        }
+        n += 1;
+    }
+
+    return ~""
+}
+
+fn main() {
+    io::println(parse_args());
+}
diff --git a/src/test/run-pass/match-pattern-drop.rs b/src/test/run-pass/match-pattern-drop.rs
index 71bbb1768e8..3ce4ef8a94c 100644
--- a/src/test/run-pass/match-pattern-drop.rs
+++ b/src/test/run-pass/match-pattern-drop.rs
@@ -14,8 +14,11 @@
 enum t { make_t(@int), clam, }
 
 fn foo(s: @int) {
+    debug!(::std::sys::refcount(s));
     let count = ::std::sys::refcount(s);
     let x: t = make_t(s); // ref up
+    assert_eq!(::std::sys::refcount(s), count + 1u);
+    debug!(::std::sys::refcount(s));
 
     match x {
       make_t(y) => {
@@ -38,6 +41,5 @@ pub fn main() {
 
     debug!("%u", ::std::sys::refcount(s));
     let count2 = ::std::sys::refcount(s);
-    let _ = ::std::sys::refcount(s); // don't get bitten by last-use.
     assert_eq!(count, count2);
 }
diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs
index 4ce229526ff..f8c369c2e5f 100644
--- a/src/test/run-pass/reflect-visit-type.rs
+++ b/src/test/run-pass/reflect-visit-type.rs
@@ -163,8 +163,8 @@ pub fn main() {
     visit_ty::<i16>(vv);
     visit_ty::<~[int]>(vv);
 
-    for v.types.iter().advance |&s| {
-        println(fmt!("type: %s", s));
+    for v.types.iter().advance |s| {
+        println(fmt!("type: %s", copy *s));
     }
     assert_eq!((*v.types).clone(), ~[~"bool", ~"int", ~"i8", ~"i16", ~"[", ~"int", ~"]"]);
 }
diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs
index 6e1a47ad2df..27f4fc83351 100644
--- a/src/test/run-pass/vec-tail-matching.rs
+++ b/src/test/run-pass/vec-tail-matching.rs
@@ -9,7 +9,7 @@ pub fn main() {
         Foo { string: ~"baz" }
     ];
     match x {
-        [first, ..tail] => {
+        [ref first, ..tail] => {
             assert!(first.string == ~"foo");
             assert_eq!(tail.len(), 2);
             assert!(tail[0].string == ~"bar");