about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-08 18:49:46 -0700
committerbors <bors@rust-lang.org>2013-07-08 18:49:46 -0700
commita48ca3290df992fde2f74ccf5b9f4e36563af8da (patch)
tree816142177cf53d6185626aee592ef837b5e1d93a /src
parent30c8aac677a754e0d4ebc16f261618f15d15a6e2 (diff)
parent0c6d02f391aa668b2ead91e8a4ed545475ac2c90 (diff)
downloadrust-a48ca3290df992fde2f74ccf5b9f4e36563af8da.tar.gz
rust-a48ca3290df992fde2f74ccf5b9f4e36563af8da.zip
auto merge of #7262 : nikomatsakis/rust/ref-bindings-in-irrefut-patterns, r=catamorphism
Correct treatment of irrefutable patterns. The old code was wrong in many, many ways. `ref` bindings didn't work, it sometimes copied when it should have moved, the borrow checker didn't even look at such patterns at all, we weren't consistent about preventing values with destructors from being pulled apart, etc.

Fixes #3224.
Fixes #3225.
Fixes #3255.
Fixes #6225.
Fixes #6386.

r? @catamorphism

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");