about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-01-10 10:59:58 -0800
committerNiko Matsakis <niko@alum.mit.edu>2013-01-31 12:09:00 -0800
commit0682ad0eb9a6b268498a81b2e16a40544e44f0fa (patch)
tree694819bae28cd319401c121afa4daa00adcbdde2
parent42b462e0765f02fd7bb0f2613240ae2489a47fee (diff)
downloadrust-0682ad0eb9a6b268498a81b2e16a40544e44f0fa.tar.gz
rust-0682ad0eb9a6b268498a81b2e16a40544e44f0fa.zip
Finalize moves-based-on-type implementation.
Changes:

- Refactor move mode computation
- Removes move mode arguments, unary move, capture clauses
  (though they still parse for backwards compatibility)
- Simplify how moves are handled in trans
- Fix a number of illegal copies that cropped up
- Workaround for bug involving def-ids in params
  (see details below)

Future work (I'll open bugs for these...):

- Improve error messages for moves that are due
  to bindings
- Add support for moving owned content like a.b.c
  to borrow check, test in trans (but I think it'll
  "just work")
- Proper fix for def-ids in params

Def ids in params:

Move captures into a map instead of recomputing.

This is a workaround for a larger bug having to do with the def-ids associated
with ty_params, which are not always properly preserved when inlining.  I am
not sure of my preferred fix for the larger bug yet.  This current fix removes
the only code in trans that I know of which relies on ty_param def-ids, but
feels fragile.
-rw-r--r--doc/rust.md2
-rw-r--r--doc/tutorial-tasks.md4
-rw-r--r--src/etc/tidy.py2
-rw-r--r--src/libcargo/cargo.rc18
-rw-r--r--src/libcore/private/global.rs6
-rw-r--r--src/libcore/task/mod.rs11
-rw-r--r--src/librustc/back/rpath.rs2
-rw-r--r--src/librustc/driver/driver.rs36
-rw-r--r--src/librustc/front/config.rs2
-rw-r--r--src/librustc/front/test.rs4
-rw-r--r--src/librustc/lib/llvm.rs9
-rw-r--r--src/librustc/metadata/common.rs3
-rw-r--r--src/librustc/metadata/creader.rs7
-rw-r--r--src/librustc/metadata/encoder.rs60
-rw-r--r--src/librustc/metadata/loader.rs5
-rw-r--r--src/librustc/metadata/tydecode.rs2
-rw-r--r--src/librustc/metadata/tyencode.rs1
-rw-r--r--src/librustc/middle/astencode.rs96
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs215
-rw-r--r--src/librustc/middle/borrowck/gather_loans.rs57
-rw-r--r--src/librustc/middle/borrowck/loan.rs9
-rw-r--r--src/librustc/middle/borrowck/mod.rs108
-rw-r--r--src/librustc/middle/borrowck/preserve.rs112
-rw-r--r--src/librustc/middle/capture.rs141
-rw-r--r--src/librustc/middle/check_loop.rs6
-rw-r--r--src/librustc/middle/check_match.rs98
-rw-r--r--src/librustc/middle/const_eval.rs12
-rw-r--r--src/librustc/middle/freevars.rs3
-rw-r--r--src/librustc/middle/kind.rs400
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/lint.rs8
-rw-r--r--src/librustc/middle/liveness.rs307
-rw-r--r--src/librustc/middle/mem_categorization.rs26
-rw-r--r--src/librustc/middle/mode.rs281
-rw-r--r--src/librustc/middle/moves.rs815
-rw-r--r--src/librustc/middle/pat_util.rs28
-rw-r--r--src/librustc/middle/region.rs9
-rw-r--r--src/librustc/middle/resolve.rs52
-rw-r--r--src/librustc/middle/trans/_match.rs35
-rw-r--r--src/librustc/middle/trans/base.rs14
-rw-r--r--src/librustc/middle/trans/build.rs2
-rw-r--r--src/librustc/middle/trans/callee.rs52
-rw-r--r--src/librustc/middle/trans/closure.rs100
-rw-r--r--src/librustc/middle/trans/common.rs4
-rw-r--r--src/librustc/middle/trans/datum.rs138
-rw-r--r--src/librustc/middle/trans/debuginfo.rs6
-rw-r--r--src/librustc/middle/trans/expr.rs548
-rw-r--r--src/librustc/middle/trans/foreign.rs15
-rw-r--r--src/librustc/middle/trans/reflect.rs1
-rw-r--r--src/librustc/middle/trans/type_of.rs8
-rw-r--r--src/librustc/middle/trans/type_use.rs8
-rw-r--r--src/librustc/middle/ty.rs136
-rw-r--r--src/librustc/middle/typeck/check/_match.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs29
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs1
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs18
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs2
-rw-r--r--src/librustc/middle/typeck/infer/lattice.rs12
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs12
-rw-r--r--src/librustc/rustc.rc11
-rw-r--r--src/librustc/util/ppaux.rs11
-rw-r--r--src/librustdoc/attr_pass.rs35
-rw-r--r--src/librustdoc/desc_to_brief_pass.rs5
-rw-r--r--src/librustdoc/markdown_index_pass.rs5
-rw-r--r--src/librustdoc/markdown_pass.rs9
-rw-r--r--src/librustdoc/text_pass.rs5
-rw-r--r--src/librustdoc/tystr_pass.rs133
-rw-r--r--src/libstd/flatpipes.rs8
-rw-r--r--src/libstd/net_ip.rs3
-rw-r--r--src/libstd/par.rs9
-rw-r--r--src/libsyntax/ast.rs65
-rw-r--r--src/libsyntax/ast_util.rs9
-rw-r--r--src/libsyntax/attr.rs4
-rw-r--r--src/libsyntax/ext/auto_encode.rs9
-rw-r--r--src/libsyntax/ext/build.rs7
-rw-r--r--src/libsyntax/ext/pipes/ast_builder.rs12
-rw-r--r--src/libsyntax/fold.rs27
-rw-r--r--src/libsyntax/parse/parser.rs141
-rw-r--r--src/libsyntax/print/pprust.rs47
-rw-r--r--src/libsyntax/visit.rs13
-rw-r--r--src/test/bench/graph500-bfs.rs3
-rw-r--r--src/test/compile-fail/alt-vec-tail-move.rs8
-rw-r--r--src/test/compile-fail/block-deinitializes-upvar.rs18
-rw-r--r--src/test/compile-fail/borrowck-loan-blocks-move-cc.rs16
-rw-r--r--src/test/compile-fail/borrowck-move-by-capture.rs18
-rw-r--r--src/test/compile-fail/borrowck-vec-pattern-move-tail.rs8
-rw-r--r--src/test/compile-fail/cap-clause-both-copy-and-move.rs15
-rw-r--r--src/test/compile-fail/cap-clause-double-copy.rs15
-rw-r--r--src/test/compile-fail/cap-clause-double-move.rs15
-rw-r--r--src/test/compile-fail/cap-clause-illegal-cap.rs32
-rw-r--r--src/test/compile-fail/cap-clause-move-upvar.rs17
-rw-r--r--src/test/compile-fail/cap-clause-unresolved-copy.rs16
-rw-r--r--src/test/compile-fail/cap-clause-unresolved-move.rs16
-rw-r--r--src/test/compile-fail/cap-clause-use-after-move.rs15
-rw-r--r--src/test/compile-fail/cap-clause-with-stack-closure.rs24
-rw-r--r--src/test/compile-fail/copy-into-closure.rs30
-rw-r--r--src/test/compile-fail/functional-struct-update.rs2
-rw-r--r--src/test/compile-fail/issue-1965.rs17
-rw-r--r--src/test/compile-fail/kindck-implicit-close-over-mut-var.rs9
-rw-r--r--src/test/compile-fail/liveness-move-call-arg.rs (renamed from src/test/compile-fail/unary-move.rs)11
-rw-r--r--src/test/compile-fail/liveness-move-from-args.rs18
-rw-r--r--src/test/compile-fail/liveness-move-in-loop.rs11
-rw-r--r--src/test/compile-fail/liveness-move-in-while.rs10
-rw-r--r--src/test/compile-fail/liveness-use-after-move.rs4
-rw-r--r--src/test/compile-fail/liveness-use-after-send.rs4
-rw-r--r--src/test/compile-fail/moves-based-on-type-access-to-field.rs20
-rw-r--r--src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs43
-rw-r--r--src/test/compile-fail/moves-based-on-type-exprs.rs95
-rw-r--r--src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs (renamed from src/test/compile-fail/liveness-move-from-mode.rs)10
-rw-r--r--src/test/compile-fail/no-reuse-move-arc.rs2
-rw-r--r--src/test/compile-fail/no-send-res-ports.rs6
-rw-r--r--src/test/compile-fail/use-after-move-self.rs8
-rw-r--r--src/test/pretty/cap-clause.rs27
-rw-r--r--src/test/run-fail/unwind-lambda.rs1
-rw-r--r--src/test/run-pass/assignability-trait.rs2
-rw-r--r--src/test/run-pass/borrowck-borrow-from-expr-block.rs3
-rw-r--r--src/test/run-pass/cap-clause-move.rs8
-rw-r--r--src/test/run-pass/last-use-corner-cases.rs44
-rw-r--r--src/test/run-pass/move-1-unique.rs6
-rw-r--r--src/test/run-pass/move-3-unique.rs2
-rw-r--r--src/test/run-pass/newtype-polymorphic.rs4
-rw-r--r--src/test/run-pass/task-comm-14.rs2
-rw-r--r--src/test/run-pass/task-comm-3.rs9
-rw-r--r--src/test/run-pass/task-spawn-move-and-copy.rs13
-rw-r--r--src/test/run-pass/threads.rs2
125 files changed, 2685 insertions, 2644 deletions
diff --git a/doc/rust.md b/doc/rust.md
index e31441c7cd2..7a5b8dfd004 100644
--- a/doc/rust.md
+++ b/doc/rust.md
@@ -1234,7 +1234,7 @@ For example:
 
 ~~~~
 trait Num {
-    static pure fn from_int(n: int) -> self;
+    static pure fn from_int(n: int) -> Self;
 }
 impl float: Num {
     static pure fn from_int(n: int) -> float { n as float }
diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md
index 26541eca7d3..98ed6b86584 100644
--- a/doc/tutorial-tasks.md
+++ b/doc/tutorial-tasks.md
@@ -440,8 +440,8 @@ Finally, tasks can be configured to not propagate failure to each
 other at all, using `task::spawn_unlinked` for _isolated failure_.
 
 ~~~
-# fn random() -> int { 100 }
-# fn sleep_for(i: int) { for i.times { task::yield() } }
+# fn random() -> uint { 100 }
+# fn sleep_for(i: uint) { for i.times { task::yield() } }
 # do task::try::<()> {
 let (time1, time2) = (random(), random());
 do task::spawn_unlinked {
diff --git a/src/etc/tidy.py b/src/etc/tidy.py
index 65737c53e61..997a9dd50fd 100644
--- a/src/etc/tidy.py
+++ b/src/etc/tidy.py
@@ -51,7 +51,7 @@ try:
                 report_err("TODO is deprecated; use FIXME")
             idx = line.find("// NOTE")
             if idx != -1:
-                report_warn("NOTE:" + line[idx + len("// NOTE"):])
+                report_warn("NOTE" + line[idx + len("// NOTE"):])
         if (line.find('\t') != -1 and
             fileinput.filename().find("Makefile") == -1):
             report_err("tab character")
diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc
index f2a7c5c3cf4..bb5e3f9f74d 100644
--- a/src/libcargo/cargo.rc
+++ b/src/libcargo/cargo.rc
@@ -1965,19 +1965,17 @@ pub fn main() {
         c = configure(o);
     }
 
-    let c = &move c;
-
     match o.free[1] {
-        ~"init" => cmd_init(c),
-        ~"install" => cmd_install(c),
-        ~"uninstall" => cmd_uninstall(c),
-        ~"list" => cmd_list(c),
-        ~"search" => cmd_search(c),
-        ~"sources" => cmd_sources(c),
+        ~"init" => cmd_init(&c),
+        ~"install" => cmd_install(&c),
+        ~"uninstall" => cmd_uninstall(&c),
+        ~"list" => cmd_list(&c),
+        ~"search" => cmd_search(&c),
+        ~"sources" => cmd_sources(&c),
         _ => cmd_usage()
     }
 
-    dump_cache(c);
-    dump_sources(c);
+    dump_cache(&c);
+    dump_sources(&c);
 }
 
diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs
index ee20fb665be..f129022957c 100644
--- a/src/libcore/private/global.rs
+++ b/src/libcore/private/global.rs
@@ -177,8 +177,10 @@ fn get_global_state() -> Exclusive<GlobalState> {
         let state = ~exclusive(state);
 
         // Convert it to an integer
-        let state_ptr: &Exclusive<GlobalState> = state;
-        let state_i: int = unsafe { transmute(state_ptr) };
+        let state_i: int = unsafe {
+            let state_ptr: &Exclusive<GlobalState> = state;
+            transmute(state_ptr)
+        };
 
         // Swap our structure into the global pointer
         let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) };
diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs
index 9ddafee6938..62d317abb95 100644
--- a/src/libcore/task/mod.rs
+++ b/src/libcore/task/mod.rs
@@ -837,11 +837,19 @@ fn test_run_basic() {
 }
 
 #[test]
+struct Wrapper {
+    mut f: Option<Chan<()>>
+}
+
+#[test]
 fn test_add_wrapper() {
     let (po, ch) = stream::<()>();
     let b0 = task();
+    let ch = Wrapper { f: Some(ch) };
     let b1 = do b0.add_wrapper |body| {
+        let ch = Wrapper { f: Some(ch.f.swap_unwrap()) };
         fn~(move body) {
+            let ch = ch.f.swap_unwrap();
             body();
             ch.send(());
         }
@@ -929,9 +937,12 @@ fn test_spawn_sched_childs_on_default_sched() {
     // Assuming tests run on the default scheduler
     let default_id = unsafe { rt::rust_get_sched_id() };
 
+    let ch = Wrapper { f: Some(ch) };
     do spawn_sched(SingleThreaded) {
         let parent_sched_id = unsafe { rt::rust_get_sched_id() };
+        let ch = Wrapper { f: Some(ch.f.swap_unwrap()) };
         do spawn {
+            let ch = ch.f.swap_unwrap();
             let child_sched_id = unsafe { rt::rust_get_sched_id() };
             assert parent_sched_id != child_sched_id;
             assert child_sched_id == default_id;
diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs
index 7440f3f70ac..560b26951a6 100644
--- a/src/librustc/back/rpath.rs
+++ b/src/librustc/back/rpath.rs
@@ -191,7 +191,7 @@ pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
     let mut minimized = ~[];
     for rpaths.each |rpath| {
         let s = rpath.to_str();
-        if !set.contains_key(s) {
+        if !set.contains_key_ref(&s) {
             minimized.push(/*bad*/copy *rpath);
             set.insert(s, ());
         }
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 12281e0b980..eca6a598f8d 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -16,7 +16,7 @@ use front;
 use lib::llvm::llvm;
 use metadata::{creader, cstore, filesearch};
 use metadata;
-use middle::{trans, freevars, kind, ty, typeck, lint};
+use middle::{trans, freevars, kind, ty, typeck, lint, astencode};
 use middle;
 use session::{Session, Session_, OptLevel, No, Less, Default, Aggressive};
 use session;
@@ -281,20 +281,26 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
         time(time_passes, ~"loop checking", ||
              middle::check_loop::check_crate(ty_cx, crate));
 
-        time(time_passes, ~"mode computation", ||
-             middle::mode::compute_modes(ty_cx, method_map, crate));
+        let middle::moves::MoveMaps {moves_map, variable_moves_map,
+                                     capture_map} =
+            time(time_passes, ~"compute moves", ||
+                 middle::moves::compute_moves(ty_cx, method_map, crate));
 
         time(time_passes, ~"match checking", ||
-             middle::check_match::check_crate(ty_cx, method_map, crate));
+             middle::check_match::check_crate(ty_cx, method_map,
+                                              moves_map, crate));
 
         let last_use_map =
             time(time_passes, ~"liveness checking", ||
-                 middle::liveness::check_crate(ty_cx, method_map, crate));
+                 middle::liveness::check_crate(ty_cx, method_map,
+                                               variable_moves_map,
+                                               capture_map, crate));
 
         let (root_map, mutbl_map, write_guard_map) =
             time(time_passes, ~"borrow checking", ||
                  middle::borrowck::check_crate(ty_cx, method_map,
-                                               last_use_map, crate));
+                                               moves_map, capture_map,
+                                               crate));
 
         time(time_passes, ~"kind checking", ||
              kind::check_crate(ty_cx, method_map, last_use_map, crate));
@@ -304,12 +310,16 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
 
         if upto == cu_no_trans { return {crate: crate, tcx: Some(ty_cx)}; }
 
-        let maps = {mutbl_map: mutbl_map,
-                    root_map: root_map,
-                    last_use_map: last_use_map,
-                    method_map: method_map,
-                    vtable_map: vtable_map,
-                    write_guard_map: write_guard_map};
+        let maps = astencode::Maps {
+            mutbl_map: mutbl_map,
+            root_map: root_map,
+            last_use_map: last_use_map,
+            method_map: method_map,
+            vtable_map: vtable_map,
+            write_guard_map: write_guard_map,
+            moves_map: moves_map,
+            capture_map: capture_map
+        };
 
         time(time_passes, ~"translation", ||
              trans::base::trans_crate(sess, crate, ty_cx,
@@ -528,7 +538,7 @@ pub fn build_session_options(+binary: ~str,
                                 getopts::opt_strs(matches, level_name));
         for flags.each |lint_name| {
             let lint_name = str::replace(*lint_name, ~"-", ~"_");
-            match lint_dict.find(lint_name) {
+            match lint_dict.find(/*bad*/ copy lint_name) {
               None => {
                 early_error(demitter, fmt!("unknown %s flag: %s",
                                            level_name, lint_name));
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index 9195da2a166..a7c071919ff 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -190,7 +190,7 @@ pub fn metas_in_cfg(cfg: ast::crate_cfg,
     if !has_cfg_metas { return true; }
 
     for cfg_metas.each |cfg_mi| {
-        if attr::contains(/*bad*/copy cfg, *cfg_mi) { return true; }
+        if attr::contains(cfg, *cfg_mi) { return true; }
     }
 
     return false;
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 8e4d17e6eba..53c2f71c548 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -46,7 +46,7 @@ pub fn modify_for_testing(sess: session::Session,
     // We generate the test harness when building in the 'test'
     // configuration, either with the '--test' or '--cfg test'
     // command line options.
-    let should_test = attr::contains(/*bad*/copy crate.node.config,
+    let should_test = attr::contains(crate.node.config,
                                      attr::mk_word_item(~"test"));
 
     if should_test {
@@ -510,7 +510,7 @@ fn mk_test_wrapper(cx: test_ctxt,
     let wrapper_expr = ast::expr  {
         id: cx.sess.next_node_id(),
         callee_id: cx.sess.next_node_id(),
-        node: ast::expr_fn(ast::ProtoBare, wrapper_decl, wrapper_body, @~[]),
+        node: ast::expr_fn(ast::ProtoBare, wrapper_decl, wrapper_body),
         span: span
     };
 
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 8f2774f15fa..375a3b43aad 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -1344,10 +1344,10 @@ pub fn mk_type_names() -> type_names {
 }
 
 pub fn type_to_str(names: type_names, ty: TypeRef) -> @str {
-    return type_to_str_inner(names, ~[], ty);
+    return type_to_str_inner(names, [], ty);
 }
 
-pub fn type_to_str_inner(names: type_names, +outer0: ~[TypeRef], ty: TypeRef)
+pub fn type_to_str_inner(names: type_names, +outer0: &[TypeRef], ty: TypeRef)
                       -> @str {
     unsafe {
         match type_has_name(names, ty) {
@@ -1355,12 +1355,11 @@ pub fn type_to_str_inner(names: type_names, +outer0: ~[TypeRef], ty: TypeRef)
           _ => {}
         }
 
-        // FIXME #2543: Bad copy.
-        let outer = vec::append_one(copy outer0, ty);
+        let outer = vec::append_one(outer0.to_vec(), ty);
 
         let kind = llvm::LLVMGetTypeKind(ty);
 
-        fn tys_str(names: type_names, outer: ~[TypeRef],
+        fn tys_str(names: type_names, outer: &[TypeRef],
                    tys: ~[TypeRef]) -> @str {
             let mut s = ~"";
             let mut first: bool = true;
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 52f7c874af4..37c19e80600 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -133,7 +133,8 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f
     tag_table_vtable_map = 0x61,
     tag_table_adjustments = 0x62,
     tag_table_legacy_boxed_trait = 0x63,
-    tag_table_value_mode = 0x64
+    tag_table_moves_map = 0x64,
+    tag_table_capture_map = 0x65
 }
 
 pub const tag_item_trait_method_sort: uint = 0x70;
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 96f64c2a088..e91c4f93864 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -163,8 +163,8 @@ fn visit_item(e: env, i: @ast::item) {
                 None => /*bad*/copy *e.intr.get(i.ident)
             };
             if attr::find_attrs_by_name(i.attrs, ~"nolink").is_empty() {
-                already_added = !cstore::add_used_library(cstore,
-                                                          foreign_name);
+                already_added =
+                    !cstore::add_used_library(cstore, copy foreign_name);
             }
             if !link_args.is_empty() && already_added {
                 e.diag.span_fatal(i.span, ~"library '" + foreign_name +
@@ -281,7 +281,8 @@ fn resolve_crate_deps(e: env, cdata: @~[u8]) -> cstore::cnum_map {
         let cmetas = metas_with(/*bad*/copy dep.vers, ~"vers", ~[]);
         debug!("resolving dep crate %s ver: %s hash: %s",
                *e.intr.get(dep.name), dep.vers, dep.hash);
-        match existing_match(e, metas_with_ident(*e.intr.get(cname), cmetas),
+        match existing_match(e, metas_with_ident(copy *e.intr.get(cname),
+                                                 copy cmetas),
                              dep.hash) {
           Some(local_cnum) => {
             debug!("already have it");
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ebedc341319..49d7bfeb2f9 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -648,14 +648,22 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: writer::Encoder,
         /* Encode the dtor */
         do struct_def.dtor.iter |dtor| {
             index.push({val: dtor.node.id, pos: ebml_w.writer.tell()});
-          encode_info_for_ctor(ecx, ebml_w, dtor.node.id,
+          encode_info_for_ctor(ecx,
+                               ebml_w,
+                               dtor.node.id,
                                ecx.tcx.sess.ident_of(
                                    ecx.tcx.sess.str_of(item.ident) +
                                    ~"_dtor"),
-                               path, if tps.len() > 0u {
-                                   Some(ii_dtor(*dtor, item.ident, tps,
+                               path,
+                               if tps.len() > 0u {
+                                   Some(ii_dtor(copy *dtor,
+                                                item.ident,
+                                                copy tps,
                                                 local_def(item.id))) }
-                               else { None }, tps);
+                               else {
+                                   None
+                               },
+                               tps);
         }
 
         /* Index the class*/
@@ -869,27 +877,35 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: writer::Encoder,
                         syntax::parse::token::special_idents::invalid);
     visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
         visit_expr: |_e, _cx, _v| { },
-        visit_item: |i, cx, v, copy ebml_w| {
-            visit::visit_item(i, cx, v);
-            match ecx.tcx.items.get(i.id) {
-              ast_map::node_item(_, pt) => {
-                encode_info_for_item(ecx, ebml_w, i, index, *pt);
-              }
-              _ => fail ~"bad item"
+        visit_item: {
+            let ebml_w = copy ebml_w;
+            |i, cx, v| {
+                visit::visit_item(i, cx, v);
+                match ecx.tcx.items.get(i.id) {
+                    ast_map::node_item(_, pt) => {
+                        encode_info_for_item(ecx, ebml_w, i,
+                                             index, *pt);
+                    }
+                    _ => fail ~"bad item"
+                }
             }
         },
-        visit_foreign_item: |ni, cx, v, copy ebml_w| {
-            visit::visit_foreign_item(ni, cx, v);
-            match ecx.tcx.items.get(ni.id) {
-              ast_map::node_foreign_item(_, abi, pt) => {
-                encode_info_for_foreign_item(ecx, ebml_w, ni,
-                                             index, /*bad*/copy *pt, abi);
-              }
-              // case for separate item and foreign-item tables
-              _ => fail ~"bad foreign item"
+        visit_foreign_item: {
+            let ebml_w = copy ebml_w;
+            |ni, cx, v| {
+                visit::visit_foreign_item(ni, cx, v);
+                match ecx.tcx.items.get(ni.id) {
+                    ast_map::node_foreign_item(_, abi, pt) => {
+                        encode_info_for_foreign_item(ecx, ebml_w, ni,
+                                                     index, /*bad*/copy *pt,
+                                                     abi);
+                    }
+                    // case for separate item and foreign-item tables
+                    _ => fail ~"bad foreign item"
+                }
             }
-        }
-        ,.. *visit::default_visitor()
+        },
+        ..*visit::default_visitor()
     }));
     ebml_w.end_tag();
     return /*bad*/copy *index;
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 3979eeee87e..d523b198b31 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -165,7 +165,8 @@ pub fn note_linkage_attrs(intr: @ident_interner, diag: span_handler,
     }
 }
 
-fn crate_matches(crate_data: @~[u8], +metas: ~[@ast::meta_item],
+fn crate_matches(crate_data: @~[u8],
+                 metas: &[@ast::meta_item],
                  hash: ~str) -> bool {
     let attrs = decoder::get_crate_attributes(crate_data);
     let linkage_metas = attr::find_linkage_metas(attrs);
@@ -177,7 +178,7 @@ fn crate_matches(crate_data: @~[u8], +metas: ~[@ast::meta_item],
 }
 
 pub fn metadata_matches(extern_metas: ~[@ast::meta_item],
-                        local_metas: ~[@ast::meta_item]) -> bool {
+                        local_metas: &[@ast::meta_item]) -> bool {
 
     debug!("matching %u metadata requirements against %u items",
            vec::len(local_metas), vec::len(extern_metas));
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index c50666d039f..4c2937b952e 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -275,6 +275,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
       }
       'p' => {
         let did = parse_def(st, TypeParameter, conv);
+        debug!("parsed ty_param: did=%?", did);
         return ty::mk_param(st.tcx, parse_int(st) as uint, did);
       }
       's' => {
@@ -422,7 +423,6 @@ fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg {
 
 fn parse_mode(st: @pstate) -> ast::mode {
     let m = ast::expl(match next(st) {
-        '-' => ast::by_move,
         '+' => ast::by_copy,
         '=' => ast::by_ref,
         '#' => ast::by_val,
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index f06bbb5a0a8..97f8c8f12a1 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -342,7 +342,6 @@ pub fn enc_arg(w: io::Writer, cx: @ctxt, arg: ty::arg) {
 
 pub fn enc_mode(w: io::Writer, cx: @ctxt, m: mode) {
     match ty::resolved_mode(cx.tcx, m) {
-      by_move => w.write_char('-'),
       by_copy => w.write_char('+'),
       by_ref => w.write_char('='),
       by_val => w.write_char('#')
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index ff7e5363d7c..95a9f602a6d 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -22,7 +22,7 @@ use metadata::tyencode;
 use middle::freevars::freevar_entry;
 use middle::typeck::{method_origin, method_map_entry, vtable_res};
 use middle::typeck::{vtable_origin};
-use middle::{ty, typeck};
+use middle::{ty, typeck, moves};
 use middle;
 use util::ppaux::ty_to_str;
 
@@ -51,19 +51,21 @@ use syntax;
 use writer = std::ebml::writer;
 
 // Auxiliary maps of things to be encoded
-pub type maps = {
+pub struct Maps {
     mutbl_map: middle::borrowck::mutbl_map,
     root_map: middle::borrowck::root_map,
     last_use_map: middle::liveness::last_use_map,
     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,
+}
 
 type decode_ctxt = @{
     cdata: cstore::crate_metadata,
     tcx: ty::ctxt,
-    maps: maps
+    maps: Maps
 };
 
 type extended_decode_ctxt_ = {
@@ -91,7 +93,7 @@ pub fn encode_inlined_item(ecx: @e::encode_ctxt,
                            ebml_w: writer::Encoder,
                            path: &[ast_map::path_elt],
                            ii: ast::inlined_item,
-                           maps: maps) {
+                           maps: Maps) {
     debug!("> Encoding inlined item: %s::%s (%u)",
            ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner),
            ecx.tcx.sess.str_of(ii.ident()),
@@ -112,7 +114,7 @@ pub fn encode_inlined_item(ecx: @e::encode_ctxt,
 
 pub fn decode_inlined_item(cdata: cstore::crate_metadata,
                            tcx: ty::ctxt,
-                           maps: maps,
+                           maps: Maps,
                            +path: ast_map::path,
                            par_doc: ebml::Doc)
                         -> Option<ast::inlined_item> {
@@ -514,6 +516,30 @@ impl freevar_entry: tr {
 }
 
 // ______________________________________________________________________
+// Encoding and decoding of CaptureVar information
+
+trait capture_var_helper {
+    fn read_capture_var(xcx: extended_decode_ctxt) -> moves::CaptureVar;
+}
+
+impl reader::Decoder : capture_var_helper {
+    fn read_capture_var(xcx: extended_decode_ctxt) -> moves::CaptureVar {
+        let cvar: moves::CaptureVar = Decodable::decode(&self);
+        cvar.tr(xcx)
+    }
+}
+
+impl moves::CaptureVar : tr {
+    fn tr(xcx: extended_decode_ctxt) -> moves::CaptureVar {
+        moves::CaptureVar {
+            def: self.def.tr(xcx),
+            span: self.span.tr(xcx),
+            mode: self.mode
+        }
+    }
+}
+
+// ______________________________________________________________________
 // Encoding and decoding of method_map_entry
 
 trait read_method_map_entry_helper {
@@ -788,10 +814,11 @@ impl writer::Encoder: write_tag_and_id {
 }
 
 fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
-                             maps: maps,
+                             maps: Maps,
                              ebml_w: writer::Encoder,
                              ii: ast::inlined_item) {
     do ebml_w.wr_tag(c::tag_table as uint) {
+        let ebml_w = copy ebml_w;
         ast_util::visit_ids_for_inlined_item(
             ii,
             fn@(id: ast::node_id, copy ebml_w) {
@@ -804,7 +831,7 @@ fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
 }
 
 fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
-                             maps: maps,
+                             maps: Maps,
                              ebml_w: writer::Encoder,
                              id: ast::node_id) {
     let tcx = ecx.tcx;
@@ -931,11 +958,19 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
         }
     }
 
-    do option::iter(&tcx.value_modes.find(id)) |vm| {
-        do ebml_w.tag(c::tag_table_value_mode) {
+    for maps.moves_map.find(id).each |_| {
+        do ebml_w.tag(c::tag_table_moves_map) {
+            ebml_w.id(id);
+        }
+    }
+
+    for maps.capture_map.find(id).each |cap_vars| {
+        do ebml_w.tag(c::tag_table_capture_map) {
             ebml_w.id(id);
             do ebml_w.tag(c::tag_table_val) {
-                (*vm).encode(&ebml_w)
+                do ebml_w.emit_from_vec(*cap_vars) |cap_var| {
+                    cap_var.encode(&ebml_w);
+                }
             }
         }
     }
@@ -980,10 +1015,24 @@ impl reader::Decoder: ebml_decoder_decoder_helpers {
         // context.  However, we do not bother, because region types
         // are not used during trans.
 
-        do self.read_opaque |doc| {
-            tydecode::parse_ty_data(
+        return do self.read_opaque |doc| {
+
+            let ty = tydecode::parse_ty_data(
                 doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx,
-                |s, a| self.convert_def_id(xcx, s, a))
+                |s, a| self.convert_def_id(xcx, s, a));
+
+            debug!("read_ty(%s) = %s",
+                   type_string(doc), ty_to_str(xcx.dcx.tcx, ty));
+
+            ty
+        };
+
+        fn type_string(doc: ebml::Doc) -> ~str {
+            let mut str = ~"";
+            for uint::range(doc.start, doc.end) |i| {
+                str::push_char(&mut str, doc.data[i] as char);
+            }
+            str
         }
     }
 
@@ -1034,10 +1083,12 @@ impl reader::Decoder: ebml_decoder_decoder_helpers {
          * to refer to the new, cloned copy of the type parameter.
          */
 
-        match source {
+        let r = match source {
             NominalType | TypeWithId => xcx.tr_def_id(did),
             TypeParameter => xcx.tr_intern_def_id(did)
-        }
+        };
+        debug!("convert_def_id(source=%?, did=%?)=%?", source, did, r);
+        return r;
     }
 }
 
@@ -1057,6 +1108,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
             dcx.maps.mutbl_map.insert(id, ());
         } else if tag == (c::tag_table_legacy_boxed_trait as uint) {
             dcx.tcx.legacy_boxed_traits.insert(id, ());
+        } else if tag == (c::tag_table_moves_map as uint) {
+            dcx.maps.moves_map.insert(id, ());
         } else {
             let val_doc = entry_doc[c::tag_table_val as uint];
             let val_dsr = &reader::Decoder(val_doc);
@@ -1065,6 +1118,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
                 dcx.tcx.def_map.insert(id, def);
             } else if tag == (c::tag_table_node_type as uint) {
                 let ty = val_dsr.read_ty(xcx);
+                debug!("inserting ty for node %?: %s",
+                       id, ty_to_str(dcx.tcx, ty));
                 (*dcx.tcx.node_types).insert(id as uint, ty);
             } else if tag == (c::tag_table_node_type_subst as uint) {
                 let tys = val_dsr.read_tys(xcx);
@@ -1098,9 +1153,12 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
                 let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
                 adj.tr(xcx);
                 dcx.tcx.adjustments.insert(id, adj);
-            } else if tag == (c::tag_table_value_mode as uint) {
-                let vm: ty::ValueMode = Decodable::decode(val_dsr);
-                dcx.tcx.value_modes.insert(id, vm);
+            } else if tag == (c::tag_table_capture_map as uint) {
+                let cvars =
+                    at_vec::from_owned(
+                        val_dsr.read_to_vec(
+                            || val_dsr.read_capture_var(xcx)));
+                dcx.maps.capture_map.insert(id, cvars);
             } else {
                 xcx.dcx.tcx.sess.bug(
                     fmt!("unknown tag found in side tables: %x", tag));
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index b1c306fbd91..76b3aea2dd1 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -19,13 +19,15 @@
 
 use core::prelude::*;
 
-use middle::borrowck::{Loan, bckerr, borrowck_ctxt, inherent_mutability};
+use middle::moves;
+use middle::borrowck::{Loan, bckerr, BorrowckCtxt, inherent_mutability};
 use middle::borrowck::{req_maps, root_map_key, save_and_restore};
+use middle::borrowck::{MoveError, MoveOk, MoveFromIllegalCmt};
+use middle::borrowck::{MoveWhileBorrowed};
 use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
 use middle::mem_categorization::{cat_local, cat_rvalue, cat_self};
 use middle::mem_categorization::{cat_special, cmt, gc_ptr, loan_path, lp_arg};
 use middle::mem_categorization::{lp_comp, lp_deref, lp_local};
-use middle::ty::{CopyValue, MoveValue, ReadValue};
 use middle::ty;
 use util::ppaux::ty_to_str;
 
@@ -42,7 +44,7 @@ use syntax::print::pprust;
 use syntax::visit;
 
 enum check_loan_ctxt = @{
-    bccx: borrowck_ctxt,
+    bccx: @BorrowckCtxt,
     req_maps: req_maps,
 
     reported: HashMap<ast::node_id, ()>,
@@ -63,9 +65,9 @@ enum purity_cause {
     pc_cmt(bckerr)
 }
 
-pub fn check_loans(bccx: borrowck_ctxt,
-                   req_maps: req_maps,
-                   crate: @ast::crate) {
+pub fn check_loans(bccx: @BorrowckCtxt,
+               req_maps: req_maps,
+               crate: @ast::crate) {
     let clcx = check_loan_ctxt(@{bccx: bccx,
                                  req_maps: req_maps,
                                  reported: HashMap(),
@@ -471,12 +473,40 @@ impl check_loan_ctxt {
         }
     }
 
-    fn check_move_out(ex: @ast::expr) {
-        let cmt = self.bccx.cat_expr(ex);
-        self.check_move_out_from_cmt(cmt);
+    fn check_move_out_from_expr(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. */
+            }
+            _ => {
+                let cmt = self.bccx.cat_expr(ex);
+                match self.analyze_move_out_from_cmt(cmt) {
+                    MoveOk => {}
+                    MoveFromIllegalCmt(_) => {
+                        self.bccx.span_err(
+                            cmt.span,
+                            fmt!("moving out of %s",
+                                 self.bccx.cmt_to_str(cmt)));
+                    }
+                    MoveWhileBorrowed(_, loan_cmt) => {
+                        self.bccx.span_err(
+                            cmt.span,
+                            fmt!("moving out of %s prohibited \
+                                  due to outstanding loan",
+                                 self.bccx.cmt_to_str(cmt)));
+                        self.bccx.span_note(
+                            loan_cmt.span,
+                            fmt!("loan of %s granted here",
+                                 self.bccx.cmt_to_str(loan_cmt)));
+                    }
+                }
+            }
+        }
     }
 
-    fn check_move_out_from_cmt(cmt: cmt) {
+    fn analyze_move_out_from_cmt(cmt: cmt) -> MoveError {
         debug!("check_move_out_from_cmt(cmt=%s)",
                self.bccx.cmt_to_repr(cmt));
 
@@ -493,59 +523,27 @@ impl check_loan_ctxt {
 
           // Nothing else.
           _ => {
-            self.bccx.span_err(
-                cmt.span,
-                fmt!("moving out of %s", self.bccx.cmt_to_str(cmt)));
-            return;
+              return MoveFromIllegalCmt(cmt);
           }
         }
 
         self.bccx.add_to_mutbl_map(cmt);
 
         // check for a conflicting loan:
-        let lp = match cmt.lp {
-          None => return,
-          Some(lp) => lp
-        };
-        for self.walk_loans_of(cmt.id, lp) |loan| {
-            self.bccx.span_err(
-                cmt.span,
-                fmt!("moving out of %s prohibited due to outstanding loan",
-                     self.bccx.cmt_to_str(cmt)));
-            self.bccx.span_note(
-                loan.cmt.span,
-                fmt!("loan of %s granted here",
-                     self.bccx.cmt_to_str(loan.cmt)));
-            return;
-        }
-    }
-
-    // Very subtle (#2633): liveness can mark options as last_use even
-    // when there is an outstanding loan.  In that case, it is not
-    // safe to consider the use a last_use.
-    fn check_last_use(expr: @ast::expr) {
-        debug!("Checking last use of expr %?", expr.id);
-        let cmt = self.bccx.cat_expr(expr);
-        let lp = match cmt.lp {
-            None => {
-                debug!("Not a loanable expression");
-                return;
+        for cmt.lp.each |lp| {
+            for self.walk_loans_of(cmt.id, *lp) |loan| {
+                return MoveWhileBorrowed(cmt, loan.cmt);
             }
-            Some(lp) => lp
-        };
-        for self.walk_loans_of(cmt.id, lp) |_loan| {
-            debug!("Removing last use entry %? due to outstanding loan",
-                   expr.id);
-            self.bccx.last_use_map.remove(expr.id);
-            return;
         }
+
+        return MoveOk;
     }
 
     fn check_call(expr: @ast::expr,
                   callee: Option<@ast::expr>,
                   callee_id: ast::node_id,
                   callee_span: span,
-                  args: ~[@ast::expr]) {
+                  args: &[@ast::expr]) {
         match self.purity(expr.id) {
           None => {}
           Some(ref pc) => {
@@ -557,35 +555,26 @@ impl check_loan_ctxt {
             }
           }
         }
-        let arg_tys =
-            ty::ty_fn_args(
-                ty::node_id_to_type(self.tcx(), callee_id));
-        for vec::each2(args, arg_tys) |arg, arg_ty| {
-            match ty::resolved_mode(self.tcx(), arg_ty.mode) {
-                ast::by_move => {
-                    self.check_move_out(*arg);
-                }
-                ast::by_ref |
-                ast::by_copy | ast::by_val => {
-                }
-            }
-        }
     }
 }
 
 fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
                      sp: span, id: ast::node_id, &&self: check_loan_ctxt,
-                     visitor: visit::vt<check_loan_ctxt>) {
+                     visitor: visit::vt<check_loan_ctxt>)
+{
+    let is_stack_closure = self.is_stack_closure(id);
+    let fty = ty::node_id_to_type(self.tcx(), id);
+    let fty_proto = ty::ty_fn_proto(fty);
+
+    check_moves_from_captured_variables(self, id, fty_proto);
 
     debug!("purity on entry=%?", copy self.declared_purity);
     do save_and_restore(&mut(self.declared_purity)) {
         do save_and_restore(&mut(self.fn_args)) {
-            let is_stack_closure = self.is_stack_closure(id);
-            let fty = ty::node_id_to_type(self.tcx(), id);
             self.declared_purity = ty::determine_inherited_purity(
                 copy self.declared_purity,
                 ty::ty_fn_purity(fty),
-                ty::ty_fn_proto(fty));
+                fty_proto);
 
             match fk {
                 visit::fk_anon(*) |
@@ -616,6 +605,50 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
         }
     }
     debug!("purity on exit=%?", copy self.declared_purity);
+
+    fn check_moves_from_captured_variables(&&self: check_loan_ctxt,
+                                           id: ast::node_id,
+                                           fty_proto: ast::Proto)
+    {
+        match fty_proto {
+            ast::ProtoBox | ast::ProtoUniq => {
+                let cap_vars = self.bccx.capture_map.get(id);
+                for cap_vars.each |cap_var| {
+                    match cap_var.mode {
+                        moves::CapRef | moves::CapCopy => { loop; }
+                        moves::CapMove => { }
+                    }
+                    let def_id = ast_util::def_id_of_def(cap_var.def).node;
+                    let ty = ty::node_id_to_type(self.tcx(), def_id);
+                    let cmt = self.bccx.cat_def(id, cap_var.span,
+                                                ty, cap_var.def);
+                    let move_err = self.analyze_move_out_from_cmt(cmt);
+                    match move_err {
+                        MoveOk => {}
+                        MoveFromIllegalCmt(move_cmt) => {
+                            self.bccx.span_err(
+                                cap_var.span,
+                                fmt!("illegal by-move capture of %s",
+                                     self.bccx.cmt_to_str(move_cmt)));
+                        }
+                        MoveWhileBorrowed(move_cmt, loan_cmt) => {
+                            self.bccx.span_err(
+                                cap_var.span,
+                                fmt!("by-move capture of %s prohibited \
+                                      due to outstanding loan",
+                                     self.bccx.cmt_to_str(move_cmt)));
+                            self.bccx.span_note(
+                                loan_cmt.span,
+                                fmt!("loan of %s granted here",
+                                     self.bccx.cmt_to_str(loan_cmt)));
+                        }
+                    }
+                }
+            }
+
+            ast::ProtoBorrowed | ast::ProtoBare => {}
+        }
+    }
 }
 
 fn check_loans_in_local(local: @ast::local,
@@ -632,48 +665,24 @@ fn check_loans_in_expr(expr: @ast::expr,
 
     self.check_for_conflicting_loans(expr.id);
 
-    // If this is a move, check it.
-    match self.tcx().value_modes.find(expr.id) {
-        Some(MoveValue) => self.check_move_out(expr),
-        Some(ReadValue) | Some(CopyValue) | None => {}
+    if self.bccx.moves_map.contains_key(expr.id) {
+        self.check_move_out_from_expr(expr);
     }
 
-    match /*bad*/copy expr.node {
-      ast::expr_path(*) if self.bccx.last_use_map.contains_key(expr.id) => {
-        self.check_last_use(expr);
-      }
-
+    match expr.node {
       ast::expr_swap(l, r) => {
         self.check_assignment(at_swap, l);
         self.check_assignment(at_swap, r);
       }
-      ast::expr_unary_move(src) => {
-        self.check_move_out(src);
-      }
       ast::expr_assign(dest, _) |
       ast::expr_assign_op(_, dest, _) => {
         self.check_assignment(at_straight_up, dest);
       }
-      ast::expr_fn(_, _, _, cap_clause) |
-      ast::expr_fn_block(_, _, cap_clause) => {
-        for (*cap_clause).each |cap_item| {
-            if cap_item.is_move {
-                let def = self.tcx().def_map.get(cap_item.id);
-
-                // Hack: the type that is used in the cmt doesn't actually
-                // matter here, so just subst nil instead of looking up
-                // the type of the def that is referred to
-                let cmt = self.bccx.cat_def(cap_item.id, cap_item.span,
-                                            ty::mk_nil(self.tcx()), def);
-                self.check_move_out_from_cmt(cmt);
-            }
-        }
+      ast::expr_call(f, ref args, _) => {
+        self.check_call(expr, Some(f), f.id, f.span, *args);
       }
-      ast::expr_call(f, args, _) => {
-        self.check_call(expr, Some(f), f.id, f.span, args);
-      }
-      ast::expr_method_call(_, _, _, args, _) => {
-        self.check_call(expr, None, expr.callee_id, expr.span, args);
+      ast::expr_method_call(_, _, _, ref args, _) => {
+        self.check_call(expr, None, expr.callee_id, expr.span, *args);
       }
       ast::expr_index(_, rval) |
       ast::expr_binary(_, _, rval)
@@ -692,6 +701,18 @@ fn check_loans_in_expr(expr: @ast::expr,
                         expr.span,
                         ~[]);
       }
+      ast::expr_match(*) => {
+          // 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.
+      }
       _ => { }
     }
 
diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs
index a0119a19b9a..bfcdacf811d 100644
--- a/src/librustc/middle/borrowck/gather_loans.rs
+++ b/src/librustc/middle/borrowck/gather_loans.rs
@@ -18,8 +18,8 @@
 
 use core::prelude::*;
 
-use middle::borrowck::preserve::{preserve_condition, pc_ok, pc_if_pure};
-use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, err_mutbl};
+use middle::borrowck::preserve::{PreserveCondition, PcOk, PcIfPure};
+use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl};
 use middle::borrowck::{req_maps};
 use middle::mem_categorization::{cat_binding, cat_discr, cmt, comp_variant};
 use middle::mem_categorization::{mem_categorization_ctxt};
@@ -68,13 +68,13 @@ use syntax::visit;
 /// No good.  Instead what will happen is that `root_ub` will be set to the
 /// body of the while loop and we will refuse to root the pointer `&*x`
 /// because it would have to be rooted for a region greater than `root_ub`.
-enum gather_loan_ctxt = @{bccx: borrowck_ctxt,
+enum gather_loan_ctxt = @{bccx: @BorrowckCtxt,
                           req_maps: req_maps,
                           mut item_ub: ast::node_id,
                           mut root_ub: ast::node_id,
                           mut ignore_adjustments: LinearSet<ast::node_id>};
 
-pub fn gather_loans(bccx: borrowck_ctxt, crate: @ast::crate) -> req_maps {
+pub fn gather_loans(bccx: @BorrowckCtxt, crate: @ast::crate) -> req_maps {
     let glcx = gather_loan_ctxt(@{bccx: bccx,
                                   req_maps: {req_loan_map: HashMap(),
                                              pure_map: HashMap()},
@@ -148,11 +148,11 @@ fn req_loans_in_expr(ex: @ast::expr,
         let scope_r = ty::re_scope(ex.id);
         for vec::each2(args, arg_tys) |arg, arg_ty| {
             match ty::resolved_mode(self.tcx(), arg_ty.mode) {
-              ast::by_ref => {
-                let arg_cmt = self.bccx.cat_expr(*arg);
-                self.guarantee_valid(arg_cmt, m_imm,  scope_r);
-              }
-               ast::by_val | ast::by_move | ast::by_copy => {}
+                ast::by_ref => {
+                    let arg_cmt = self.bccx.cat_expr(*arg);
+                    self.guarantee_valid(arg_cmt, m_imm,  scope_r);
+                }
+                ast::by_val | ast::by_copy => {}
             }
         }
         visit::visit_expr(ex, self, vt);
@@ -164,11 +164,11 @@ fn req_loans_in_expr(ex: @ast::expr,
         let scope_r = ty::re_scope(ex.id);
         for vec::each2(args, arg_tys) |arg, arg_ty| {
             match ty::resolved_mode(self.tcx(), arg_ty.mode) {
-              ast::by_ref => {
-                let arg_cmt = self.bccx.cat_expr(*arg);
-                self.guarantee_valid(arg_cmt, m_imm,  scope_r);
-              }
-               ast::by_val | ast::by_move | ast::by_copy => {}
+                ast::by_ref => {
+                    let arg_cmt = self.bccx.cat_expr(*arg);
+                    self.guarantee_valid(arg_cmt, m_imm,  scope_r);
+                }
+                ast::by_val | ast::by_copy => {}
             }
         }
 
@@ -374,7 +374,7 @@ impl gather_loan_ctxt {
           // matches with the actual mutability (but if an immutable
           // pointer is desired, that is ok as long as we are pure)
           None => {
-            let result: bckres<preserve_condition> = {
+            let result: bckres<PreserveCondition> = {
                 do self.check_mutbl(req_mutbl, cmt).chain |pc1| {
                     do self.bccx.preserve(cmt, scope_r,
                                           self.item_ub,
@@ -385,16 +385,16 @@ impl gather_loan_ctxt {
             };
 
             match result {
-                Ok(pc_ok) => {
-                    debug!("result of preserve: pc_ok");
+                Ok(PcOk) => {
+                    debug!("result of preserve: PcOk");
 
                     // we were able guarantee the validity of the ptr,
                     // perhaps by rooting or because it is immutably
                     // rooted.  good.
                     self.bccx.stable_paths += 1;
                 }
-                Ok(pc_if_pure(ref e)) => {
-                    debug!("result of preserve: %?", pc_if_pure((*e)));
+                Ok(PcIfPure(ref e)) => {
+                    debug!("result of preserve: %?", PcIfPure((*e)));
 
                     // we are only able to guarantee the validity if
                     // the scope is pure
@@ -443,25 +443,25 @@ impl gather_loan_ctxt {
     // mutable memory.
     fn check_mutbl(&self,
                    req_mutbl: ast::mutability,
-                   cmt: cmt) -> bckres<preserve_condition> {
+                   cmt: cmt) -> bckres<PreserveCondition> {
         debug!("check_mutbl(req_mutbl=%?, cmt.mutbl=%?)",
                req_mutbl, cmt.mutbl);
 
         if req_mutbl == m_const || req_mutbl == cmt.mutbl {
             debug!("required is const or they are the same");
-            Ok(pc_ok)
+            Ok(PcOk)
         } else {
             let e = bckerr { cmt: cmt, code: err_mutbl(req_mutbl) };
             if req_mutbl == m_imm {
                 // if this is an @mut box, then it's generally OK to borrow as
                 // &imm; this will result in a write guard
                 if cmt.cat.is_mutable_box() {
-                    Ok(pc_ok)
+                    Ok(PcOk)
                 } else {
                     // you can treat mutable things as imm if you are pure
                     debug!("imm required, must be pure");
 
-                    Ok(pc_if_pure(e))
+                    Ok(PcIfPure(e))
                 }
             } else {
                 Err(e)
@@ -556,11 +556,6 @@ impl gather_loan_ctxt {
             match pat.node {
               ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => {
                 match bm {
-                  ast::bind_by_value | ast::bind_by_move => {
-                    // copying does not borrow anything, so no check
-                    // is required
-                    // as for move, check::_match ensures it's from an rvalue.
-                  }
                   ast::bind_by_ref(mutbl) => {
                     // ref x or ref x @ p --- creates a ptr which must
                     // remain valid for the scope of the match
@@ -582,9 +577,9 @@ impl gather_loan_ctxt {
                         self.guarantee_valid(cmt, mutbl, scope_r);
                     }
                   }
-                  ast::bind_infer => {
-                    // Nothing to do here; this is either a copy or a move;
-                    // thus either way there is nothing to check. Yay!
+                  ast::bind_by_copy | ast::bind_infer => {
+                    // Nothing to do here; neither copies nor moves induce
+                    // borrows.
                   }
                 }
               }
diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs
index be12ae9dff4..c4b36085ec8 100644
--- a/src/librustc/middle/borrowck/loan.rs
+++ b/src/librustc/middle/borrowck/loan.rs
@@ -43,7 +43,7 @@ XXX --- much more needed, don't have time to write this all up now
 
 use core::prelude::*;
 
-use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, err_mutbl};
+use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl};
 use middle::borrowck::{err_out_of_scope};
 use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
 use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self};
@@ -57,8 +57,9 @@ use core::result::{Err, Ok, Result};
 use syntax::ast::{m_const, m_imm, m_mutbl};
 use syntax::ast;
 
-impl borrowck_ctxt {
-    fn loan(cmt: cmt,
+impl BorrowckCtxt {
+    fn loan(&self,
+            cmt: cmt,
             scope_region: ty::Region,
             mutbl: ast::mutability) -> bckres<~[Loan]> {
         let lc = LoanContext {
@@ -77,7 +78,7 @@ impl borrowck_ctxt {
 }
 
 struct LoanContext {
-    bccx: borrowck_ctxt,
+    bccx: &BorrowckCtxt,
 
     // the region scope for which we must preserve the memory
     scope_region: ty::Region,
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 9f9d5f20b69..c0c59c68699 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -230,6 +230,7 @@ use middle::liveness;
 use middle::mem_categorization::*;
 use middle::region;
 use middle::ty;
+use middle::moves;
 use util::common::{indenter, stmt_set};
 use util::ppaux::{expr_repr, note_and_explain_region};
 use util::ppaux::{ty_to_str, region_to_str, explain_region};
@@ -254,15 +255,17 @@ pub mod gather_loans;
 pub mod loan;
 pub mod preserve;
 
-pub fn check_crate(tcx: ty::ctxt,
-                   method_map: typeck::method_map,
-                   last_use_map: liveness::last_use_map,
-                   crate: @ast::crate)
-                -> (root_map, mutbl_map, write_guard_map) {
-
-    let bccx = borrowck_ctxt_(@{tcx: tcx,
+pub fn check_crate(
+    tcx: ty::ctxt,
+    method_map: typeck::method_map,
+    moves_map: moves::MovesMap,
+    capture_map: moves::CaptureMap,
+    crate: @ast::crate) -> (root_map, mutbl_map, write_guard_map)
+{
+    let bccx = @BorrowckCtxt   {tcx: tcx,
                                 method_map: method_map,
-                                last_use_map: last_use_map,
+                                moves_map: moves_map,
+                                capture_map: capture_map,
                                 root_map: root_map(),
                                 mutbl_map: HashMap(),
                                 write_guard_map: HashMap(),
@@ -271,7 +274,7 @@ pub fn check_crate(tcx: ty::ctxt,
                                 mut loaned_paths_imm: 0,
                                 mut stable_paths: 0,
                                 mut req_pure_paths: 0,
-                                mut guaranteed_paths: 0});
+                                mut guaranteed_paths: 0};
 
     let req_maps = gather_loans::gather_loans(bccx, crate);
     check_loans::check_loans(bccx, req_maps, crate);
@@ -292,7 +295,7 @@ pub fn check_crate(tcx: ty::ctxt,
 
     return (bccx.root_map, bccx.mutbl_map, bccx.write_guard_map);
 
-    fn make_stat(bccx: borrowck_ctxt, stat: uint) -> ~str {
+    fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> ~str {
         let stat_f = stat as float;
         let total = bccx.guaranteed_paths as float;
         fmt!("%u (%.0f%%)", stat  , stat_f * 100f / total)
@@ -302,23 +305,22 @@ pub fn check_crate(tcx: ty::ctxt,
 // ----------------------------------------------------------------------
 // Type definitions
 
-pub type borrowck_ctxt_ = {tcx: ty::ctxt,
-                           method_map: typeck::method_map,
-                           last_use_map: liveness::last_use_map,
-                           root_map: root_map,
-                           mutbl_map: mutbl_map,
-                           write_guard_map: write_guard_map,
-                           stmt_map: stmt_set,
-
-                           // Statistics:
-                           mut loaned_paths_same: uint,
-                           mut loaned_paths_imm: uint,
-                           mut stable_paths: uint,
-                           mut req_pure_paths: uint,
-                           mut guaranteed_paths: uint};
-
-pub enum borrowck_ctxt {
-    borrowck_ctxt_(@borrowck_ctxt_)
+pub struct BorrowckCtxt {
+    tcx: ty::ctxt,
+    method_map: typeck::method_map,
+    moves_map: moves::MovesMap,
+    capture_map: moves::CaptureMap,
+    root_map: root_map,
+    mutbl_map: mutbl_map,
+    write_guard_map: write_guard_map,
+    stmt_map: stmt_set,
+
+    // Statistics:
+    mut loaned_paths_same: uint,
+    mut loaned_paths_imm: uint,
+    mut stable_paths: uint,
+    mut req_pure_paths: uint,
+    mut guaranteed_paths: uint
 }
 
 pub struct RootInfo {
@@ -371,6 +373,12 @@ pub struct bckerr {
     code: bckerr_code
 }
 
+pub enum MoveError {
+    MoveOk,
+    MoveFromIllegalCmt(cmt),
+    MoveWhileBorrowed(/*move*/ cmt, /*loan*/ cmt)
+}
+
 // shorthand for something that fails with `bckerr` or succeeds with `T`
 pub type bckres<T> = Result<T, bckerr>;
 
@@ -411,60 +419,62 @@ pub fn root_map() -> root_map {
 // ___________________________________________________________________________
 // Misc
 
-pub impl borrowck_ctxt {
-    fn is_subregion_of(r_sub: ty::Region, r_sup: ty::Region) -> bool {
+pub impl BorrowckCtxt {
+    fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) -> bool {
         region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
     }
 
-    fn cat_expr(expr: @ast::expr) -> cmt {
+    fn cat_expr(&self, expr: @ast::expr) -> cmt {
         cat_expr(self.tcx, self.method_map, expr)
     }
 
-    fn cat_expr_unadjusted(expr: @ast::expr) -> cmt {
+    fn cat_expr_unadjusted(&self, expr: @ast::expr) -> cmt {
         cat_expr_unadjusted(self.tcx, self.method_map, expr)
     }
 
-    fn cat_expr_autoderefd(expr: @ast::expr,
+    fn cat_expr_autoderefd(&self, expr: @ast::expr,
                            adj: @ty::AutoAdjustment)
                         -> cmt {
         cat_expr_autoderefd(self.tcx, self.method_map, expr, adj)
     }
 
-    fn cat_def(id: ast::node_id,
+    fn cat_def(&self,
+               id: ast::node_id,
                span: span,
                ty: ty::t,
                def: ast::def) -> cmt {
         cat_def(self.tcx, self.method_map, id, span, ty, def)
     }
 
-    fn cat_variant<N: ast_node>(arg: N,
+    fn cat_variant<N: ast_node>(&self,
+                                arg: N,
                                 enum_did: ast::def_id,
                                 cmt: cmt) -> cmt {
         cat_variant(self.tcx, self.method_map, arg, enum_did, cmt)
     }
 
-    fn cat_discr(cmt: cmt, match_id: ast::node_id) -> cmt {
-        return @cmt_ { cat: cat_discr(cmt, match_id),.. *cmt };
+    fn cat_discr(&self, cmt: cmt, match_id: ast::node_id) -> cmt {
+        return @cmt_ {cat:cat_discr(cmt, match_id),.. *cmt};
     }
 
-    fn mc_ctxt() -> mem_categorization_ctxt {
+    fn mc_ctxt(&self) -> mem_categorization_ctxt {
         mem_categorization_ctxt {tcx: self.tcx,
                                  method_map: self.method_map}
     }
 
-    fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
+    fn cat_pattern(&self, cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
         let mc = self.mc_ctxt();
         mc.cat_pattern(cmt, pat, op);
     }
 
-    fn report_if_err(bres: bckres<()>) {
+    fn report_if_err(&self, bres: bckres<()>) {
         match bres {
           Ok(()) => (),
           Err(ref e) => self.report((*e))
         }
     }
 
-    fn report(err: bckerr) {
+    fn report(&self, err: bckerr) {
         self.span_err(
             err.cmt.span,
             fmt!("illegal borrow: %s",
@@ -472,15 +482,15 @@ pub impl borrowck_ctxt {
         self.note_and_explain_bckerr(err);
     }
 
-    fn span_err(s: span, +m: ~str) {
+    fn span_err(&self, s: span, +m: ~str) {
         self.tcx.sess.span_err(s, m);
     }
 
-    fn span_note(s: span, +m: ~str) {
+    fn span_note(&self, s: span, +m: ~str) {
         self.tcx.sess.span_note(s, m);
     }
 
-    fn add_to_mutbl_map(cmt: cmt) {
+    fn add_to_mutbl_map(&self, cmt: cmt) {
         match cmt.cat {
           cat_local(id) | cat_arg(id) => {
             self.mutbl_map.insert(id, ());
@@ -492,7 +502,7 @@ pub impl borrowck_ctxt {
         }
     }
 
-    fn bckerr_to_str(err: bckerr) -> ~str {
+    fn bckerr_to_str(&self, err: bckerr) -> ~str {
         match err.code {
             err_mutbl(req) => {
                 fmt!("creating %s alias to %s",
@@ -520,7 +530,7 @@ pub impl borrowck_ctxt {
         }
     }
 
-    fn note_and_explain_bckerr(err: bckerr) {
+    fn note_and_explain_bckerr(&self, err: bckerr) {
         let code = err.code;
         match code {
             err_mutbl(*) | err_mut_uniq | err_mut_variant |
@@ -555,25 +565,25 @@ pub impl borrowck_ctxt {
     }
 
 
-    fn cmt_to_str(cmt: cmt) -> ~str {
+    fn cmt_to_str(&self, cmt: cmt) -> ~str {
         let mc = &mem_categorization_ctxt {tcx: self.tcx,
                                            method_map: self.method_map};
         mc.cmt_to_str(cmt)
     }
 
-    fn cmt_to_repr(cmt: cmt) -> ~str {
+    fn cmt_to_repr(&self, cmt: cmt) -> ~str {
         let mc = &mem_categorization_ctxt {tcx: self.tcx,
                                            method_map: self.method_map};
         mc.cmt_to_repr(cmt)
     }
 
-    fn mut_to_str(mutbl: ast::mutability) -> ~str {
+    fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
         let mc = &mem_categorization_ctxt {tcx: self.tcx,
                                            method_map: self.method_map};
         mc.mut_to_str(mutbl)
     }
 
-    fn loan_to_repr(loan: &Loan) -> ~str {
+    fn loan_to_repr(&self, loan: &Loan) -> ~str {
         fmt!("Loan(lp=%?, cmt=%s, mutbl=%?)",
              loan.lp, self.cmt_to_repr(loan.cmt), loan.mutbl)
     }
diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs
index 048fd7b623c..570b439cf8c 100644
--- a/src/librustc/middle/borrowck/preserve.rs
+++ b/src/librustc/middle/borrowck/preserve.rs
@@ -15,7 +15,7 @@
 
 use core::prelude::*;
 
-use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, borrowck_ctxt};
+use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, BorrowckCtxt};
 use middle::borrowck::{err_mut_uniq, err_mut_variant};
 use middle::borrowck::{err_out_of_root_scope, err_out_of_scope};
 use middle::borrowck::{err_root_not_permitted, root_map_key};
@@ -30,40 +30,42 @@ use util::common::indenter;
 use syntax::ast::{m_const, m_imm, m_mutbl};
 use syntax::ast;
 
-pub enum preserve_condition {
-    pc_ok,
-    pc_if_pure(bckerr)
+pub enum PreserveCondition {
+    PcOk,
+    PcIfPure(bckerr)
 }
 
-impl preserve_condition {
+impl PreserveCondition {
     // combines two preservation conditions such that if either of
     // them requires purity, the result requires purity
-    fn combine(pc: preserve_condition) -> preserve_condition {
-        match self {
-          pc_ok => {pc}
-          pc_if_pure(_) => {self}
+    fn combine(&self, pc: PreserveCondition) -> PreserveCondition {
+        match *self {
+            PcOk => {pc}
+            PcIfPure(_) => {*self}
         }
     }
 }
 
-impl borrowck_ctxt {
-    fn preserve(cmt: cmt,
+impl BorrowckCtxt {
+    fn preserve(&self,
+                cmt: cmt,
                 scope_region: ty::Region,
                 item_ub: ast::node_id,
-                root_ub: ast::node_id)
-        -> bckres<preserve_condition> {
-
-        let ctxt = preserve_ctxt({bccx: self,
-                                  scope_region: scope_region,
-                                  item_ub: item_ub,
-                                  root_ub: root_ub,
-                                  root_managed_data: true});
-        (&ctxt).preserve(cmt)
+                root_ub: ast::node_id) -> bckres<PreserveCondition>
+    {
+        let ctxt = PreserveCtxt {
+            bccx: self,
+            scope_region: scope_region,
+            item_ub: item_ub,
+            root_ub: root_ub,
+            root_managed_data: true
+        };
+        ctxt.preserve(cmt)
     }
 }
 
-enum preserve_ctxt = {
-    bccx: borrowck_ctxt,
+struct PreserveCtxt {
+    bccx: &BorrowckCtxt,
 
     // the region scope for which we must preserve the memory
     scope_region: ty::Region,
@@ -76,13 +78,12 @@ enum preserve_ctxt = {
 
     // if false, do not attempt to root managed data
     root_managed_data: bool
-};
-
+}
 
-priv impl &preserve_ctxt {
-    fn tcx() -> ty::ctxt { self.bccx.tcx }
+impl PreserveCtxt {
+    fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
 
-    fn preserve(cmt: cmt) -> bckres<preserve_condition> {
+    fn preserve(&self, cmt: cmt) -> bckres<PreserveCondition> {
         debug!("preserve(cmt=%s, root_ub=%?, root_managed_data=%b)",
                self.bccx.cmt_to_repr(cmt), self.root_ub,
                self.root_managed_data);
@@ -94,7 +95,7 @@ priv impl &preserve_ctxt {
             self.compare_scope(cmt, ty::re_scope(self.item_ub))
           }
           cat_special(sk_static_item) | cat_special(sk_method) => {
-            Ok(pc_ok)
+            Ok(PcOk)
           }
           cat_rvalue => {
             // when we borrow an rvalue, we can keep it rooted but only
@@ -181,7 +182,7 @@ priv impl &preserve_ctxt {
           }
           cat_deref(_, _, unsafe_ptr) => {
             // Unsafe pointers are the user's problem
-            Ok(pc_ok)
+            Ok(PcOk)
           }
           cat_deref(base, derefs, gc_ptr(*)) => {
             // GC'd pointers of type @MT: if this pointer lives in
@@ -193,13 +194,15 @@ priv impl &preserve_ctxt {
             if cmt.cat.derefs_through_mutable_box() {
                 self.attempt_root(cmt, base, derefs)
             } else if base.mutbl == m_imm {
-                let non_rooting_ctxt =
-                    preserve_ctxt({root_managed_data: false,.. **self});
-                match (&non_rooting_ctxt).preserve(base) {
-                  Ok(pc_ok) => {
-                    Ok(pc_ok)
+                let non_rooting_ctxt = PreserveCtxt {
+                    root_managed_data: false,
+                    ..*self
+                };
+                match non_rooting_ctxt.preserve(base) {
+                  Ok(PcOk) => {
+                    Ok(PcOk)
                   }
-                  Ok(pc_if_pure(_)) => {
+                  Ok(PcIfPure(_)) => {
                     debug!("must root @T, otherwise purity req'd");
                     self.attempt_root(cmt, base, derefs)
                   }
@@ -267,10 +270,11 @@ priv impl &preserve_ctxt {
             // node appears to draw the line between what will be rooted
             // in the *arm* vs the *match*.
 
-            let match_rooting_ctxt =
-                preserve_ctxt({scope_region: ty::re_scope(match_id),
-                               .. **self});
-            (&match_rooting_ctxt).preserve(base)
+              let match_rooting_ctxt = PreserveCtxt {
+                  scope_region: ty::re_scope(match_id),
+                  ..*self
+              };
+              match_rooting_ctxt.preserve(base)
           }
         }
     }
@@ -279,28 +283,29 @@ priv impl &preserve_ctxt {
     /// `base`) be found in an immutable location (that is, `base`
     /// must be immutable).  Also requires that `base` itself is
     /// preserved.
-    fn require_imm(cmt: cmt,
+    fn require_imm(&self,
+                   cmt: cmt,
                    cmt_base: cmt,
-                   code: bckerr_code) -> bckres<preserve_condition> {
+                   code: bckerr_code) -> bckres<PreserveCondition> {
         // Variant contents and unique pointers: must be immutably
         // rooted to a preserved address.
         match self.preserve(cmt_base) {
           // the base is preserved, but if we are not mutable then
           // purity is required
-          Ok(pc_ok) => {
+          Ok(PcOk) => {
             match cmt_base.mutbl {
               m_mutbl | m_const => {
-                Ok(pc_if_pure(bckerr { cmt: cmt, code: code }))
+                Ok(PcIfPure(bckerr {cmt:cmt, code:code}))
               }
               m_imm => {
-                Ok(pc_ok)
+                Ok(PcOk)
               }
             }
           }
 
           // the base requires purity too, that's fine
-          Ok(pc_if_pure(ref e)) => {
-            Ok(pc_if_pure((*e)))
+          Ok(PcIfPure(ref e)) => {
+            Ok(PcIfPure((*e)))
           }
 
           // base is not stable, doesn't matter
@@ -312,10 +317,11 @@ priv impl &preserve_ctxt {
 
     /// Checks that the scope for which the value must be preserved
     /// is a subscope of `scope_ub`; if so, success.
-    fn compare_scope(cmt: cmt,
-                     scope_ub: ty::Region) -> bckres<preserve_condition> {
+    fn compare_scope(&self,
+                     cmt: cmt,
+                     scope_ub: ty::Region) -> bckres<PreserveCondition> {
         if self.bccx.is_subregion_of(self.scope_region, scope_ub) {
-            Ok(pc_ok)
+            Ok(PcOk)
         } else {
             Err(bckerr {
                 cmt:cmt,
@@ -333,10 +339,8 @@ priv impl &preserve_ctxt {
     /// value live for longer than the current fn or else potentially
     /// require that an statically unbounded number of values be
     /// rooted (if a loop exists).
-    fn attempt_root(cmt: cmt,
-                    base: cmt,
-                    derefs: uint)
-                 -> bckres<preserve_condition> {
+    fn attempt_root(&self, cmt: cmt, base: cmt,
+                    derefs: uint) -> bckres<PreserveCondition> {
         if !self.root_managed_data {
             // normally, there is a root_ub; the only time that this
             // is none is when a boxed value is stored in an immutable
@@ -387,7 +391,7 @@ priv impl &preserve_ctxt {
                     scope: scope_to_use,
                     freezes: cmt.cat.derefs_through_mutable_box()
                 });
-                return Ok(pc_ok);
+                return Ok(PcOk);
             } else {
                 debug!("Unable to root");
                 return Err(bckerr {
diff --git a/src/librustc/middle/capture.rs b/src/librustc/middle/capture.rs
deleted file mode 100644
index 5b77228d1ab..00000000000
--- a/src/librustc/middle/capture.rs
+++ /dev/null
@@ -1,141 +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.
-
-use core::prelude::*;
-
-use middle::freevars;
-use middle::ty;
-
-use core::option;
-use core::vec;
-use std::map::HashMap;
-use std::map;
-use syntax::codemap::span;
-use syntax::{ast, ast_util};
-
-pub enum capture_mode {
-    cap_copy, // Copy the value into the closure.
-    cap_move, // Move the value into the closure.
-    cap_drop, // Drop value after creating closure.
-    cap_ref,  // Reference directly from parent stack frame (block fn).
-}
-
-pub type capture_var = {
-    def: ast::def,                       // Variable being accessed free
-    span: span,                          // Location of access or cap item
-    cap_item: Option<ast::capture_item>, // Capture item, if any
-    mode: capture_mode                   // How variable is being accessed
-};
-
-pub type capture_map = map::HashMap<ast::def_id, capture_var>;
-
-// checks the capture clause for a fn_expr() and issues warnings or
-// errors for any irregularities which we identify.
-pub fn check_capture_clause(tcx: ty::ctxt,
-                            fn_expr_id: ast::node_id,
-                            cap_clause: ast::capture_clause) {
-    let freevars = freevars::get_freevars(tcx, fn_expr_id);
-    let seen_defs = map::HashMap();
-
-    for (*cap_clause).each |cap_item| {
-        let cap_def = tcx.def_map.get(cap_item.id);
-        if !vec::any(*freevars, |fv| fv.def == cap_def ) {
-            tcx.sess.span_warn(
-                cap_item.span,
-                fmt!("captured variable `%s` not used in closure",
-                     tcx.sess.str_of(cap_item.name)));
-        }
-
-        let cap_def_id = ast_util::def_id_of_def(cap_def).node;
-        if !seen_defs.insert(cap_def_id, ()) {
-            tcx.sess.span_err(
-                cap_item.span,
-                fmt!("variable `%s` captured more than once",
-                     tcx.sess.str_of(cap_item.name)));
-        }
-    }
-}
-
-pub fn compute_capture_vars(tcx: ty::ctxt,
-                            fn_expr_id: ast::node_id,
-                            fn_proto: ast::Proto,
-                            cap_clause: ast::capture_clause)
-                         -> ~[capture_var] {
-    let freevars = freevars::get_freevars(tcx, fn_expr_id);
-    let cap_map = map::HashMap();
-
-    // first add entries for anything explicitly named in the cap clause
-
-    for (*cap_clause).each |cap_item| {
-        debug!("Doing capture var: %s (%?)",
-               tcx.sess.str_of(cap_item.name), cap_item.id);
-
-        let cap_def = tcx.def_map.get(cap_item.id);
-        let cap_def_id = ast_util::def_id_of_def(cap_def).node;
-        if cap_item.is_move {
-            // if we are moving the value in, but it's not actually used,
-            // must drop it.
-            if vec::any(*freevars, |fv| fv.def == cap_def ) {
-                cap_map.insert(cap_def_id, {def:cap_def,
-                                            span: cap_item.span,
-                                            cap_item: Some(*cap_item),
-                                            mode:cap_move});
-            } else {
-                cap_map.insert(cap_def_id, {def:cap_def,
-                                            span: cap_item.span,
-                                            cap_item: Some(*cap_item),
-                                            mode:cap_drop});
-            }
-        } else {
-            // if we are copying the value in, but it's not actually used,
-            // just ignore it.
-            if vec::any(*freevars, |fv| fv.def == cap_def ) {
-                cap_map.insert(cap_def_id, {def:cap_def,
-                                            span: cap_item.span,
-                                            cap_item: Some(*cap_item),
-                                            mode:cap_copy});
-            }
-        }
-    }
-
-    // now go through anything that is referenced but was not explicitly
-    // named and add that
-
-    let implicit_mode_is_by_ref = fn_proto == ast::ProtoBorrowed;
-    for vec::each(*freevars) |fvar| {
-        let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;
-        match cap_map.find(fvar_def_id) {
-            option::Some(_) => { /* was explicitly named, do nothing */ }
-            option::None => {
-                // Move if this type implicitly moves; copy otherwise.
-                let mode;
-                if implicit_mode_is_by_ref {
-                    mode = cap_ref;
-                } else {
-                    let fvar_ty = ty::node_id_to_type(tcx, fvar_def_id);
-                    if ty::type_implicitly_moves(tcx, fvar_ty) {
-                        mode = cap_move;
-                    } else {
-                        mode = cap_copy;
-                    }
-                };
-
-                cap_map.insert(fvar_def_id, {def:fvar.def,
-                                             span: fvar.span,
-                                             cap_item: None,
-                                             mode:mode});
-            }
-        }
-    }
-
-    let mut result = ~[];
-    for cap_map.each_value |cap_var| { result.push(cap_var); }
-    return result;
-}
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index de3056639cc..bfe73a9d15c 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -32,13 +32,13 @@ pub fn check_crate(tcx: ty::ctxt, crate: @crate) {
               expr_loop(ref b, _) => {
                 (v.visit_block)((*b), {in_loop: true,.. cx}, v);
               }
-              expr_fn(_, _, _, _) => {
+              expr_fn(_, _, _) => {
                 visit::visit_expr(e, {in_loop: false, can_ret: true}, v);
               }
-              expr_fn_block(_, ref b, _) => {
+              expr_fn_block(_, ref b) => {
                 (v.visit_block)((*b), {in_loop: false, can_ret: false}, v);
               }
-              expr_loop_body(@expr {node: expr_fn_block(_, ref b, _), _}) => {
+              expr_loop_body(@expr {node: expr_fn_block(_, ref b), _}) => {
                 let proto = ty::ty_fn_proto(ty::expr_ty(tcx, e));
                 let blk = (proto == ProtoBorrowed);
                 (v.visit_block)((*b), {in_loop: true, can_ret: blk}, v);
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 4587d3b7b07..406fdbaeac7 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -16,6 +16,7 @@ use middle::pat_util::*;
 use middle::ty::*;
 use middle::ty;
 use middle::typeck::method_map;
+use middle::moves;
 use util::ppaux::ty_to_str;
 
 use core::cmp;
@@ -34,10 +35,16 @@ use syntax::visit;
 pub struct MatchCheckCtxt {
     tcx: ty::ctxt,
     method_map: method_map,
+    moves_map: moves::MovesMap
 }
 
-pub fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: @crate) {
-    let cx = @MatchCheckCtxt { tcx: tcx, method_map: method_map };
+pub fn check_crate(tcx: ty::ctxt,
+                   method_map: method_map,
+                   moves_map: moves::MovesMap,
+                   crate: @crate) {
+    let cx = @MatchCheckCtxt {tcx: tcx,
+                              method_map: method_map,
+                              moves_map: moves_map};
     visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
         visit_expr: |a,b,c| check_expr(cx, a, b, c),
         visit_local: |a,b,c| check_local(cx, a, b, c),
@@ -53,13 +60,7 @@ pub fn expr_is_non_moving_lvalue(cx: @MatchCheckCtxt, expr: @expr) -> bool {
         return false;
     }
 
-    match cx.tcx.value_modes.find(expr.id) {
-        Some(MoveValue) => return false,
-        Some(CopyValue) | Some(ReadValue) => return true,
-        None => {
-            cx.tcx.sess.span_bug(expr.span, ~"no entry in value mode map");
-        }
-    }
+    !cx.moves_map.contains_key(expr.id)
 }
 
 pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
@@ -113,7 +114,7 @@ pub fn check_arms(cx: @MatchCheckCtxt, arms: ~[arm]) {
     for arms.each |arm| {
         for arm.pats.each |pat| {
             let v = ~[*pat];
-            match is_useful(cx, seen, v) {
+            match is_useful(cx, copy seen, v) {
               not_useful => {
                 cx.tcx.sess.span_err(pat.span, ~"unreachable pattern");
               }
@@ -197,7 +198,7 @@ pub enum ctor {
 
 // Note: is_useful doesn't work on empty types, as the paper notes.
 // So it assumes that v is non-empty.
-pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: ~[@pat]) -> useful {
+pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: &[@pat]) -> useful {
     if m.len() == 0u { return useful_; }
     if m[0].len() == 0u { return not_useful; }
     let real_pat = match vec::find(m, |r| r[0].id != 0) {
@@ -272,12 +273,12 @@ pub fn is_useful(cx: @MatchCheckCtxt, +m: matrix, +v: ~[@pat]) -> useful {
 
 pub fn is_useful_specialized(cx: @MatchCheckCtxt,
                              m: matrix,
-                             +v: ~[@pat],
+                             +v: &[@pat],
                              +ctor: ctor,
                              arity: uint,
                              lty: ty::t)
                           -> useful {
-    let ms = vec::filter_map(m, |r| specialize(cx, copy *r,
+    let ms = vec::filter_map(m, |r| specialize(cx, *r,
                                                ctor, arity, lty));
     let could_be_useful = is_useful(
         cx, ms, specialize(cx, v, ctor, arity, lty).get());
@@ -467,7 +468,7 @@ pub fn wild() -> @pat {
 }
 
 pub fn specialize(cx: @MatchCheckCtxt,
-                  +r: ~[@pat],
+                  +r: &[@pat],
                   ctor_id: ctor,
                   arity: uint,
                   left_ty: ty::t)
@@ -729,21 +730,13 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
     for pats.each |pat| {
         do pat_bindings(def_map, *pat) |bm, id, span, _path| {
             match bm {
+                bind_by_copy => {}
                 bind_by_ref(_) => {
                     by_ref_span = Some(span);
                 }
-                bind_by_move => {
-                    any_by_move = true;
-                }
-                bind_by_value => {}
                 bind_infer => {
-                    match cx.tcx.value_modes.find(id) {
-                        Some(MoveValue) => any_by_move = true,
-                        Some(CopyValue) | Some(ReadValue) => {}
-                        None => {
-                            cx.tcx.sess.span_bug(span, ~"no mode for pat \
-                                                         binding");
-                        }
+                    if cx.moves_map.contains_key(id) {
+                        any_by_move = true;
                     }
                 }
             }
@@ -781,18 +774,18 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
         do walk_pat(*pat) |p| {
             if pat_is_binding(def_map, p) {
                 match p.node {
-                    pat_ident(bind_by_move, _, sub) => check_move(p, sub),
-                    pat_ident(bind_infer, _, sub) => {
-                        match tcx.value_modes.find(p.id) {
-                            Some(MoveValue) => check_move(p, sub),
-                            Some(CopyValue) | Some(ReadValue) => {}
-                            None => {
-                                cx.tcx.sess.span_bug(
-                                    pat.span, ~"no mode for pat binding");
-                            }
+                    pat_ident(_, _, sub) => {
+                        if cx.moves_map.contains_key(p.id) {
+                            check_move(p, sub);
                         }
                     }
-                    _ => {}
+                    _ => {
+                        cx.tcx.sess.span_bug(
+                            p.span,
+                            fmt!("Binding pattern %d is \
+                                  not an identifier: %?",
+                                 p.id, p.node));
+                    }
                 }
             }
         }
@@ -800,32 +793,23 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
         // Now check to ensure that any move binding is not behind an @ or &.
         // This is always illegal.
         let vt = visit::mk_vt(@visit::Visitor {
-            visit_pat: |pat, behind_bad_pointer, v| {
-                let error_out = || {
-                    cx.tcx.sess.span_err(pat.span, ~"by-move pattern \
-                                                     bindings may not occur \
-                                                     behind @ or & bindings");
-                };
+            visit_pat: |pat, behind_bad_pointer: bool, v| {
                 match pat.node {
-                    pat_ident(binding_mode, _, sub) => {
+                    pat_ident(_, _, sub) => {
                         debug!("(check legality of move) checking pat \
                                 ident with behind_bad_pointer %?",
                                 behind_bad_pointer);
-                        match binding_mode {
-                            bind_by_move if behind_bad_pointer => error_out(),
-                            bind_infer if behind_bad_pointer => {
-                                match cx.tcx.value_modes.find(pat.id) {
-                                    Some(MoveValue) => error_out(),
-                                    Some(CopyValue) |
-                                    Some(ReadValue) => {}
-                                    None => {
-                                        cx.tcx.sess.span_bug(pat.span,
-                                            ~"no mode for pat binding");
-                                    }
-                                }
-                            }
-                            _ => {}
+
+                        if behind_bad_pointer &&
+                            cx.moves_map.contains_key(pat.id)
+                        {
+                            cx.tcx.sess.span_err(
+                                pat.span,
+                                ~"by-move pattern \
+                                  bindings may not occur \
+                                  behind @ or & bindings");
                         }
+
                         match sub {
                             None => {}
                             Some(subpat) => {
@@ -833,9 +817,11 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
                             }
                         }
                     }
+
                     pat_box(subpat) | pat_region(subpat) => {
                         (v.visit_pat)(subpat, true, v);
                     }
+
                     _ => visit::visit_pat(pat, behind_bad_pointer, v)
                 }
             },
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 022fbe7f306..7edc345adc4 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -413,8 +413,8 @@ pub fn lit_to_const(lit: @lit) -> const_val {
 }
 
 pub fn compare_const_vals(a: const_val, b: const_val) -> int {
-  match (a, b) {
-    (const_int(a), const_int(b)) => {
+  match (&a, &b) {
+    (&const_int(a), &const_int(b)) => {
         if a == b {
             0
         } else if a < b {
@@ -423,7 +423,7 @@ pub fn compare_const_vals(a: const_val, b: const_val) -> int {
             1
         }
     }
-    (const_uint(a), const_uint(b)) => {
+    (&const_uint(a), &const_uint(b)) => {
         if a == b {
             0
         } else if a < b {
@@ -432,7 +432,7 @@ pub fn compare_const_vals(a: const_val, b: const_val) -> int {
             1
         }
     }
-    (const_float(a), const_float(b)) => {
+    (&const_float(a), &const_float(b)) => {
         if a == b {
             0
         } else if a < b {
@@ -441,7 +441,7 @@ pub fn compare_const_vals(a: const_val, b: const_val) -> int {
             1
         }
     }
-    (const_str(ref a), const_str(ref b)) => {
+    (&const_str(ref a), &const_str(ref b)) => {
         if (*a) == (*b) {
             0
         } else if (*a) < (*b) {
@@ -450,7 +450,7 @@ pub fn compare_const_vals(a: const_val, b: const_val) -> int {
             1
         }
     }
-    (const_bool(a), const_bool(b)) => {
+    (&const_bool(a), &const_bool(b)) => {
         if a == b {
             0
         } else if a < b {
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index ba4aae75fbd..68bb1db9af3 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -48,7 +48,7 @@ fn collect_freevars(def_map: resolve::DefMap, blk: ast::blk)
 
     let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
             match expr.node {
-              ast::expr_fn(proto, _, _, _) => {
+              ast::expr_fn(proto, _, _) => {
                 if proto != ast::ProtoBare {
                     visit::visit_expr(expr, depth + 1, v);
                 }
@@ -123,6 +123,7 @@ pub fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info {
       Some(d) => return d
     }
 }
+
 pub fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool {
     return vec::len(*get_freevars(tcx, fid)) != 0u;
 }
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index f3556778984..8977052e029 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -15,7 +15,6 @@ use middle::freevars;
 use middle::lint::{non_implicitly_copyable_typarams, implicit_copies};
 use middle::liveness;
 use middle::pat_util;
-use middle::ty::{CopyValue, MoveValue, ReadValue};
 use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const};
 use middle::ty;
 use middle::typeck;
@@ -102,8 +101,6 @@ pub fn check_crate(tcx: ty::ctxt,
     let visit = visit::mk_vt(@visit::Visitor {
         visit_arm: check_arm,
         visit_expr: check_expr,
-        visit_stmt: check_stmt,
-        visit_block: check_block,
         visit_fn: check_fn,
         visit_ty: check_ty,
         visit_item: fn@(i: @item, cx: ctx, v: visit::vt<ctx>) {
@@ -115,75 +112,41 @@ pub fn check_crate(tcx: ty::ctxt,
     tcx.sess.abort_if_errors();
 }
 
-// bool flag is only used for checking closures,
-// where it refers to whether a var is 'move' in the
-// capture clause
-pub type check_fn = fn@(ctx,
-                        node_id,
-                        Option<@freevar_entry>,
-                        bool,
-                        ty::t,
-                        sp: span);
+type check_fn = fn@(ctx, @freevar_entry);
 
 // Yields the appropriate function to check the kind of closed over
 // variables. `id` is the node_id for some expression that creates the
 // closure.
-pub fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
-    fn check_for_uniq(cx: ctx, id: node_id, fv: Option<@freevar_entry>,
-                      is_move: bool, var_t: ty::t, sp: span) {
+fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
+    fn check_for_uniq(cx: ctx, fv: @freevar_entry) {
         // all captured data must be sendable, regardless of whether it is
         // moved in or copied in.  Note that send implies owned.
-        if !check_send(cx, var_t, sp) { return; }
-
-        // copied in data must be copyable, but moved in data can be anything
-        let is_implicit = fv.is_some();
-        if !is_move {
-            check_copy(cx, id, var_t, sp, is_implicit,
-                       Some(("non-copyable value cannot be copied into a \
-                              ~fn closure",
-                             "to copy values into a ~fn closure, use a \
-                              capture clause: `fn~(copy x)` or `|copy x|`")));
-        }
+        let id = ast_util::def_id_of_def(fv.def).node;
+        let var_t = ty::node_id_to_type(cx.tcx, id);
+        if !check_send(cx, var_t, fv.span) { return; }
+
         // check that only immutable variables are implicitly copied in
-        for fv.each |fv| {
-            check_imm_free_var(cx, fv.def, fv.span);
-        }
+        check_imm_free_var(cx, fv.def, fv.span);
     }
 
-    fn check_for_box(cx: ctx, id: node_id, fv: Option<@freevar_entry>,
-                     is_move: bool, var_t: ty::t, sp: span) {
+    fn check_for_box(cx: ctx, fv: @freevar_entry) {
         // all captured data must be owned
-        if !check_durable(cx.tcx, var_t, sp) { return; }
-
-        // copied in data must be copyable, but moved in data can be anything
-        let is_implicit = fv.is_some();
-        if !is_move {
-            check_copy(cx, id, var_t, sp, is_implicit,
-                       Some(("non-copyable value cannot be copied into a \
-                              @fn closure",
-                             "to copy values into a @fn closure, use a \
-                              capture clause: `fn~(copy x)` or `|copy x|`")));
-        }
+        let id = ast_util::def_id_of_def(fv.def).node;
+        let var_t = ty::node_id_to_type(cx.tcx, id);
+        if !check_durable(cx.tcx, var_t, fv.span) { return; }
+
         // check that only immutable variables are implicitly copied in
-        for fv.each |fv| {
-            check_imm_free_var(cx, fv.def, fv.span);
-        }
+        check_imm_free_var(cx, fv.def, fv.span);
     }
 
-    fn check_for_block(cx: ctx, _id: node_id, fv: Option<@freevar_entry>,
-                       _is_move: bool, _var_t: ty::t, sp: span) {
-        // only restriction: no capture clauses (we would have to take
-        // ownership of the moved/copied in data).
-        if fv.is_none() {
-            cx.tcx.sess.span_err(
-                sp,
-                ~"cannot capture values explicitly with a block closure");
-        }
+    fn check_for_block(_cx: ctx, _fv: @freevar_entry) {
+        // no restrictions
     }
 
-    fn check_for_bare(cx: ctx, _id: node_id, _fv: Option<@freevar_entry>,
-                      _is_move: bool, _var_t: ty::t, sp: span) {
-        cx.tcx.sess.span_err(sp, ~"attempted dynamic environment capture");
+    fn check_for_bare(cx: ctx, fv: @freevar_entry) {
+        cx.tcx.sess.span_err(
+            fv.span,
+            ~"attempted dynamic environment capture");
     }
 
     let fty = ty::node_id_to_type(cx.tcx, id);
@@ -197,68 +160,26 @@ pub fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
 
 // Check that the free variables used in a shared/sendable closure conform
 // to the copy/move kind bounds. Then recursively check the function body.
-pub fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
-                fn_id: node_id, cx: ctx, v: visit::vt<ctx>) {
-    // Find the check function that enforces the appropriate bounds for this
-    // kind of function:
-    do with_appropriate_checker(cx, fn_id) |chk| {
-
-        // Begin by checking the variables in the capture clause, if any.
-        // Here we slightly abuse the map function to both check and report
-        // errors and produce a list of the def id's for all capture
-        // variables.  This list is used below to avoid checking and reporting
-        // on a given variable twice.
-        let cap_clause = match fk {
-            visit::fk_anon(_, cc) | visit::fk_fn_block(cc) => cc,
-            visit::fk_item_fn(*) | visit::fk_method(*) |
-            visit::fk_dtor(*) => @~[]
-        };
-        let captured_vars = do (*cap_clause).map |cap_item| {
-            let cap_def = cx.tcx.def_map.get(cap_item.id);
-            let cap_def_id = ast_util::def_id_of_def(cap_def).node;
-            let ty = ty::node_id_to_type(cx.tcx, cap_def_id);
-            chk(cx, fn_id, None, cap_item.is_move, ty, cap_item.span);
-            cap_def_id
-        };
+fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
+            fn_id: node_id, cx: ctx, v: visit::vt<ctx>) {
 
-        // Iterate over any free variables that may not have appeared in the
-        // capture list.  Ensure that they too are of the appropriate kind.
+    // Check kinds on free variables:
+    do with_appropriate_checker(cx, fn_id) |chk| {
         for vec::each(*freevars::get_freevars(cx.tcx, fn_id)) |fv| {
-            let id = ast_util::def_id_of_def(fv.def).node;
-
-            // skip over free variables that appear in the cap clause
-            if captured_vars.contains(&id) { loop; }
-
-            let ty = ty::node_id_to_type(cx.tcx, id);
-
-            // is_move is true if this type implicitly moves and false
-            // otherwise.
-            let is_move = ty::type_implicitly_moves(cx.tcx, ty);
-
-            chk(cx, fn_id, Some(*fv), is_move, ty, fv.span);
+            chk(cx, *fv);
         }
     }
 
     visit::visit_fn(fk, decl, body, sp, fn_id, cx, v);
 }
 
-pub fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) {
-    match b.node.expr {
-      Some(ex) => maybe_copy(cx, ex,
-         Some(("Tail expressions in blocks must be copyable",
-                                  try_adding))),
-      _ => ()
-    }
-    visit::visit_block(b, cx, v);
-}
-
-pub fn check_arm(a: arm, cx: ctx, v: visit::vt<ctx>) {
+fn check_arm(a: arm, cx: ctx, v: visit::vt<ctx>) {
     for vec::each(a.pats) |p| {
         do pat_util::pat_bindings(cx.tcx.def_map, *p) |mode, id, span, _pth| {
-            if mode == bind_by_value {
+            if mode == bind_by_copy {
                 let t = ty::node_id_to_type(cx.tcx, id);
                 let reason = "consider binding with `ref` or `move` instead";
-                check_copy(cx, id, t, span, false, Some((reason,reason)));
+                check_copy(cx, t, span, reason);
             }
         }
     }
@@ -267,14 +188,14 @@ pub fn check_arm(a: arm, cx: ctx, v: visit::vt<ctx>) {
 
 pub fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
     debug!("kind::check_expr(%s)", expr_to_str(e, cx.tcx.sess.intr()));
-    let id_to_use = match e.node {
+
+    // Handle any kind bounds on type parameters
+    let type_parameter_id = match e.node {
         expr_index(*)|expr_assign_op(*)|
         expr_unary(*)|expr_binary(*)|expr_method_call(*) => e.callee_id,
         _ => e.id
     };
-
-    // Handle any kind bounds on type parameters
-    do option::iter(&cx.tcx.node_type_substs.find(id_to_use)) |ts| {
+    do option::iter(&cx.tcx.node_type_substs.find(type_parameter_id)) |ts| {
         let bounds = match e.node {
           expr_path(_) => {
             let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id));
@@ -299,137 +220,76 @@ pub fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
                       *bounds, (*bounds).len());
         }
         for vec::each2(*ts, *bounds) |ty, bound| {
-            check_bounds(cx, id_to_use, e.span, *ty, *bound)
+            check_bounds(cx, type_parameter_id, e.span, *ty, *bound)
         }
     }
 
-    match /*bad*/copy e.node {
-      expr_assign(_, ex) |
-      expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
-      expr_ret(Some(ex)) => {
-        maybe_copy(cx, ex, Some(("returned values must be copyable",
-                                 try_adding)));
-      }
-      expr_cast(source, _) => {
-        maybe_copy(cx, source, Some(("casted values must be copyable",
-                                     try_adding)));
-        check_cast_for_escaping_regions(cx, source, e);
-        check_kind_bounds_of_cast(cx, source, e);
-      }
-      expr_copy(expr) => check_copy_ex(cx, expr, false,
-          Some(("explicit copy requires a copyable argument", ""))),
-      // Vector add copies, but not "implicitly"
-      expr_assign_op(_, _, ex) => check_copy_ex(cx, ex, false,
-                                   Some(("assignment with operation requires \
-                                          a copyable argument", ""))),
-      expr_binary(add, ls, rs) => {
-        let reason = Some(("binary operators require copyable arguments",
-                           ""));
-        check_copy_ex(cx, ls, false, reason);
-        check_copy_ex(cx, rs, false, reason);
-      }
-      expr_rec(ref fields, def) | expr_struct(_, ref fields, def) => {
-        for (*fields).each |field| { maybe_copy(cx, field.node.expr,
-                                   Some(("record or struct fields require \
-                                          copyable arguments", ""))); }
-        match def {
-          Some(ex) => {
-            // All noncopyable fields must be overridden
-            let t = ty::expr_ty(cx.tcx, ex);
-            let ty_fields = match /*bad*/copy ty::get(t).sty {
-              ty::ty_rec(f) => f,
-              ty::ty_struct(did, ref substs) =>
-                  ty::struct_fields(cx.tcx, did, &(*substs)),
-              _ => cx.tcx.sess.span_bug(ex.span,
-                                        ~"bad base expr type in record")
-            };
-            for ty_fields.each |tf| {
-                if !vec::any((*fields), |f| f.node.ident == tf.ident ) &&
-                    !ty::kind_can_be_copied(ty::type_kind(cx.tcx, tf.mt.ty)) {
-                    cx.tcx.sess.span_err(e.span,
-                                         ~"copying a noncopyable value");
-                }
-            }
-          }
-          _ => {}
+    match e.node {
+        expr_cast(source, _) => {
+            check_cast_for_escaping_regions(cx, source, e);
+            check_kind_bounds_of_cast(cx, source, e);
         }
-      }
-      expr_tup(exprs) | expr_vec(exprs, _) => {
-        for exprs.each |expr| { maybe_copy(cx, *expr,
-                    Some(("tuple or vec elements must be copyable", ""))); }
-      }
-      expr_call(f, args, _) => {
-        for ty::ty_fn_args(ty::expr_ty(cx.tcx, f)).eachi |i, arg_t| {
-            match ty::arg_mode(cx.tcx, *arg_t) {
-              by_copy => maybe_copy(cx, args[i],
-                     Some(("function arguments must be copyable",
-                           "try changing the function to take a reference \
-                            instead"))),
-              by_ref | by_val | by_move => ()
-            }
+        expr_copy(expr) => {
+            // Note: This is the only place where we must check whether the
+            // argument is copyable.  This is not because this is the only
+            // kind of expression that may copy things, but rather because all
+            // other copies will have been converted to moves by by the
+            // `moves` pass if the value is not copyable.
+            check_copy(cx,
+                       ty::expr_ty(cx.tcx, expr),
+                       expr.span,
+                       "explicit copy requires a copyable argument");
         }
-      }
-      expr_method_call(_, _, _, args, _) => {
-        for ty::ty_fn_args(ty::node_id_to_type(cx.tcx, e.callee_id)).eachi
-                |i, arg_t| {
-            match ty::arg_mode(cx.tcx, *arg_t) {
-              by_copy => maybe_copy(cx, args[i],
-                     Some(("function arguments must be copyable",
-                           "try changing the function to take a \
-                            reference instead"))),
-              by_ref | by_val | by_move => ()
-            }
-        }
-      }
-      expr_field(lhs, _, _) => {
-        // If this is a method call with a by-val argument, we need
-        // to check the copy
-        match cx.method_map.find(e.id) {
-            Some(ref mme) => {
-                match ty::arg_mode(cx.tcx, mme.self_arg) {
-                    by_copy => maybe_copy(cx, lhs,
-                      Some(("method call takes its self argument by copy",
-                            ""))),
-                    by_ref | by_val | by_move => ()
+        expr_rec(ref fields, def) | expr_struct(_, ref fields, def) => {
+            match def {
+                Some(ex) => {
+                    // All noncopyable fields must be overridden
+                    let t = ty::expr_ty(cx.tcx, ex);
+                    let ty_fields = match ty::get(t).sty {
+                        ty::ty_rec(ref f) => {
+                            copy *f
+                        }
+                        ty::ty_struct(did, ref substs) => {
+                            ty::struct_fields(cx.tcx, did, substs)
+                        }
+                        _ => {
+                            cx.tcx.sess.span_bug(
+                                ex.span,
+                                ~"bad base expr type in record")
+                        }
+                    };
+                    for ty_fields.each |tf| {
+                        // If this field would not be copied, ok.
+                        if fields.any(|f| f.node.ident == tf.ident) { loop; }
+
+                        // If this field is copyable, ok.
+                        let kind = ty::type_kind(cx.tcx, tf.mt.ty);
+                        if ty::kind_can_be_copied(kind) { loop; }
+
+                        cx.tcx.sess.span_err(
+                            e.span,
+                            fmt!("cannot copy field `%s` of base expression, \
+                                  which has a noncopyable type",
+                                 *cx.tcx.sess.intr().get(tf.ident)));
+                    }
                 }
+                _ => {}
             }
-            _ => ()
         }
-      }
-      expr_repeat(element, count_expr, _) => {
-        let count = ty::eval_repeat_count(cx.tcx, count_expr, e.span);
-        if count == 1 {
-            maybe_copy(cx, element, Some(("trivial repeat takes its element \
-                                           by copy", "")));
-        } else {
-            let element_ty = ty::expr_ty(cx.tcx, element);
-            check_copy(cx, element.id, element_ty, element.span, true,
-                       Some(("repeat takes its elements by copy", "")));
-        }
-      }
-      _ => { }
-    }
-    visit::visit_expr(e, cx, v);
-}
-
-pub fn check_stmt(stmt: @stmt, cx: ctx, v: visit::vt<ctx>) {
-    match stmt.node {
-      stmt_decl(@spanned {node: decl_local(ref locals), _}, _) => {
-        for locals.each |local| {
-            match local.node.init {
-              Some(expr) =>
-                  maybe_copy(cx, expr, Some(("initializer statement \
-                              takes its right-hand side by copy", ""))),
-              _ => {}
+        expr_repeat(element, count_expr, _) => {
+            let count = ty::eval_repeat_count(cx.tcx, count_expr, e.span);
+            if count > 1 {
+                let element_ty = ty::expr_ty(cx.tcx, element);
+                check_copy(cx, element_ty, element.span,
+                           "repeated element will be copied");
             }
         }
-      }
-      _ => {}
+        _ => {}
     }
-    visit::visit_stmt(stmt, cx, v);
+    visit::visit_expr(e, cx, v);
 }
 
-pub fn check_ty(aty: @Ty, cx: ctx, v: visit::vt<ctx>) {
+fn check_ty(aty: @Ty, cx: ctx, v: visit::vt<ctx>) {
     match aty.node {
       ty_path(_, id) => {
         do option::iter(&cx.tcx.node_type_substs.find(id)) |ts| {
@@ -471,11 +331,7 @@ pub fn check_bounds(cx: ctx, id: node_id, sp: span,
     }
 }
 
-pub fn maybe_copy(cx: ctx, ex: @expr, why: Option<(&str,&str)>) {
-    check_copy_ex(cx, ex, true, why);
-}
-
-pub fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
+fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
     match ex.node {
       expr_path(_) => {
         match cx.tcx.def_map.get(ex.id) {
@@ -489,75 +345,31 @@ pub fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
     }
 }
 
-pub fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool,
-                     why: Option<(&str,&str)>) {
-    if ty::expr_is_lval(cx.tcx, cx.method_map, ex) &&
-
-        // a reference to a constant like `none`... no need to warn
-        // about *this* even if the type is Option<~int>
-        !is_nullary_variant(cx, ex) &&
-
-        // borrowed unique value isn't really a copy
-        !is_autorefd(cx, ex)
-    {
-        match cx.tcx.value_modes.find(ex.id) {
-            None => cx.tcx.sess.span_bug(ex.span, ~"no value mode for lval"),
-            Some(MoveValue) | Some(ReadValue) => {} // Won't be a copy.
-            Some(CopyValue) => {
-                debug!("(kind checking) is a copy value: `%s`",
-                       expr_to_str(ex, cx.tcx.sess.intr()));
-                let ty = ty::expr_ty(cx.tcx, ex);
-                check_copy(cx, ex.id, ty, ex.span, implicit_copy, why);
+fn check_imm_free_var(cx: ctx, def: def, sp: span) {
+    match def {
+        def_local(_, is_mutbl) => {
+            if is_mutbl {
+                cx.tcx.sess.span_err(
+                    sp,
+                    ~"mutable variables cannot be implicitly captured");
             }
         }
-    }
-
-    fn is_autorefd(cx: ctx, ex: @expr) -> bool {
-        match cx.tcx.adjustments.find(ex.id) {
-            None => false,
-            Some(ref adj) => adj.autoref.is_some()
-        }
-    }
-}
-
-pub fn check_imm_free_var(cx: ctx, def: def, sp: span) {
-    let msg = ~"mutable variables cannot be implicitly captured; \
-               use a capture clause";
-    match def {
-      def_local(_, is_mutbl) => {
-        if is_mutbl {
-            cx.tcx.sess.span_err(sp, msg);
+        def_arg(*) => { /* ok */ }
+        def_upvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
+        def_binding(*) | def_self(*) => { /*ok*/ }
+        _ => {
+            cx.tcx.sess.span_bug(
+                sp,
+                fmt!("unknown def for free variable: %?", def));
         }
-      }
-      def_arg(*) => { /* ok */ }
-      def_upvar(_, def1, _, _) => {
-        check_imm_free_var(cx, *def1, sp);
-      }
-      def_binding(*) | def_self(*) => { /*ok*/ }
-      _ => {
-        cx.tcx.sess.span_bug(
-            sp,
-            fmt!("unknown def for free variable: %?", def));
-      }
     }
 }
 
-pub fn check_copy(cx: ctx, id: node_id, ty: ty::t, sp: span,
-                  implicit_copy: bool, why: Option<(&str,&str)>) {
+fn check_copy(cx: ctx, ty: ty::t, sp: span, reason: &str) {
     let k = ty::type_kind(cx.tcx, ty);
     if !ty::kind_can_be_copied(k) {
         cx.tcx.sess.span_err(sp, ~"copying a noncopyable value");
-        do why.map |reason| {
-            cx.tcx.sess.span_note(sp, fmt!("%s", reason.first()));
-        };
-    } else if implicit_copy && !ty::kind_can_be_implicitly_copied(k) {
-        cx.tcx.sess.span_lint(
-            implicit_copies, id, cx.current_item,
-            sp,
-            ~"implicitly copying a non-implicitly-copyable value");
-        do why.map |reason| {
-            cx.tcx.sess.span_note(sp, fmt!("%s", reason.second()));
-        };
+        cx.tcx.sess.span_note(sp, fmt!("%s", reason));
     }
 }
 
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 0f9fe013d6f..6d691438359 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -352,7 +352,7 @@ impl LanguageItemCollector {
             return;    // Didn't match.
         }
 
-        match self.item_refs.find(value) {
+        match self.item_refs.find(/*bad*/copy value) {
             None => {
                 // Didn't match.
             }
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index ea8a40520e8..1bc3827586c 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -344,7 +344,7 @@ impl ctxt {
 
         for triples.each |pair| {
             let (meta, level, lintname) = /*bad*/copy *pair;
-            match self.dict.find(lintname) {
+            match self.dict.find(/*bad*/ copy lintname) {
               None => {
                 self.span_lint(
                     new_ctxt.get_level(unrecognized_lint),
@@ -518,9 +518,9 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
 
     fn check_limits(cx: ty::ctxt, binop: ast::binop, l: &ast::expr,
                     r: &ast::expr) -> bool {
-        let (lit, expr, swap) = match (l.node, r.node) {
-            (ast::expr_lit(_), _) => (l, r, true),
-            (_, ast::expr_lit(_)) => (r, l, false),
+        let (lit, expr, swap) = match (&l.node, &r.node) {
+            (&ast::expr_lit(_), _) => (l, r, true),
+            (_, &ast::expr_lit(_)) => (r, l, false),
             _ => return true
         };
         // Normalize the binop so that the literal is always on the RHS in
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 90bcdb54e19..e5e0181bd3c 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -105,12 +105,11 @@
 
 use core::prelude::*;
 
-use middle::capture::{cap_move, cap_drop, cap_copy, cap_ref};
-use middle::capture;
 use middle::pat_util;
-use middle::ty::MoveValue;
 use middle::ty;
 use middle::typeck;
+use middle::moves;
+use util::ppaux::ty_to_str;
 
 use core::cmp;
 use core::dvec::DVec;
@@ -203,6 +202,8 @@ fn live_node_kind_to_str(lnk: LiveNodeKind, cx: ty::ctxt) -> ~str {
 
 pub fn check_crate(tcx: ty::ctxt,
                    method_map: typeck::method_map,
+                   variable_moves_map: moves::VariableMovesMap,
+                   capture_map: moves::CaptureMap,
                    crate: @crate) -> last_use_map {
     let visitor = visit::mk_vt(@visit::Visitor {
         visit_fn: visit_fn,
@@ -213,7 +214,8 @@ pub fn check_crate(tcx: ty::ctxt,
     });
 
     let last_use_map = HashMap();
-    let initial_maps = @IrMaps(tcx, method_map, last_use_map);
+    let initial_maps = @IrMaps(tcx, method_map, variable_moves_map,
+                               capture_map, last_use_map);
     visit::visit_crate(*crate, initial_maps, visitor);
     tcx.sess.abort_if_errors();
     return last_use_map;
@@ -294,28 +296,35 @@ fn relevant_def(def: def) -> Option<node_id> {
 struct IrMaps {
     tcx: ty::ctxt,
     method_map: typeck::method_map,
+    variable_moves_map: moves::VariableMovesMap,
+    capture_map: moves::CaptureMap,
     last_use_map: last_use_map,
 
     mut num_live_nodes: uint,
     mut num_vars: uint,
     live_node_map: HashMap<node_id, LiveNode>,
     variable_map: HashMap<node_id, Variable>,
-    capture_map: HashMap<node_id, @~[CaptureInfo]>,
+    capture_info_map: HashMap<node_id, @~[CaptureInfo]>,
     mut var_kinds: ~[VarKind],
     mut lnks: ~[LiveNodeKind],
 }
 
-fn IrMaps(tcx: ty::ctxt, method_map: typeck::method_map,
+fn IrMaps(tcx: ty::ctxt,
+          method_map: typeck::method_map,
+          variable_moves_map: moves::VariableMovesMap,
+          capture_map: moves::CaptureMap,
           last_use_map: last_use_map) -> IrMaps {
     IrMaps {
         tcx: tcx,
         method_map: method_map,
+        variable_moves_map: variable_moves_map,
+        capture_map: capture_map,
         last_use_map: last_use_map,
         num_live_nodes: 0,
         num_vars: 0,
         live_node_map: HashMap(),
         variable_map: HashMap(),
-        capture_map: HashMap(),
+        capture_info_map: HashMap(),
         var_kinds: ~[],
         lnks: ~[]
     }
@@ -377,11 +386,11 @@ impl IrMaps {
     }
 
     fn set_captures(node_id: node_id, +cs: ~[CaptureInfo]) {
-        self.capture_map.insert(node_id, @cs);
+        self.capture_info_map.insert(node_id, @cs);
     }
 
     fn captures(expr: @expr) -> @~[CaptureInfo] {
-        match self.capture_map.find(expr.id) {
+        match self.capture_info_map.find(expr.id) {
           Some(caps) => caps,
           None => {
             self.tcx.sess.span_bug(expr.span, ~"no registered caps");
@@ -397,7 +406,6 @@ impl IrMaps {
         let vk = self.var_kinds[*var];
         debug!("Node %d is a last use of variable %?", expr_id, vk);
         match vk {
-          Arg(id, _, by_move) |
           Arg(id, _, by_copy) |
           Local(LocalInfo {id: id, kind: FromLetNoInitializer, _}) |
           Local(LocalInfo {id: id, kind: FromLetWithInitializer, _}) |
@@ -427,7 +435,10 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
     let _i = ::util::common::indenter();
 
     // swap in a new set of IR maps for this function body:
-    let fn_maps = @IrMaps(self.tcx, self.method_map,
+    let fn_maps = @IrMaps(self.tcx,
+                          self.method_map,
+                          self.variable_moves_map,
+                          self.capture_map,
                           self.last_use_map);
 
     debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint);
@@ -548,8 +559,8 @@ fn visit_expr(expr: @expr, &&self: @IrMaps, vt: vt<@IrMaps>) {
         }
         visit::visit_expr(expr, self, vt);
       }
-      expr_fn(_, _, _, cap_clause) |
-      expr_fn_block(_, _, cap_clause) => {
+      expr_fn(_, _, _) |
+      expr_fn_block(_, _) => {
         // Interesting control flow (for loops can contain labeled
         // breaks or continues)
         self.add_live_node_for_node(expr.id, ExprNode(expr.span));
@@ -558,17 +569,18 @@ fn visit_expr(expr: @expr, &&self: @IrMaps, vt: vt<@IrMaps>) {
         // being the location that the variable is used.  This results
         // in better error messages than just pointing at the closure
         // construction site.
-        let proto = ty::ty_fn_proto(ty::expr_ty(self.tcx, expr));
-        let cvs = capture::compute_capture_vars(self.tcx, expr.id, proto,
-                                                cap_clause);
+        let cvs = self.capture_map.get(expr.id);
         let mut call_caps = ~[];
         for cvs.each |cv| {
             match relevant_def(cv.def) {
               Some(rv) => {
                 let cv_ln = self.add_live_node(FreeVarNode(cv.span));
                 let is_move = match cv.mode {
-                  cap_move | cap_drop => true, // var must be dead afterwards
-                  cap_copy | cap_ref => false // var can still be used
+                    // var must be dead afterwards
+                    moves::CapMove => true,
+
+                    // var can stil be used
+                    moves::CapCopy | moves::CapRef => false
                 };
                 call_caps.push(CaptureInfo {ln: cv_ln,
                                             is_move: is_move,
@@ -600,7 +612,7 @@ fn visit_expr(expr: @expr, &&self: @IrMaps, vt: vt<@IrMaps>) {
       expr_loop_body(*) | expr_do_body(*) | expr_cast(*) |
       expr_unary(*) | expr_fail(*) |
       expr_break(_) | expr_again(_) | expr_lit(_) | expr_ret(*) |
-      expr_block(*) | expr_unary_move(*) | expr_assign(*) |
+      expr_block(*) | expr_assign(*) |
       expr_swap(*) | expr_assign_op(*) | expr_mac(*) | expr_struct(*) |
       expr_repeat(*) | expr_paren(*) => {
           visit::visit_expr(expr, self, vt);
@@ -700,7 +712,7 @@ impl Liveness {
     }
 
     fn variable(node_id: node_id, span: span) -> Variable {
-        (*self.ir).variable(node_id, span)
+        self.ir.variable(node_id, span)
     }
 
     fn variable_from_def_map(node_id: node_id,
@@ -760,7 +772,7 @@ impl Liveness {
 
         assert ln.is_valid();
         let reader = self.users[self.idx(ln, var)].reader;
-        if reader.is_valid() {Some((*self.ir).lnk(reader))} else {None}
+        if reader.is_valid() {Some(self.ir.lnk(reader))} else {None}
     }
 
     /*
@@ -782,7 +794,7 @@ impl Liveness {
 
         assert ln.is_valid();
         let writer = self.users[self.idx(ln, var)].writer;
-        if writer.is_valid() {Some((*self.ir).lnk(writer))} else {None}
+        if writer.is_valid() {Some(self.ir.lnk(writer))} else {None}
     }
 
     fn assigned_on_exit(ln: LiveNode, var: Variable)
@@ -980,21 +992,22 @@ impl Liveness {
         // inputs passed by & mode should be considered live on exit:
         for decl.inputs.each |arg| {
             match ty::resolved_mode(self.tcx, arg.mode) {
-              by_ref | by_val => {
-                // These are "non-owned" modes, so register a read at
-                // the end.  This will prevent us from moving out of
-                // such variables but also prevent us from registering
-                // last uses and so forth.
-                do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
-                        |_bm, arg_id, _sp, _path| {
-                    let var = self.variable(arg_id, blk.span);
-                    self.acc(self.s.exit_ln, var, ACC_READ);
+                by_val | by_ref => {
+                    // By val and by ref do not own, so register a
+                    // read at the end.  This will prevent us from
+                    // moving out of such variables but also prevent
+                    // us from registering last uses and so forth.
+                    do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
+                        |_bm, arg_id, _sp, _path|
+                    {
+                        let var = self.variable(arg_id, blk.span);
+                        self.acc(self.s.exit_ln, var, ACC_READ);
+                    }
+                }
+                by_copy => {
+                    // By copy is an owned mode.  If we don't use the
+                    // variable, nobody will.
                 }
-              }
-              by_move | by_copy => {
-                // These are owned modes.  If we don't use the
-                // variable, nobody will.
-              }
             }
         }
 
@@ -1092,7 +1105,7 @@ impl Liveness {
               self.propagate_through_expr(e, succ)
           }
 
-          expr_fn(_, _, ref blk, _) | expr_fn_block(_, ref blk, _) => {
+          expr_fn(_, _, ref blk) | expr_fn_block(_, ref blk) => {
               debug!("%s is an expr_fn or expr_fn_block",
                    expr_to_str(expr, self.tcx.sess.intr()));
 
@@ -1105,8 +1118,8 @@ impl Liveness {
 
                  // the construction of a closure itself is not important,
                  // but we have to consider the closed over variables.
-                 let caps = (*self.ir).captures(expr);
-                 do (*caps).foldr(succ) |cap, succ| {
+                 let caps = self.ir.captures(expr);
+                 do caps.foldr(succ) |cap, succ| {
                      self.init_from_succ(cap.ln, succ);
                      let var = self.variable(cap.var_nid, expr.span);
                      self.acc(cap.ln, var, ACC_READ | ACC_USE);
@@ -1315,7 +1328,6 @@ impl Liveness {
           expr_assert(e) |
           expr_addr_of(_, e) |
           expr_copy(e) |
-          expr_unary_move(e) |
           expr_loop_body(e) |
           expr_do_body(e) |
           expr_cast(e, _) |
@@ -1541,26 +1553,6 @@ fn check_arm(arm: arm, &&self: @Liveness, vt: vt<@Liveness>) {
     visit::visit_arm(arm, self, vt);
 }
 
-fn check_call(args: &[@expr],
-              targs: &[ty::arg],
-              &&self: @Liveness) {
-    for vec::each2(args, targs) |arg_expr, arg_ty| {
-        match ty::resolved_mode(self.tcx, arg_ty.mode) {
-            by_val | by_copy | by_ref => {}
-            by_move => {
-                if ty::expr_is_lval(self.tcx, self.ir.method_map, *arg_expr) {
-                    // Probably a bad error message (what's an rvalue?)
-                    // but I can't think of anything better
-                    self.tcx.sess.span_err(arg_expr.span,
-                      fmt!("move mode argument must be an rvalue: try (move \
-                            %s) instead",
-                           expr_to_str(*arg_expr, self.tcx.sess.intr())));
-                }
-            }
-        }
-    }
-}
-
 fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
     match /*bad*/copy expr.node {
       expr_path(_) => {
@@ -1568,19 +1560,12 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
             let ln = self.live_node(expr.id, expr.span);
             self.consider_last_use(expr, ln, *var);
 
-            match self.tcx.value_modes.find(expr.id) {
-                Some(MoveValue) => {
+            match self.ir.variable_moves_map.find(expr.id) {
+                None => {}
+                Some(entire_expr) => {
                     debug!("(checking expr) is a move: `%s`",
                            expr_to_str(expr, self.tcx.sess.intr()));
-                    self.check_move_from_var(expr.span, ln, *var);
-                }
-                Some(v) => {
-                    debug!("(checking expr) not a move (%?): `%s`",
-                           v,
-                           expr_to_str(expr, self.tcx.sess.intr()));
-                }
-                None => {
-                    fail ~"no mode for lval";
+                    self.check_move_from_var(ln, *var, entire_expr);
                 }
             }
         }
@@ -1589,12 +1574,12 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
       }
 
       expr_fn(*) | expr_fn_block(*) => {
-        let caps = (*self.ir).captures(expr);
-        for (*caps).each |cap| {
+        let caps = self.ir.captures(expr);
+        for caps.each |cap| {
             let var = self.variable(cap.var_nid, expr.span);
             self.consider_last_use(expr, cap.ln, var);
             if cap.is_move {
-                self.check_move_from_var(expr.span, cap.ln, var);
+                self.check_move_from_var(cap.ln, var, expr);
             }
         }
 
@@ -1608,32 +1593,14 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
         visit::visit_expr(expr, self, vt);
       }
 
-      expr_unary_move(r) => {
-        self.check_move_from_expr(r, vt);
-
-        visit::visit_expr(expr, self, vt);
-      }
-
       expr_assign_op(_, l, _) => {
         self.check_lvalue(l, vt);
 
         visit::visit_expr(expr, self, vt);
       }
 
-      expr_call(f, args, _) => {
-        let targs = ty::ty_fn_args(ty::expr_ty(self.tcx, f));
-        check_call(args, targs, self);
-        visit::visit_expr(expr, self, vt);
-      }
-
-      expr_method_call(_, _, _, args, _) => {
-        let targs = ty::ty_fn_args(ty::node_id_to_type(self.tcx,
-                                                       expr.callee_id));
-        check_call(args, targs, self);
-        visit::visit_expr(expr, self, vt);
-      }
-
       // no correctness conditions related to liveness
+      expr_call(*) | expr_method_call(*) |
       expr_if(*) | expr_match(*) |
       expr_while(*) | expr_loop(*) |
       expr_index(*) | expr_field(*) | expr_vstore(*) |
@@ -1659,7 +1626,8 @@ fn check_fn(_fk: visit::fn_kind, _decl: fn_decl,
 enum ReadKind {
     PossiblyUninitializedVariable,
     PossiblyUninitializedField,
-    MovedValue
+    MovedValue,
+    PartiallyMovedValue
 }
 
 impl @Liveness {
@@ -1683,17 +1651,28 @@ impl @Liveness {
         }
     }
 
-    /*
-    Checks whether <var> is live on entry to any of the successors of <ln>.
-    If it is, report an error.
-    */
-    fn check_move_from_var(span: span, ln: LiveNode, var: Variable) {
+    fn check_move_from_var(ln: LiveNode,
+                           var: Variable,
+                           move_expr: @expr)
+    {
+        /*!
+         *
+         * Checks whether `var` is live on entry to any of the
+         * successors of `ln`.  If it is, report an error.
+         * `move_expr` is the expression which caused the variable
+         * to be moved.
+         *
+         * Note that `move_expr` is not necessarily a reference to the
+         * variable.  It might be an expression like `x.f` which could
+         * cause a move of the variable `x`, or a closure creation.
+         */
+
         debug!("check_move_from_var(%s, %s)",
                ln.to_str(), var.to_str());
 
         match self.live_on_exit(ln, var) {
           None => {}
-          Some(lnk) => self.report_illegal_move(span, lnk, var)
+          Some(lnk) => self.report_illegal_move(lnk, var, move_expr)
         }
     }
 
@@ -1703,48 +1682,7 @@ impl @Liveness {
 
         match self.live_on_exit(ln, var) {
           Some(_) => {}
-          None => (*self.ir).add_last_use(expr.id, var)
-       }
-    }
-
-    fn check_move_from_expr(expr: @expr, vt: vt<@Liveness>) {
-        debug!("check_move_from_expr(node %d: %s)",
-               expr.id, expr_to_str(expr, self.tcx.sess.intr()));
-
-        if self.ir.method_map.contains_key(expr.id) {
-            // actually an rvalue, since this calls a method
-            return;
-        }
-
-        match expr.node {
-          expr_path(_) => {
-            match self.variable_from_path(expr) {
-              Some(var) => {
-                let ln = self.live_node(expr.id, expr.span);
-                self.check_move_from_var(expr.span, ln, var);
-              }
-              None => {}
-            }
-          }
-
-          expr_field(base, _, _) => {
-            // Moving from x.y is allowed if x is never used later.
-            // (Note that the borrowck guarantees that anything
-            //  being moved from is uniquely tied to the stack frame)
-            self.check_move_from_expr(base, vt);
-          }
-
-          expr_index(base, _) => {
-            // Moving from x[y] is allowed if x is never used later.
-            // (Note that the borrowck guarantees that anything
-            //  being moved from is uniquely tied to the stack frame)
-            self.check_move_from_expr(base, vt);
-          }
-
-          _ => {
-            // For other kinds of lvalues, no checks are required,
-            // and any embedded expressions are actually rvalues
-          }
+          None => self.ir.add_last_use(expr.id, var)
        }
     }
 
@@ -1808,36 +1746,84 @@ impl @Liveness {
         }
     }
 
-    fn report_illegal_move(move_span: span,
-                           lnk: LiveNodeKind,
-                           var: Variable) {
-
-        // the only time that it is possible to have a moved value
+    fn report_illegal_move(lnk: LiveNodeKind,
+                           var: Variable,
+                           move_expr: @expr)
+    {
+        // the only time that it is possible to have a moved variable
         // used by ExitNode would be arguments or fields in a ctor.
         // we give a slightly different error message in those cases.
         if lnk == ExitNode {
+            // XXX this seems like it should be reported in the borrow checker
             let vk = self.ir.var_kinds[*var];
             match vk {
               Arg(_, name, _) => {
                 self.tcx.sess.span_err(
-                    move_span,
+                    move_expr.span,
                     fmt!("illegal move from argument `%s`, which is not \
                           copy or move mode", self.tcx.sess.str_of(name)));
                 return;
               }
               Local(*) | ImplicitRet => {
                 self.tcx.sess.span_bug(
-                    move_span,
+                    move_expr.span,
                     fmt!("illegal reader (%?) for `%?`",
                          lnk, vk));
               }
             }
         }
 
-        self.report_illegal_read(move_span, lnk, var, MovedValue);
-        self.tcx.sess.span_note(
-            move_span, ~"move of value occurred here");
+        match move_expr.node {
+            expr_fn(*) | expr_fn_block(*) => {
+                self.report_illegal_read(
+                    move_expr.span, lnk, var, MovedValue);
+                let name = self.ir.variable_name(var);
+                self.tcx.sess.span_note(
+                    move_expr.span,
+                    fmt!("`%s` moved into closure environment here \
+                          because its type is moved by default",
+                         name));
+            }
+            expr_path(*) => {
+                self.report_illegal_read(
+                    move_expr.span, lnk, var, MovedValue);
+                self.report_move_location(
+                    move_expr, var, "", "it");
+            }
+            expr_field(*) => {
+                self.report_illegal_read(
+                    move_expr.span, lnk, var, PartiallyMovedValue);
+                self.report_move_location(
+                    move_expr, var, "field of ", "the field");
+            }
+            expr_index(*) => {
+                self.report_illegal_read(
+                    move_expr.span, lnk, var, PartiallyMovedValue);
+                self.report_move_location(
+                    move_expr, var, "element of ", "the element");
+            }
+            _ => {
+                self.report_illegal_read(
+                    move_expr.span, lnk, var, PartiallyMovedValue);
+                self.report_move_location(
+                    move_expr, var, "subcomponent of ", "the subcomponent");
+            }
+        };
+    }
 
+    fn report_move_location(move_expr: @expr,
+                            var: Variable,
+                            expr_descr: &str,
+                            pronoun: &str)
+    {
+        let move_expr_ty = ty::expr_ty(self.tcx, move_expr);
+        let name = self.ir.variable_name(var);
+        self.tcx.sess.span_note(
+            move_expr.span,
+            fmt!("%s`%s` moved here because %s has type %s, \
+                  which is moved by default (use `copy` to override)",
+                 expr_descr, name, pronoun,
+                 ty_to_str(self.tcx, move_expr_ty)));
     }
 
     fn report_illegal_read(chk_span: span,
@@ -1845,13 +1831,13 @@ impl @Liveness {
                            var: Variable,
                            rk: ReadKind) {
         let msg = match rk {
-          PossiblyUninitializedVariable => {
-            ~"possibly uninitialized variable"
-          }
-          PossiblyUninitializedField => ~"possibly uninitialized field",
-          MovedValue => ~"moved value"
+            PossiblyUninitializedVariable => "possibly uninitialized \
+                                              variable",
+            PossiblyUninitializedField => "possibly uninitialized field",
+            MovedValue => "moved value",
+            PartiallyMovedValue => "partially moved value"
         };
-        let name = (*self.ir).variable_name(var);
+        let name = self.ir.variable_name(var);
         match lnk {
           FreeVarNode(span) => {
             self.tcx.sess.span_err(
@@ -1863,8 +1849,7 @@ impl @Liveness {
                 span,
                 fmt!("use of %s: `%s`", msg, name));
           }
-          ExitNode |
-          VarDefNode(_) => {
+          ExitNode | VarDefNode(_) => {
             self.tcx.sess.span_bug(
                 chk_span,
                 fmt!("illegal reader: %?", lnk));
@@ -1873,7 +1858,7 @@ impl @Liveness {
     }
 
     fn should_warn(var: Variable) -> Option<~str> {
-        let name = (*self.ir).variable_name(var);
+        let name = self.ir.variable_name(var);
         if name[0] == ('_' as u8) {None} else {Some(name)}
     }
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 687e9cdc74d..625b9889aad 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -394,7 +394,7 @@ pub impl &mem_categorization_ctxt {
           ast::expr_block(*) | ast::expr_loop(*) | ast::expr_match(*) |
           ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) |
           ast::expr_again(*) | ast::expr_rec(*) | ast::expr_struct(*) |
-          ast::expr_unary_move(*) | ast::expr_repeat(*) => {
+          ast::expr_repeat(*) => {
             return self.cat_rvalue(expr, expr_ty);
           }
         }
@@ -430,20 +430,16 @@ pub impl &mem_categorization_ctxt {
             // lp: loan path, must be none for aliasable things
             let m = if mutbl {m_mutbl} else {m_imm};
             let lp = match ty::resolved_mode(self.tcx, mode) {
-              ast::by_move | ast::by_copy => {
-                Some(@lp_arg(vid))
-              }
-              ast::by_ref => {
-                None
-              }
-              ast::by_val => {
-                // by-value is this hybrid mode where we have a
-                // pointer but we do not own it.  This is not
-                // considered loanable because, for example, a by-ref
-                // and and by-val argument might both actually contain
-                // the same unique ptr.
-                None
-              }
+                ast::by_copy => Some(@lp_arg(vid)),
+                ast::by_ref => None,
+                ast::by_val => {
+                    // by-value is this hybrid mode where we have a
+                    // pointer but we do not own it.  This is not
+                    // considered loanable because, for example, a by-ref
+                    // and and by-val argument might both actually contain
+                    // the same unique ptr.
+                    None
+                }
             };
             @cmt_ {
                 id:id,
diff --git a/src/librustc/middle/mode.rs b/src/librustc/middle/mode.rs
deleted file mode 100644
index 149821db289..00000000000
--- a/src/librustc/middle/mode.rs
+++ /dev/null
@@ -1,281 +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.
-
-use core::prelude::*;
-
-use middle::pat_util;
-use middle::ty;
-use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt};
-use middle::typeck::{method_map, method_map_entry};
-
-use core::vec;
-use std::map::HashMap;
-use syntax::ast::{bind_infer, box, by_copy, by_move, by_ref, by_val, crate};
-use syntax::ast::{deref, expr, expr_addr_of, expr_assign, expr_assign_op};
-use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
-use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
-use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
-use syntax::ast::{expr_vstore, expr_vec, expr_rec, expr_tup, expr_lit};
-use syntax::ast::{expr_cast, expr_if, expr_while, expr_loop, expr_fn};
-use syntax::ast::{expr_fn_block, expr_loop_body, expr_do_body, expr_block};
-use syntax::ast::{expr_unary_move, expr_fail, expr_break, expr_again};
-use syntax::ast::{expr_ret, expr_log, expr_assert, expr_mac, expr_struct};
-use syntax::ast::{expr_repeat};
-use syntax::ast::{sty_uniq, sty_value, uniq};
-use syntax::ast::{fn_decl, blk};
-use syntax::visit;
-use syntax::visit::{fn_kind, vt};
-use syntax::print::pprust;
-use syntax::codemap::span;
-
-struct VisitContext {
-    tcx: ctxt,
-    method_map: HashMap<node_id,method_map_entry>,
-    mode: ValueMode,
-}
-
-fn compute_modes_for_fn(fk: fn_kind,
-                        decl: fn_decl,
-                        body: blk,
-                        sp: span,
-                        id: node_id,
-                        &&cx: VisitContext,
-                        v: vt<VisitContext>) {
-    let body_cx = VisitContext { mode: MoveValue, ..cx };
-    visit::visit_fn(fk, decl, body, sp, id, body_cx, v);
-}
-
-fn compute_modes_for_fn_args(callee_id: node_id,
-                             args: &[@expr],
-                             last_arg_is_block: bool,
-                             &&cx: VisitContext,
-                             v: vt<VisitContext>) {
-    let arg_tys = ty::ty_fn_args(ty::node_id_to_type(cx.tcx, callee_id));
-    let mut i = 0;
-    for vec::each2(args, arg_tys) |arg, arg_ty| {
-        if last_arg_is_block && i == args.len() - 1 {
-            let block_cx = VisitContext { mode: MoveValue, ..cx };
-            compute_modes_for_expr(*arg, block_cx, v);
-        } else {
-            match ty::resolved_mode(cx.tcx, arg_ty.mode) {
-                by_ref => {
-                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
-                    compute_modes_for_expr(*arg, arg_cx, v);
-                }
-                by_val | by_move | by_copy => {
-                    compute_modes_for_expr(*arg, cx, v);
-                }
-            }
-        }
-        i += 1;
-    }
-}
-
-fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
-    match cx.mode {
-        ReadValue | CopyValue => {
-            cx.tcx.value_modes.insert(expr.id, cx.mode);
-        }
-        MoveValue => {
-            // This is, contextually, a move, but if this expression
-            // is implicitly copyable it's cheaper to copy.
-            let e_ty = ty::expr_ty(cx.tcx, expr);
-            if ty::type_implicitly_moves(cx.tcx, e_ty) {
-                cx.tcx.value_modes.insert(expr.id, MoveValue);
-            } else {
-                cx.tcx.value_modes.insert(expr.id, CopyValue);
-            }
-        }
-    }
-}
-
-fn compute_modes_for_expr(expr: @expr,
-                          &&cx: VisitContext,
-                          v: vt<VisitContext>) {
-    debug!("compute_modes_for_expr(expr=%?/%s, mode=%?)",
-           expr.id, pprust::expr_to_str(expr, cx.tcx.sess.intr()),
-           cx.mode);
-
-    // Adjust the mode if there was an implicit reference here.
-    let cx = match cx.tcx.adjustments.find(expr.id) {
-        None => cx,
-        Some(adjustment) => {
-            if adjustment.autoref.is_some() {
-                VisitContext { mode: ReadValue, ..cx }
-            } else {
-                cx
-            }
-        }
-    };
-
-    match copy expr.node {
-        expr_call(callee, args, is_block) => {
-            let callee_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(callee, callee_cx, v);
-            compute_modes_for_fn_args(callee.id, args, is_block, cx, v);
-        }
-        expr_path(*) => {
-            record_mode_for_expr(expr, cx);
-        }
-        expr_copy(expr) => {
-            let callee_cx = VisitContext { mode: CopyValue, ..cx };
-            compute_modes_for_expr(expr, callee_cx, v);
-        }
-        expr_method_call(callee, _, _, args, is_block) => {
-            // The LHS of the dot may or may not result in a move, depending
-            // on the method map entry.
-            let callee_mode;
-            match cx.method_map.find(expr.id) {
-                Some(ref method_map_entry) => {
-                    match method_map_entry.explicit_self {
-                        sty_uniq(_) | sty_value => callee_mode = MoveValue,
-                        _ => callee_mode = ReadValue
-                    }
-                }
-                None => {
-                    cx.tcx.sess.span_bug(expr.span, ~"no method map entry");
-                }
-            }
-
-            let callee_cx = VisitContext { mode: callee_mode, ..cx };
-            compute_modes_for_expr(callee, callee_cx, v);
-
-            compute_modes_for_fn_args(expr.callee_id, args, is_block, cx, v);
-        }
-        expr_binary(_, lhs, rhs) | expr_assign_op(_, lhs, rhs) => {
-            // The signatures of these take their arguments by-ref, so they
-            // don't copy or move.
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(lhs, arg_cx, v);
-            compute_modes_for_expr(rhs, arg_cx, v);
-        }
-        expr_addr_of(_, arg) => {
-            // Takes its argument by-ref, so it doesn't copy or move.
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(arg, arg_cx, v);
-        }
-        expr_unary(unop, arg) => {
-            match unop {
-                deref => {
-                    // Derefs function as reads.
-                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
-                    compute_modes_for_expr(arg, arg_cx, v);
-
-                    // This is an lvalue, so it needs a value mode recorded
-                    // for it.
-                    record_mode_for_expr(expr, cx);
-                }
-                box(_) | uniq(_) => {
-                    let arg_cx = VisitContext { mode: MoveValue, ..cx };
-                    compute_modes_for_expr(arg, arg_cx, v);
-                }
-                not | neg => {
-                    // Takes its argument by ref.
-                    let arg_cx = VisitContext { mode: ReadValue, ..cx };
-                    compute_modes_for_expr(arg, arg_cx, v);
-                }
-            }
-        }
-        expr_field(arg, _, _) => {
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(arg, arg_cx, v);
-
-            record_mode_for_expr(expr, cx);
-        }
-        expr_assign(lhs, rhs) => {
-            // The signatures of these take their arguments by-ref, so they
-            // don't copy or move.
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(lhs, arg_cx, v);
-            compute_modes_for_expr(rhs, cx, v);
-        }
-        expr_swap(lhs, rhs) => {
-            let arg_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(lhs, arg_cx, v);
-            compute_modes_for_expr(rhs, arg_cx, v);
-        }
-        expr_index(lhs, rhs) => {
-            let lhs_cx = VisitContext { mode: ReadValue, ..cx };
-            compute_modes_for_expr(lhs, lhs_cx, v);
-            let rhs_cx = VisitContext { mode: MoveValue, ..cx };
-            compute_modes_for_expr(rhs, rhs_cx, v);
-
-            record_mode_for_expr(expr, cx);
-        }
-        expr_paren(arg) => {
-            compute_modes_for_expr(arg, cx, v);
-            record_mode_for_expr(expr, cx);
-        }
-        expr_match(head, ref arms) => {
-            // We must do this first so that `arms_have_by_move_bindings`
-            // below knows which bindings are moves.
-            for arms.each |arm| {
-                (v.visit_arm)(*arm, cx, v);
-            }
-
-            let by_move_bindings_present =
-                pat_util::arms_have_by_move_bindings(cx.tcx, *arms);
-            if by_move_bindings_present {
-                // Propagate the current mode flag downward.
-                visit::visit_expr(expr, cx, v);
-            } else {
-                // We aren't moving into any pattern, so this is just a read.
-                let head_cx = VisitContext { mode: ReadValue, ..cx };
-                compute_modes_for_expr(head, head_cx, v);
-            }
-        }
-        // Spell out every remaining expression so we don't forget to
-        // update this code if we add a new variant.
-        // (Maybe a macro to do this would be nice...)
-        expr_vstore(*) | expr_vec(*) | expr_rec(*) | expr_tup(*) |
-            expr_lit(*) | expr_cast(*) | expr_if(*) | expr_while(*) |
-            expr_loop(*) | expr_fn(*) | expr_fn_block(*) |
-            expr_loop_body(*) | expr_do_body(*) | expr_block(*) |
-            expr_unary_move(*) | expr_fail(*) | expr_break(*) |
-            expr_again(*) | expr_ret(*) | expr_log(*) | expr_assert(*) |
-            expr_mac(*) | expr_struct(*) | expr_repeat(*) => {
-            visit::visit_expr(expr, cx, v)
-        }
-    }
-}
-
-fn compute_modes_for_pat(pat: @pat,
-                         &&cx: VisitContext,
-                         v: vt<VisitContext>) {
-    match pat.node {
-        pat_ident(bind_infer, _, _)
-                if pat_util::pat_is_binding(cx.tcx.def_map, pat) => {
-            if ty::type_implicitly_moves(cx.tcx, ty::pat_ty(cx.tcx, pat)) {
-                cx.tcx.value_modes.insert(pat.id, MoveValue);
-            } else {
-                cx.tcx.value_modes.insert(pat.id, CopyValue);
-            }
-        }
-        _ => {}
-    }
-
-    visit::visit_pat(pat, cx, v);
-}
-
-pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
-    let visitor = visit::mk_vt(@visit::Visitor {
-        visit_fn: compute_modes_for_fn,
-        visit_expr: compute_modes_for_expr,
-        visit_pat: compute_modes_for_pat,
-        .. *visit::default_visitor()
-    });
-    let callee_cx = VisitContext {
-        tcx: tcx,
-        method_map: method_map,
-        mode: MoveValue
-    };
-    visit::visit_crate(*crate, callee_cx, visitor);
-}
-
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
new file mode 100644
index 00000000000..2d6565cc9c6
--- /dev/null
+++ b/src/librustc/middle/moves.rs
@@ -0,0 +1,815 @@
+// 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.
+
+/*!
+
+# Moves Computation
+
+The goal of this file is to compute which
+expressions/patterns/captures correspond to *moves*.  This is
+generally a function of the context in which the expression appears as
+well as the expression's type.
+
+## Examples
+
+We will use the following fragment of code to explain the various
+considerations.  Note that in this code `x` is used after it has been
+moved here.  This is not relevant to this pass, though the information
+we compute would later be used to detect this error (see the section
+Enforcement of Moves, below).
+
+    struct Foo { a: int, b: ~int }
+    let x: Foo = ...;
+    let w = (x {Read}).a;      // Read
+    let y = (x {Move}).b;      // Move
+    let z = copy (x {Read}).b; // Read
+
+Let's look at these examples one by one.  In the first case, `w`, the
+expression being assigned is `x.a`, which has `int` type.  In that
+case, the value is read, and the container (`x`) is also read.
+
+In the second case, `y`, `x.b` is being assigned which has type
+`~int`.  Because this type moves by default, that will be a move
+reference.  Whenever we move from a compound expression like `x.b` (or
+`x[b]` or `*x` or `{x)[b].c`, etc), this invalidates all containing
+expressions since we do not currently permit "incomplete" variables
+where part of them has been moved and part has not.  In this case,
+this means that the reference to `x` is also a move.  We'll see later,
+though, that these kind of "partial moves", where part of the
+expression has been moved, are classified and stored somewhat
+differently.
+
+The final example (`z`) is `copy x.b`: in this case, although the
+expression being assigned has type `~int`, there are no moves
+involved.
+
+### Patterns
+
+For each binding in a match or let pattern, we also compute a read
+or move designation.  A move binding means that the value will be
+moved from the value being matched.  As a result, the expression
+being matched (aka, the 'discriminant') is either moved or read
+depending on whethe the bindings move the value they bind to out of
+the discriminant.
+
+For examples, consider this match expression:
+
+    match x {Move} {
+      Foo { a: a {Read}, b: b {Move} } => {...}
+    }
+
+Here, the binding `b` is value (not ref) mode, and `b` has type
+`~int`, and therefore the discriminant expression `x` would be
+incomplete so it also considered moved.
+
+In the following two examples, in contrast, the mode of `b` is either
+`copy` or `ref` and hence the overall result is a read:
+
+    match x {Read} {
+      Foo { a: a {Read}, b: copy b {Read} } => {...}
+    }
+
+    match x {Read} {
+      Foo { a: a {Read}, b: ref b {Read} } => {...}
+    }
+
+Similar reasoning can be applied to `let` expressions:
+
+    let Foo { a: a {Read}, b: b {Move} } = x {Move};
+    let Foo { a: a {Read}, b: copy b {Read} } = x {Read};
+    let Foo { a: a {Read}, b: ref b  {Read} } = x {Read};
+
+## Output
+
+The pass results in the struct `MoveMaps` which contains two sets,
+`moves_map` and `variable_moves_map`, and one map, `capture_map`.
+
+`moves_map` is a set containing the id of every *outermost
+expression* or *binding* that is moved.  Note that `moves_map` only
+contains the *outermost expressions* that are moved.  Therefore, if
+you have a use of `x.b`, as in the example `y` above, the
+expression `x.b` would be in the `moves_map` but not `x`.  The
+reason for this is that, for most purposes, it's only the outermost
+expression that is needed.  The borrow checker and trans, for
+example, only care about the outermost expressions that are moved.
+It is more efficient therefore just to store those entries.
+
+In the case of the liveness pass, however, we need to know which
+*variable references* are moved (see the Enforcement of Moves
+section below for more details).  That is, for the `x.b`
+expression, liveness only cares about the `x`.  For this purpose,
+we have a second map, `variable_moves_map`, that contains the ids
+of all variable references which is moved.
+
+The `capture_map` maps from the node_id of a closure expression to an
+array of `CaptureVar` structs detailing which variables are captured
+and how (by ref, by copy, by move).
+
+## Enforcement of Moves
+
+The enforcement of moves is somewhat complicated because it is divided
+amongst the liveness and borrowck modules. In general, the borrow
+checker is responsible for guaranteeing that *only owned data is
+moved*.  The liveness checker, in contrast, is responsible for
+checking that *no variable is used after it is moved*.
+
+To see the difference, let's look at a few examples.  Here is a
+program fragment where the error would be caught by liveness:
+
+    struct Foo { a: int, b: ~int }
+    let x: Foo = ...;
+    let y = x.b; // (1)
+    let z = x;   // (2)            //~ ERROR use of moved value `x`
+
+Here the liveness checker will see the assignment to `y` moves
+invalidates the variable `x` because it moves the expression `x.b`.
+An error is resported because `x` is not dead at the point where it is
+invalidated.
+
+In more concrete terms, the `moves_map` generated from this example
+would contain both the expression `x.b` (1) and the expression `x`
+(2).  Note that it would not contain `x` (1), because `moves_map` only
+contains the outermost expressions that are moved.  However,
+`moves_map` is not used by liveness.  It uses the
+`variable_moves_map`, which would contain both references to `x`: (1)
+and (2).  Therefore, after computing which variables are live where,
+liveness will see that the reference (1) to `x` is both present in
+`variable_moves_map` and that `x` is live and report an error.
+
+Now let's look at another illegal example, but one where liveness would
+not catch the error:
+
+    struct Foo { a: int, b: ~int }
+    let x: @Foo = ...;
+    let y = x.b;                   //~ ERROR move from managed (@) box
+
+This is an interesting example because the only change I've made is
+to make `x` have type `@Foo` and not `Foo`.  Thanks to auto-deref,
+the expression `x.b` still works, but now it is short for `{x).b`,
+and hence the move is actually moving out of the contents of a
+managed box, which is illegal.  However, liveness knows nothing of
+this.  It only tracks what variables are used where.  The moves
+pass (that is, this pass) is also ignorant of such details.  From
+the perspective of the moves pass, the `let y = x.b` line above
+will be categorized as follows:
+
+    let y = {(x{Move}) {Move}).b; {Move}
+
+Therefore, the reference to `x` will be present in
+`variable_moves_map`, but liveness will not report an error because
+there is no subsequent use.
+
+This is where the borrow checker comes in.  When the borrow checker
+runs, it will see that `x.b` is present in the `moves_map`.  It will
+use the `mem_categorization` module to determine where the result of
+this expression resides in memory and see that it is owned by managed
+data, and report an error.
+
+In principle, liveness could use the `mem_categorization` module
+itself and check that moves always originate from owned data
+(historically, of course, this was not the case; `mem_categorization`
+used to be private to the borrow checker).  However, there is another
+kind of error which liveness could not possibly detect. Sometimes a
+move is an error due to an outstanding loan, and it is borrow
+checker's job to compute those loans.  That is, consider *this*
+example:
+
+    struct Foo { a: int, b: ~int }
+    let x: Foo = ...;
+    let y = &x.b;                   //~ NOTE loan issued here
+    let z = x.b;                    //~ ERROR move with outstanding loan
+
+In this case, `y` is a pointer into `x`, so when `z` tries to move out
+of `x`, we get an error.  There is no way that liveness could compute
+this information without redoing the efforts of the borrow checker.
+
+### Closures
+
+Liveness is somewhat complicated by having to deal with stack
+closures.  More information to come!
+
+## Distributive property
+
+Copies are "distributive" over parenthesization, but blocks are
+considered rvalues.  What this means is that, for example, neither
+`a.clone()` nor `(a).clone()` will move `a` (presuming that `a` has a
+linear type and `clone()` takes its self by reference), but
+`{a}.clone()` will move `a`, as would `(if cond {a} else {b}).clone()`
+and so on.
+
+*/
+
+use core::prelude::*;
+
+use middle::pat_util::{pat_bindings};
+use middle::freevars;
+use middle::ty;
+use middle::typeck::{method_map, method_map_entry};
+use middle::typeck::check::{DerefArgs, DoDerefArgs, DontDerefArgs};
+use util::ppaux;
+use util::common::indenter;
+
+use core::vec;
+use std::map::HashMap;
+use syntax::ast::*;
+use syntax::ast_util;
+use syntax::visit;
+use syntax::visit::{fn_kind, fk_item_fn, fk_method, fk_dtor,
+                    fk_anon, fk_fn_block, vt};
+use syntax::print::pprust;
+use syntax::codemap::span;
+
+#[auto_encode]
+#[auto_decode]
+pub enum CaptureMode {
+    CapCopy, // Copy the value into the closure.
+    CapMove, // Move the value into the closure.
+    CapRef,  // Reference directly from parent stack frame (used by `&fn()`).
+}
+
+#[auto_encode]
+#[auto_decode]
+pub struct CaptureVar {
+    def: def,         // Variable being accessed free
+    span: span,       // Location of an access to this variable
+    mode: CaptureMode // How variable is being accessed
+}
+
+pub type CaptureMap = HashMap<node_id, @[CaptureVar]>;
+
+pub type MovesMap = HashMap<node_id, ()>;
+
+/**
+ * For each variable which will be moved, links to the
+ * expression */
+pub type VariableMovesMap = HashMap<node_id, @expr>;
+
+/** See the section Output on the module comment for explanation. */
+pub struct MoveMaps {
+    moves_map: MovesMap,
+    variable_moves_map: VariableMovesMap,
+    capture_map: CaptureMap
+}
+
+struct VisitContext {
+    tcx: ty::ctxt,
+    method_map: HashMap<node_id,method_map_entry>,
+    move_maps: MoveMaps
+}
+
+enum UseMode {
+    MoveInWhole,         // Move the entire value.
+    MoveInPart(@expr),   // Some subcomponent will be moved
+    Read                 // Read no matter what the type.
+}
+
+pub fn compute_moves(tcx: ty::ctxt,
+                     method_map: method_map,
+                     crate: @crate) -> MoveMaps
+{
+    let visitor = visit::mk_vt(@visit::Visitor {
+        visit_expr: compute_modes_for_expr,
+        .. *visit::default_visitor()
+    });
+    let visit_cx = VisitContext {
+        tcx: tcx,
+        method_map: method_map,
+        move_maps: MoveMaps {
+            moves_map: HashMap(),
+            variable_moves_map: HashMap(),
+            capture_map: HashMap()
+        }
+    };
+    visit::visit_crate(*crate, visit_cx, visitor);
+    return visit_cx.move_maps;
+}
+
+// ______________________________________________________________________
+// Expressions
+
+fn compute_modes_for_expr(expr: @expr,
+                          &&cx: VisitContext,
+                          v: vt<VisitContext>)
+{
+    cx.consume_expr(expr, v);
+}
+
+impl UseMode {
+    fn component_mode(&self, expr: @expr) -> UseMode {
+        /*!
+         *
+         * Assuming that `self` is the mode for an expression E,
+         * returns the appropriate mode to use for a subexpression of E.
+         */
+
+        match *self {
+            Read | MoveInPart(_) => *self,
+            MoveInWhole => MoveInPart(expr)
+        }
+    }
+}
+
+impl VisitContext {
+    fn consume_exprs(&self,
+                     exprs: &[@expr],
+                     visitor: vt<VisitContext>)
+    {
+        for exprs.each |expr| {
+            self.consume_expr(*expr, visitor);
+        }
+    }
+
+    fn consume_expr(&self,
+                    expr: @expr,
+                    visitor: vt<VisitContext>)
+    {
+        /*!
+         *
+         * Indicates that the value of `expr` will be consumed,
+         * meaning either copied or moved depending on its type.
+         */
+
+        debug!("consume_expr(expr=%?/%s)",
+               expr.id,
+               pprust::expr_to_str(expr, self.tcx.sess.intr()));
+
+        let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
+        let mode = self.consume_mode_for_ty(expr_ty);
+        self.use_expr(expr, mode, visitor);
+    }
+
+    fn consume_block(&self,
+                     blk: &blk,
+                     visitor: vt<VisitContext>)
+    {
+        /*!
+         *
+         * Indicates that the value of `blk` will be consumed,
+         * meaning either copied or moved depending on its type.
+         */
+
+        debug!("consume_block(blk.id=%?)", blk.node.id);
+
+        for blk.node.stmts.each |stmt| {
+            (visitor.visit_stmt)(*stmt, *self, visitor);
+        }
+
+        for blk.node.expr.each |tail_expr| {
+            self.consume_expr(*tail_expr, visitor);
+        }
+    }
+
+    fn consume_mode_for_ty(&self, ty: ty::t) -> UseMode {
+        /*!
+         *
+         * Selects the appropriate `UseMode` to consume a value with
+         * the type `ty`.  This will be `MoveEntireMode` if `ty` is
+         * not implicitly copyable.
+         */
+
+        let result = if ty::type_implicitly_moves(self.tcx, ty) {
+            MoveInWhole
+        } else {
+            Read
+        };
+
+        debug!("consume_mode_for_ty(ty=%s) = %?",
+               ppaux::ty_to_str(self.tcx, ty), result);
+
+        return result;
+    }
+
+    fn use_expr(&self,
+                expr: @expr,
+                expr_mode: UseMode,
+                visitor: vt<VisitContext>)
+    {
+        /*!
+         *
+         * Indicates that `expr` is used with a given mode.  This will
+         * in turn trigger calls to the subcomponents of `expr`.
+         */
+
+        debug!("use_expr(expr=%?/%s, mode=%?)",
+               expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr()),
+               expr_mode);
+
+        match expr_mode {
+            MoveInWhole => { self.move_maps.moves_map.insert(expr.id, ()); }
+            MoveInPart(_) | Read => {}
+        }
+
+        // `expr_mode` refers to the post-adjustment value.  If one of
+        // those adjustments is to take a reference, then it's only
+        // reading the underlying expression, not moving it.
+        let comp_mode = match self.tcx.adjustments.find(expr.id) {
+            Some(adj) if adj.autoref.is_some() => Read,
+            _ => expr_mode.component_mode(expr)
+        };
+
+        debug!("comp_mode = %?", comp_mode);
+
+        match expr.node {
+            expr_path(*) => {
+                match comp_mode {
+                    MoveInPart(entire_expr) => {
+                        self.move_maps.variable_moves_map.insert(
+                            expr.id, entire_expr);
+                    }
+                    Read => {}
+                    MoveInWhole => {
+                        self.tcx.sess.span_bug(
+                            expr.span,
+                            fmt!("Component mode can never be MoveInWhole"));
+                    }
+                }
+            }
+
+            expr_unary(deref, base) => {       // *base
+                if !self.use_overloaded_operator(
+                    expr, DontDerefArgs, base, [], visitor)
+                {
+                    // Moving out of *base moves out of base.
+                    self.use_expr(base, comp_mode, visitor);
+                }
+            }
+
+            expr_field(base, _, _) => {        // base.f
+                // Moving out of base.f moves out of base.
+                self.use_expr(base, comp_mode, visitor);
+            }
+
+            expr_index(lhs, rhs) => {          // lhs[rhs]
+                if !self.use_overloaded_operator(
+                    expr, DontDerefArgs, lhs, [rhs], visitor)
+                {
+                    self.use_expr(lhs, comp_mode, visitor);
+                    self.consume_expr(rhs, visitor);
+                }
+            }
+
+            expr_call(callee, ref args, _) => {    // callee(args)
+                self.use_expr(callee, Read, visitor);
+                self.use_fn_args(callee.id, *args, visitor);
+            }
+
+            expr_method_call(callee, _, _, ref args, _) => { // callee.m(args)
+                // Implicit self is equivalent to & mode, but every
+                // other kind should be + mode.
+                self.use_receiver(expr.id, expr.span, callee, visitor);
+                self.use_fn_args(expr.callee_id, *args, visitor);
+            }
+
+            expr_rec(ref fields, opt_with) |
+            expr_struct(_, ref fields, opt_with) => {
+                for fields.each |field| {
+                    self.consume_expr(field.node.expr, visitor);
+                }
+
+                for opt_with.each |with_expr| {
+                    self.consume_expr(*with_expr, visitor);
+                }
+            }
+
+            expr_tup(ref exprs) => {
+                self.consume_exprs(*exprs, visitor);
+            }
+
+            expr_if(cond_expr, ref then_blk, opt_else_expr) => {
+                self.consume_expr(cond_expr, visitor);
+                self.consume_block(then_blk, visitor);
+                for opt_else_expr.each |else_expr| {
+                    self.consume_expr(*else_expr, visitor);
+                }
+            }
+
+            expr_match(discr, ref arms) => {
+                // We must do this first so that `arms_have_by_move_bindings`
+                // below knows which bindings are moves.
+                for arms.each |arm| {
+                    self.consume_arm(arm, visitor);
+                }
+
+                let by_move_bindings_present =
+                    self.arms_have_by_move_bindings(
+                        self.move_maps.moves_map, *arms);
+
+                if by_move_bindings_present {
+                    // If one of the arms moves a value out of the
+                    // discriminant, then the discriminant itself is
+                    // moved.
+                    self.consume_expr(discr, visitor);
+                } else {
+                    // Otherwise, the discriminant is merely read.
+                    self.use_expr(discr, Read, visitor);
+                }
+            }
+
+            expr_copy(base) => {
+                self.use_expr(base, Read, visitor);
+            }
+
+            expr_paren(base) => {
+                // Note: base is not considered a *component* here, so
+                // use `expr_mode` not `comp_mode`.
+                self.use_expr(base, expr_mode, visitor);
+            }
+
+            expr_vec(ref exprs, _) => {
+                self.consume_exprs(*exprs, visitor);
+            }
+
+            expr_addr_of(_, base) => {   // &base
+                self.use_expr(base, Read, visitor);
+            }
+
+            expr_break(*) |
+            expr_again(*) |
+            expr_lit(*) => {}
+
+            expr_loop(ref blk, _) => {
+                self.consume_block(blk, visitor);
+            }
+
+            expr_log(_, a_expr, b_expr) => {
+                self.consume_expr(a_expr, visitor);
+                self.use_expr(b_expr, Read, visitor);
+            }
+
+            expr_assert(cond_expr) => {
+                self.consume_expr(cond_expr, visitor);
+            }
+
+            expr_while(cond_expr, ref blk) => {
+                self.consume_expr(cond_expr, visitor);
+                self.consume_block(blk, visitor);
+            }
+
+            expr_unary(_, lhs) => {
+                if !self.use_overloaded_operator(
+                    expr, DontDerefArgs, lhs, [], visitor)
+                {
+                    self.consume_expr(lhs, visitor);
+                }
+            }
+
+            expr_binary(_, lhs, rhs) => {
+                if !self.use_overloaded_operator(
+                    expr, DoDerefArgs, lhs, [rhs], visitor)
+                {
+                    self.consume_expr(lhs, visitor);
+                    self.consume_expr(rhs, visitor);
+                }
+            }
+
+            expr_block(ref blk) => {
+                self.consume_block(blk, visitor);
+            }
+
+            expr_fail(ref opt_expr) |
+            expr_ret(ref opt_expr) => {
+                for opt_expr.each |expr| {
+                    self.consume_expr(*expr, visitor);
+                }
+            }
+
+            expr_assign(lhs, rhs) => {
+                self.use_expr(lhs, Read, visitor);
+                self.consume_expr(rhs, visitor);
+            }
+
+            expr_cast(base, _) => {
+                self.consume_expr(base, visitor);
+            }
+
+            expr_assign_op(_, lhs, rhs) => {
+                // FIXME(#4712) --- Overloaded operators?
+                //
+                // if !self.use_overloaded_operator(
+                //     expr, DoDerefArgs, lhs, [rhs], visitor)
+                // {
+                self.consume_expr(lhs, visitor);
+                self.consume_expr(rhs, visitor);
+                // }
+            }
+
+            expr_repeat(base, count, _) => {
+                self.consume_expr(base, visitor);
+                self.consume_expr(count, visitor);
+            }
+
+            expr_swap(lhs, rhs) => {
+                self.use_expr(lhs, Read, visitor);
+                self.use_expr(rhs, Read, visitor);
+            }
+
+            expr_loop_body(base) |
+            expr_do_body(base) => {
+                self.use_expr(base, comp_mode, visitor);
+            }
+
+            expr_fn(_, _, ref body) |
+            expr_fn_block(_, ref body) => {
+                let cap_vars = self.compute_captures(expr.id);
+                self.move_maps.capture_map.insert(expr.id, cap_vars);
+                self.consume_block(body, visitor);
+            }
+
+            expr_vstore(base, _) => {
+                self.use_expr(base, comp_mode, visitor);
+            }
+
+            expr_mac(*) => {
+                self.tcx.sess.span_bug(
+                    expr.span,
+                    ~"macro expression remains after expansion");
+            }
+        }
+    }
+
+    fn use_overloaded_operator(&self,
+                               expr: @expr,
+                               deref_args: DerefArgs,
+                               receiver_expr: @expr,
+                               arg_exprs: &[@expr],
+                               visitor: vt<VisitContext>) -> bool
+    {
+        if !self.method_map.contains_key(expr.id) {
+            return false;
+        }
+
+        self.use_receiver(expr.id, expr.span, receiver_expr, visitor);
+
+        // The deref_args stuff should eventually be converted into
+        // adjustments.  Moreover, it should eventually be applied
+        // consistently to all overloaded operators.  But that's not
+        // how it is today.
+        match deref_args {
+            DoDerefArgs => {
+                // we are always passing in a borrowed pointer,
+                // so it's always read mode:
+                for arg_exprs.each |arg_expr| {
+                    self.use_expr(*arg_expr, Read, visitor);
+                }
+            }
+            DontDerefArgs => {
+                self.use_fn_args(expr.callee_id, arg_exprs, visitor);
+            }
+        }
+
+        return true;
+    }
+
+    fn consume_arm(&self,
+                   arm: &arm,
+                   visitor: vt<VisitContext>)
+    {
+        for arm.pats.each |pat| {
+            self.use_pat(*pat);
+        }
+
+        for arm.guard.each |guard| {
+            self.consume_expr(*guard, visitor);
+        }
+
+        self.consume_block(&arm.body, visitor);
+    }
+
+    fn use_pat(&self,
+               pat: @pat)
+    {
+        /*!
+         *
+         * Decides whether each binding in a pattern moves the value
+         * into itself or not based on its type and annotation.
+         */
+
+        do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, _path| {
+            let mode = match bm {
+                bind_by_copy => Read,
+                bind_by_ref(_) => Read,
+                bind_infer => {
+                    let pat_ty = ty::node_id_to_type(self.tcx, id);
+                    self.consume_mode_for_ty(pat_ty)
+                }
+            };
+
+            match mode {
+                MoveInWhole => { self.move_maps.moves_map.insert(id, ()); }
+                MoveInPart(_) | Read => {}
+            }
+        }
+    }
+
+    fn use_receiver(&self,
+                    expr_id: node_id,
+                    span: span,
+                    receiver_expr: @expr,
+                    visitor: vt<VisitContext>)
+    {
+        let callee_mode = match self.method_map.find(expr_id) {
+            Some(ref method_map_entry) => {
+                match method_map_entry.explicit_self {
+                    sty_by_ref => by_ref,
+                    _ => by_copy
+                }
+            }
+            None => {
+                self.tcx.sess.span_bug(
+                    span,
+                    ~"no method map entry");
+            }
+        };
+        self.use_fn_arg(callee_mode, receiver_expr, visitor);
+    }
+
+    fn use_fn_args(&self,
+                   callee_id: node_id,
+                   arg_exprs: &[@expr],
+                   visitor: vt<VisitContext>)
+    {
+        /*!
+         *
+         * Uses the argument expressions according to the function modes.
+         */
+
+        let arg_tys =
+            ty::ty_fn_args(ty::node_id_to_type(self.tcx, callee_id));
+        for vec::each2(arg_exprs, arg_tys) |arg_expr, arg_ty| {
+            let arg_mode = ty::resolved_mode(self.tcx, arg_ty.mode);
+            self.use_fn_arg(arg_mode, *arg_expr, visitor);
+        }
+    }
+
+    fn use_fn_arg(&self,
+                  arg_mode: rmode,
+                  arg_expr: @expr,
+                  visitor: vt<VisitContext>)
+    {
+        /*!
+         *
+         * Uses the argument according to the given argument mode.
+         */
+
+        match arg_mode {
+            by_val | by_ref => self.use_expr(arg_expr, Read, visitor),
+            by_copy => self.consume_expr(arg_expr, visitor)
+        }
+    }
+
+    fn arms_have_by_move_bindings(&self,
+                                  moves_map: MovesMap,
+                                  +arms: &[arm]) -> bool
+    {
+        for arms.each |arm| {
+            for arm.pats.each |pat| {
+                let mut found = false;
+                do pat_bindings(self.tcx.def_map, *pat) |_, node_id, _, _| {
+                    if moves_map.contains_key(node_id) {
+                        found = true;
+                    }
+                }
+                if found { return true; }
+            }
+        }
+        return false;
+    }
+
+    fn compute_captures(&self, fn_expr_id: node_id) -> @[CaptureVar] {
+        debug!("compute_capture_vars(fn_expr_id=%?)", fn_expr_id);
+        let _indenter = indenter();
+
+        let fn_ty = ty::node_id_to_type(self.tcx, fn_expr_id);
+        let proto = ty::ty_fn_proto(fn_ty);
+        let freevars = freevars::get_freevars(self.tcx, fn_expr_id);
+        if proto == ProtoBorrowed {
+            // &fn() captures everything by ref
+            at_vec::from_fn(freevars.len(), |i| {
+                let fvar = &freevars[i];
+                CaptureVar {def: fvar.def, span: fvar.span, mode: CapRef}
+            })
+        } else {
+            // @fn() and ~fn() capture by copy or by move depending on type
+            at_vec::from_fn(freevars.len(), |i| {
+                let fvar = &freevars[i];
+                let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;
+                let fvar_ty = ty::node_id_to_type(self.tcx, fvar_def_id);
+                debug!("fvar_def_id=%? fvar_ty=%s",
+                       fvar_def_id, ppaux::ty_to_str(self.tcx, fvar_ty));
+                let mode = if ty::type_implicitly_moves(self.tcx, fvar_ty) {
+                    CapMove
+                } else {
+                    CapCopy
+                };
+                CaptureVar {def: fvar.def, span: fvar.span, mode:mode}
+            })
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 056ab96008a..205be5f891b 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -11,7 +11,6 @@
 use core::prelude::*;
 
 use middle::resolve;
-use middle::ty::{CopyValue, MoveValue, ReadValue};
 use middle::ty;
 
 use syntax::ast::*;
@@ -94,30 +93,3 @@ pub fn pat_binding_ids(dm: resolve::DefMap, pat: @pat) -> ~[node_id] {
     return found;
 }
 
-pub fn arms_have_by_move_bindings(tcx: ty::ctxt, +arms: &[arm]) -> bool {
-    for arms.each |arm| {
-        for arm.pats.each |pat| {
-            let mut found = false;
-            do pat_bindings(tcx.def_map, *pat)
-                    |binding_mode, node_id, span, _path| {
-                match binding_mode {
-                    bind_by_move => found = true,
-                    bind_infer => {
-                        match tcx.value_modes.find(node_id) {
-                            Some(MoveValue) => found = true,
-                            Some(CopyValue) | Some(ReadValue) => {}
-                            None => {
-                                tcx.sess.span_bug(span, ~"pat binding not in \
-                                                          value mode map");
-                            }
-                        }
-                    }
-                    bind_by_ref(*) | bind_by_value => {}
-                }
-            }
-            if found { return true; }
-        }
-    }
-    return false;
-}
-
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 698da4e6661..31ac2f0f676 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -290,15 +290,6 @@ pub fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
                                                            cx.sess.intr()));
         new_cx.parent = Some(expr.id);
       }
-      ast::expr_fn(_, _, _, cap_clause) |
-      ast::expr_fn_block(_, _, cap_clause) => {
-        // although the capture items are not expressions per se, they
-        // do get "evaluated" in some sense as copies or moves of the
-        // relevant variables so we parent them like an expression
-        for (*cap_clause).each |cap_item| {
-            record_parent(new_cx, cap_item.id);
-        }
-      }
       ast::expr_while(cond, _) => {
         new_cx.root_exprs.insert(cond.id, ());
       }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index a17db8652ce..5314005a956 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -24,8 +24,8 @@ use core::cmp;
 use core::str;
 use core::vec;
 use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm};
-use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk, capture_clause};
-use syntax::ast::{bind_by_value, bind_infer, bind_by_ref, bind_by_move};
+use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk};
+use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy};
 use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding};
 use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label};
 use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self};
@@ -175,11 +175,6 @@ pub enum SelfBinding {
     HasSelfBinding(node_id, bool /* is implicit */)
 }
 
-pub enum CaptureClause {
-    NoCaptureClause,
-    HasCaptureClause(capture_clause)
-}
-
 pub type ResolveVisitor = vt<()>;
 
 #[deriving_eq]
@@ -3727,7 +3722,6 @@ pub impl Resolver {
                                          OpaqueFunctionRibKind),
                                       (*block),
                                       NoSelfBinding,
-                                      NoCaptureClause,
                                       visitor);
             }
 
@@ -3803,33 +3797,7 @@ pub impl Resolver {
                         type_parameters: TypeParameters,
                         block: blk,
                         self_binding: SelfBinding,
-                        capture_clause: CaptureClause,
                         visitor: ResolveVisitor) {
-        // Check each element of the capture clause.
-        match capture_clause {
-            NoCaptureClause => {
-                // Nothing to do.
-            }
-            HasCaptureClause(capture_clause) => {
-                // Resolve each captured item.
-                for (*capture_clause).each |capture_item| {
-                    match self.resolve_identifier(capture_item.name,
-                                                  ValueNS,
-                                                  true,
-                                                  capture_item.span) {
-                        None => {
-                            self.session.span_err(capture_item.span,
-                                                  ~"unresolved name in \
-                                                   capture clause");
-                        }
-                        Some(def) => {
-                            self.record_def(capture_item.id, def);
-                        }
-                    }
-                }
-            }
-        }
-
         // Create a value rib for the function.
         let function_value_rib = @Rib(rib_kind);
         (*self.value_ribs).push(function_value_rib);
@@ -3945,7 +3913,6 @@ pub impl Resolver {
                                           HasSelfBinding
                                             ((*destructor).node.self_id,
                                              true),
-                                          NoCaptureClause,
                                           visitor);
                 }
             }
@@ -3976,7 +3943,6 @@ pub impl Resolver {
                               type_parameters,
                               method.body,
                               self_binding,
-                              NoCaptureClause,
                               visitor);
     }
 
@@ -4047,7 +4013,6 @@ pub impl Resolver {
                                              NormalRibKind),
                                           method.body,
                                           HasSelfBinding(method.self_id),
-                                          NoCaptureClause,
                                           visitor);
 */
             }
@@ -4855,14 +4820,13 @@ pub impl Resolver {
                 visit_expr(expr, (), visitor);
             }
 
-            expr_fn(_, ref fn_decl, ref block, capture_clause) |
-            expr_fn_block(ref fn_decl, ref block, capture_clause) => {
+            expr_fn(_, ref fn_decl, ref block) |
+            expr_fn_block(ref fn_decl, ref block) => {
                 self.resolve_function(FunctionRibKind(expr.id, block.node.id),
                                       Some(@/*bad*/copy *fn_decl),
                                       NoTypeParameters,
                                       (*block),
                                       NoSelfBinding,
-                                      HasCaptureClause(capture_clause),
                                       visitor);
             }
 
@@ -5139,18 +5103,12 @@ pub impl Resolver {
                                     descr: &str) {
         match pat_binding_mode {
             bind_infer => {}
-            bind_by_value => {
+            bind_by_copy => {
                 self.session.span_err(
                     pat.span,
                     fmt!("cannot use `copy` binding mode with %s",
                          descr));
             }
-            bind_by_move => {
-                self.session.span_err(
-                    pat.span,
-                    fmt!("cannot use `move` binding mode with %s",
-                         descr));
-            }
             bind_by_ref(*) => {
                 self.session.span_err(
                     pat.span,
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 86dad3b7c1b..2c36d0d088a 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -160,7 +160,6 @@ use middle::trans::datum::*;
 use middle::trans::expr::Dest;
 use middle::trans::expr;
 use middle::trans::glue;
-use middle::ty::{CopyValue, MoveValue, ReadValue};
 use util::common::indenter;
 
 use core::dvec::DVec;
@@ -935,7 +934,7 @@ pub fn root_pats_as_necessary(bcx: block,
                 // for details (look for the case covering cat_discr).
 
                 let datum = Datum {val: val, ty: node_id_type(bcx, pat_id),
-                                   mode: ByRef, source: FromLvalue};
+                                   mode: ByRef, source: ZeroMem};
                 bcx = datum.root(bcx, root_info);
                 // If we kept going, we'd only re-root the same value, so
                 // return now.
@@ -1091,7 +1090,7 @@ pub fn store_non_ref_bindings(bcx: block,
             TrByValue(is_move, lldest) => {
                 let llval = Load(bcx, binding_info.llmatch); // get a T*
                 let datum = Datum {val: llval, ty: binding_info.ty,
-                                   mode: ByRef, source: FromLvalue};
+                                   mode: ByRef, source: ZeroMem};
                 bcx = {
                     if is_move {
                         datum.move_to(bcx, INIT, lldest)
@@ -1575,30 +1574,19 @@ pub fn trans_match_inner(scope_cx: block,
         // Note that we use the names because each binding will have many ids
         // from the various alternatives.
         let bindings_map = HashMap();
-        do pat_bindings(tcx.def_map, arm.pats[0]) |bm, p_id, s, path| {
+        do pat_bindings(tcx.def_map, arm.pats[0]) |bm, p_id, _s, path| {
             let ident = path_to_ident(path);
             let variable_ty = node_id_type(bcx, p_id);
             let llvariable_ty = type_of::type_of(bcx.ccx(), variable_ty);
 
             let llmatch, trmode;
             match bm {
-                ast::bind_by_value | ast::bind_by_move => {
-                    // in this case, the type of the variable will be T,
-                    // but we need to store a *T
-                    let is_move = (bm == ast::bind_by_move);
-                    llmatch = alloca(bcx, T_ptr(llvariable_ty));
-                    trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
-                }
-                ast::bind_infer => {
-                    // in this case also, the type of the variable will be T,
-                    // but we need to store a *T
-                    let is_move = match tcx.value_modes.find(p_id) {
-                        None => {
-                            tcx.sess.span_bug(s, ~"no value mode");
-                        }
-                        Some(MoveValue) => true,
-                        Some(CopyValue) | Some(ReadValue) => false
-                    };
+                ast::bind_by_copy | ast::bind_infer => {
+                    // 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 =
+                        scope_cx.ccx().maps.moves_map.contains_key(p_id);
                     llmatch = alloca(bcx, T_ptr(llvariable_ty));
                     trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
                 }
@@ -1657,7 +1645,8 @@ pub fn trans_match_inner(scope_cx: block,
         arm_cxs.push(bcx);
     }
 
-    return controlflow::join_blocks(scope_cx, dvec::unwrap(move arm_cxs));
+    bcx = controlflow::join_blocks(scope_cx, dvec::unwrap(move arm_cxs));
+    return bcx;
 
     fn mk_fail(bcx: block, sp: span, +msg: ~str,
                finished: @mut Option<BasicBlockRef>) -> BasicBlockRef {
@@ -1697,7 +1686,7 @@ pub fn bind_irrefutable_pat(bcx: block,
             if make_copy {
                 let binding_ty = node_id_type(bcx, pat.id);
                 let datum = Datum {val: val, ty: binding_ty,
-                                   mode: ByRef, source: FromRvalue};
+                                   mode: ByRef, source: RevokeClean};
                 let scratch = scratch_datum(bcx, binding_ty, false);
                 datum.copy_to_datum(bcx, INIT, scratch);
                 match binding_mode {
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 864ffd5e820..e7d21cbbe53 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1676,7 +1676,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
             ast::by_ref => {
                 llarg = raw_llarg;
             }
-            ast::by_move | ast::by_copy => {
+            ast::by_copy => {
                 // only by value if immediate:
                 if datum::appropriate_mode(arg_ty.ty).is_by_value() {
                     let alloc = alloc_ty(bcx, arg_ty.ty);
@@ -2198,16 +2198,8 @@ pub fn create_main_wrapper(ccx: @crate_ctxt, _sp: span, main_llfn: ValueRef) {
     create_entry_fn(ccx, llfn);
 
     fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef) -> ValueRef {
-        let unit_ty = ty::mk_estr(ccx.tcx, ty::vstore_uniq);
-        let vecarg_ty: ty::arg =
-            arg {
-                mode: ast::expl(ast::by_val),
-                ty: ty::mk_evec(ccx.tcx,
-                    ty::mt {ty: unit_ty, mutbl: ast::m_imm},
-                    ty::vstore_uniq)
-            };
         let nt = ty::mk_nil(ccx.tcx);
-        let llfty = type_of_fn(ccx, ~[vecarg_ty], nt);
+        let llfty = type_of_fn(ccx, ~[], nt);
         let llfdecl = decl_fn(ccx.llmod, ~"_rust_main",
                               lib::llvm::CCallConv, llfty);
 
@@ -2953,7 +2945,7 @@ pub fn trans_crate(sess: session::Session,
                    tcx: ty::ctxt,
                    output: &Path,
                    emap2: resolve::ExportMap2,
-                   maps: astencode::maps) -> (ModuleRef, link_meta) {
+                   maps: astencode::Maps) -> (ModuleRef, link_meta) {
 
     let symbol_hasher = @hash::default_state();
     let link_meta =
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index 584e5d9f184..850da79290c 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -79,7 +79,7 @@ pub fn count_insn(cx: block, category: &str) {
         s += ~"/";
         s += category;
 
-        let n = match h.find(s) {
+        let n = match h.find(/*bad*/ copy s) {
           Some(n) => n,
           _ => 0u
         };
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index af45dd7064e..91eabaf6ab8 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -334,7 +334,7 @@ pub fn trans_method_call(in_cx: block,
 
 pub fn trans_rtcall_or_lang_call(bcx: block,
                                  did: ast::def_id,
-                                 args: ~[ValueRef],
+                                 args: &[ValueRef],
                                  dest: expr::Dest)
                               -> block {
     let fty = if did.crate == ast::local_crate {
@@ -351,7 +351,7 @@ pub fn trans_rtcall_or_lang_call(bcx: block,
 
 pub fn trans_rtcall_or_lang_call_with_type_params(bcx: block,
                                                   did: ast::def_id,
-                                                  args: ~[ValueRef],
+                                                  args: &[ValueRef],
                                                   type_params: ~[ty::t],
                                                   dest: expr::Dest)
                                                -> block {
@@ -418,11 +418,11 @@ pub fn trans_call_inner(
     dest: expr::Dest,
     autoref_arg: AutorefArg) -> block {
     do base::with_scope(in_cx, call_info, ~"call") |cx| {
-        let ret_in_loop = match /*bad*/copy args {
+        let ret_in_loop = match args {
           ArgExprs(args) => {
             args.len() > 0u && match vec::last(args).node {
               ast::expr_loop_body(@ast::expr {
-                node: ast::expr_fn_block(_, ref body, _),
+                node: ast::expr_fn_block(_, ref body),
                 _
               }) =>  body_contains_ret((*body)),
               _ => false
@@ -464,7 +464,7 @@ pub fn trans_call_inner(
             }
         };
 
-        let args_res = trans_args(bcx, llenv, /*bad*/copy args, fn_expr_ty,
+        let args_res = trans_args(bcx, llenv, args, fn_expr_ty,
                                   dest, ret_flag, autoref_arg);
         bcx = args_res.bcx;
         let mut llargs = /*bad*/copy args_res.args;
@@ -520,9 +520,10 @@ pub fn trans_call_inner(
     }
 }
 
+
 pub enum CallArgs {
-    ArgExprs(~[@ast::expr]),
-    ArgVals(~[ValueRef])
+    ArgExprs(&[@ast::expr]),
+    ArgVals(&[ValueRef])
 }
 
 pub fn trans_args(cx: block,
@@ -625,7 +626,7 @@ pub fn trans_arg_expr(bcx: block,
                 ast::expr_loop_body(
                     // XXX: Bad copy.
                     blk@@ast::expr {
-                        node: ast::expr_fn_block(copy decl, ref body, cap),
+                        node: ast::expr_fn_block(copy decl, ref body),
                         _
                     }) =>
                 {
@@ -635,12 +636,12 @@ pub fn trans_arg_expr(bcx: block,
                     let proto = ty::ty_fn_proto(arg_ty);
                     let bcx = closure::trans_expr_fn(
                         bcx, proto, decl, /*bad*/copy *body, arg_expr.id,
-                        blk.id, cap, Some(ret_flag), expr::SaveIn(scratch));
+                        blk.id, Some(ret_flag), expr::SaveIn(scratch));
                     DatumBlock {bcx: bcx,
                                 datum: Datum {val: scratch,
                                               ty: scratch_ty,
                                               mode: ByRef,
-                                              source: FromRvalue}}
+                                              source: RevokeClean}}
                 }
                 _ => {
                     bcx.sess().impossible_case(
@@ -670,34 +671,35 @@ pub fn trans_arg_expr(bcx: block,
     } else {
         // FIXME(#3548) use the adjustments table
         match autoref_arg {
-            DoAutorefArg => { val = arg_datum.to_ref_llval(bcx); }
+            DoAutorefArg => {
+                assert !bcx.ccx().maps.moves_map.contains_key(arg_expr.id);
+                val = arg_datum.to_ref_llval(bcx);
+            }
             DontAutorefArg => {
                 match arg_mode {
                     ast::by_ref => {
+                        // This assertion should really be valid, but because
+                        // the explicit self code currently passes by-ref, it
+                        // does not hold.
+                        //
+                        //assert !bcx.ccx().maps.moves_map.contains_key(
+                        //    arg_expr.id);
                         val = arg_datum.to_ref_llval(bcx);
                     }
 
                     ast::by_val => {
                         // NB: avoid running the take glue.
+
+                        assert !bcx.ccx().maps.moves_map.contains_key(
+                            arg_expr.id);
                         val = arg_datum.to_value_llval(bcx);
                     }
 
-                    ast::by_copy | ast::by_move => {
+                    ast::by_copy => {
                         let scratch = scratch_datum(bcx, arg_datum.ty, false);
 
-                        if arg_mode == ast::by_move {
-                            // NDM---Doesn't seem like this should be
-                            // necessary
-                            if !arg_datum.store_will_move() {
-                                bcx.sess().span_bug(
-                                    arg_expr.span,
-                                    fmt!("move mode but datum will not \
-                                          store: %s",
-                                          arg_datum.to_str(bcx.ccx())));
-                            }
-                        }
-
-                        arg_datum.store_to_datum(bcx, INIT, scratch);
+                        arg_datum.store_to_datum(bcx, arg_expr.id,
+                                                 INIT, scratch);
 
                         // Technically, ownership of val passes to the callee.
                         // However, we must cleanup should we fail before the
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index f6a6c5af5ff..52bb8f56218 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -15,12 +15,12 @@ use back::link::{mangle_internal_name_by_path_and_seq};
 use back::link::{mangle_internal_name_by_path};
 use lib::llvm::llvm;
 use lib::llvm::{ValueRef, TypeRef};
-use middle::capture;
+use middle::moves;
 use middle::trans::base::*;
 use middle::trans::build::*;
 use middle::trans::callee;
 use middle::trans::common::*;
-use middle::trans::datum::{Datum, INIT, ByRef, ByValue, FromLvalue};
+use middle::trans::datum::{Datum, INIT, ByRef, ByValue, ZeroMem};
 use middle::trans::expr;
 use middle::trans::glue;
 use middle::trans::machine;
@@ -106,7 +106,7 @@ use syntax::print::pprust::expr_to_str;
 
 pub enum EnvAction {
     /// Copy the value from this llvm ValueRef into the environment.
-    EnvStore,
+    EnvCopy,
 
     /// Move the value from this llvm ValueRef into the environment.
     EnvMove,
@@ -123,7 +123,7 @@ pub struct EnvValue {
 pub impl EnvAction {
     fn to_str() -> ~str {
         match self {
-            EnvStore => ~"EnvStore",
+            EnvCopy => ~"EnvCopy",
             EnvMove => ~"EnvMove",
             EnvRef => ~"EnvRef"
         }
@@ -151,7 +151,7 @@ pub fn mk_closure_tys(tcx: ty::ctxt,
     // converted to ptrs.
     let bound_tys = bound_values.map(|bv| {
         match bv.action {
-            EnvStore | EnvMove => bv.datum.ty,
+            EnvCopy | EnvMove => bv.datum.ty,
             EnvRef => ty::mk_mut_ptr(tcx, bv.datum.ty)
         }
     });
@@ -242,8 +242,8 @@ pub fn store_environment(bcx: block,
         let bound_data = GEPi(bcx, llbox, [0u, abi::box_field_body, i]);
 
         match bv.action {
-            EnvStore => {
-                bcx = bv.datum.store_to(bcx, INIT, bound_data);
+            EnvCopy => {
+                bcx = bv.datum.copy_to(bcx, INIT, bound_data);
             }
             EnvMove => {
                 bcx = bv.datum.move_to(bcx, INIT, bound_data);
@@ -264,7 +264,7 @@ pub fn store_environment(bcx: block,
 // Given a context and a list of upvars, build a closure. This just
 // collects the upvars and packages them up for store_environment.
 pub fn build_closure(bcx0: block,
-                     cap_vars: ~[capture::capture_var],
+                     cap_vars: &[moves::CaptureVar],
                      proto: ast::Proto,
                      include_ret_handle: Option<ValueRef>) -> closure_result {
     let _icx = bcx0.insn_ctxt("closure::build_closure");
@@ -274,27 +274,23 @@ pub fn build_closure(bcx0: block,
 
     // Package up the captured upvars
     let mut env_vals = ~[];
-    for vec::each(cap_vars) |cap_var| {
+    for cap_vars.each |cap_var| {
         debug!("Building closure: captured variable %?", *cap_var);
-        let datum = expr::trans_local_var(bcx, cap_var.def, None);
+        let datum = expr::trans_local_var(bcx, cap_var.def);
         match cap_var.mode {
-            capture::cap_ref => {
+            moves::CapRef => {
                 assert proto == ast::ProtoBorrowed;
                 env_vals.push(EnvValue {action: EnvRef,
                                         datum: datum});
             }
-            capture::cap_copy => {
-                env_vals.push(EnvValue {action: EnvStore,
+            moves::CapCopy => {
+                env_vals.push(EnvValue {action: EnvCopy,
                                         datum: datum});
             }
-            capture::cap_move => {
+            moves::CapMove => {
                 env_vals.push(EnvValue {action: EnvMove,
                                         datum: datum});
             }
-            capture::cap_drop => {
-                bcx = datum.drop_val(bcx);
-                datum.cancel_clean(bcx);
-            }
         }
     }
 
@@ -303,7 +299,7 @@ pub fn build_closure(bcx0: block,
     do option::iter(&include_ret_handle) |flagptr| {
         // Flag indicating we have returned (a by-ref bool):
         let flag_datum = Datum {val: *flagptr, ty: ty::mk_bool(tcx),
-                                mode: ByRef, source: FromLvalue};
+                                mode: ByRef, source: ZeroMem};
         env_vals.push(EnvValue {action: EnvRef,
                                 datum: flag_datum});
 
@@ -315,7 +311,7 @@ pub fn build_closure(bcx0: block,
         };
         let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil()));
         let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(tcx),
-                               mode: ByRef, source: FromLvalue};
+                               mode: ByRef, source: ZeroMem};
         env_vals.push(EnvValue {action: EnvRef,
                                 datum: ret_datum});
     }
@@ -328,7 +324,7 @@ pub fn build_closure(bcx0: block,
 // with the upvars and type descriptors.
 pub fn load_environment(fcx: fn_ctxt,
                         cdata_ty: ty::t,
-                        cap_vars: ~[capture::capture_var],
+                        cap_vars: &[moves::CaptureVar],
                         load_ret_handle: bool,
                         proto: ast::Proto) {
     let _icx = fcx.insn_ctxt("closure::load_environment");
@@ -354,20 +350,15 @@ pub fn load_environment(fcx: fn_ctxt,
 
     // Populate the upvars from the environment.
     let mut i = 0u;
-    for vec::each(cap_vars) |cap_var| {
-        match cap_var.mode {
-          capture::cap_drop => { /* ignore */ }
-          _ => {
-            let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
-            match proto {
-                ast::ProtoBorrowed => { upvarptr = Load(bcx, upvarptr); }
-                ast::ProtoBox | ast::ProtoUniq | ast::ProtoBare => {}
-            }
-            let def_id = ast_util::def_id_of_def(cap_var.def);
-            fcx.llupvars.insert(def_id.node, upvarptr);
-            i += 1u;
-          }
+    for cap_vars.each |cap_var| {
+        let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
+        match proto {
+            ast::ProtoBorrowed => { upvarptr = Load(bcx, upvarptr); }
+            ast::ProtoBox | ast::ProtoUniq | ast::ProtoBare => {}
         }
+        let def_id = ast_util::def_id_of_def(cap_var.def);
+        fcx.llupvars.insert(def_id.node, upvarptr);
+        i += 1u;
     }
     if load_ret_handle {
         let flagptr = Load(bcx, GEPi(bcx, llcdata, [0u, i]));
@@ -383,9 +374,9 @@ pub fn trans_expr_fn(bcx: block,
                      +body: ast::blk,
                      outer_id: ast::node_id,
                      user_id: ast::node_id,
-                     cap_clause: ast::capture_clause,
                      is_loop_body: Option<Option<ValueRef>>,
-                     dest: expr::Dest) -> block {
+                     dest: expr::Dest) -> block
+{
     /*!
      *
      * Translates the body of a closure expression.
@@ -426,29 +417,24 @@ pub fn trans_expr_fn(bcx: block,
                                                  ~"expr_fn");
     let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
 
-    let trans_closure_env: &fn(ast::Proto) -> Result = |proto| {
-        let cap_vars = capture::compute_capture_vars(ccx.tcx, user_id, proto,
-                                                     cap_clause);
-        let ret_handle = match is_loop_body { Some(x) => x, None => None };
-        // XXX: Bad copy.
-        let {llbox, cdata_ty, bcx} = build_closure(bcx, copy cap_vars, proto,
-                                                   ret_handle);
-        trans_closure(ccx, /*bad*/copy sub_path, decl, /*bad*/copy body,
-                      llfn, no_self, /*bad*/copy bcx.fcx.param_substs,
-                      user_id, None, |fcx| {
-                          load_environment(fcx, cdata_ty, copy cap_vars,
-                                           ret_handle.is_some(), proto);
-                      }, |bcx| {
-                          if is_loop_body.is_some() {
-                              Store(bcx, C_bool(true), bcx.fcx.llretptr);
-                          }
-                      });
-        rslt(bcx, llbox)
-    };
-
     let Result {bcx: bcx, val: closure} = match proto {
         ast::ProtoBorrowed | ast::ProtoBox | ast::ProtoUniq => {
-            trans_closure_env(proto)
+            let cap_vars = ccx.maps.capture_map.get(user_id);
+            let ret_handle = match is_loop_body {Some(x) => x,
+                                                 None => None};
+            let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, proto,
+                                                       ret_handle);
+            trans_closure(ccx, sub_path, decl,
+                          body, llfn, no_self,
+                          /*bad*/ copy bcx.fcx.param_substs, user_id, None,
+                          |fcx| load_environment(fcx, cdata_ty, cap_vars,
+                                                 ret_handle.is_some(), proto),
+                          |bcx| {
+                              if is_loop_body.is_some() {
+                                  Store(bcx, C_bool(true), bcx.fcx.llretptr);
+                              }
+                          });
+            rslt(bcx, llbox)
         }
         ast::ProtoBare => {
             trans_closure(ccx, sub_path, decl, body, llfn, no_self, None,
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 7ab90dd1ef7..6a2618412b9 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -205,7 +205,7 @@ pub struct crate_ctxt {
      type_short_names: HashMap<ty::t, ~str>,
      all_llvm_symbols: Set<~str>,
      tcx: ty::ctxt,
-     maps: astencode::maps,
+     maps: astencode::Maps,
      stats: stats,
      upcalls: @upcall::upcalls,
      tydesc_type: TypeRef,
@@ -1134,7 +1134,7 @@ pub fn C_u8(i: uint) -> ValueRef {
 // our boxed-and-length-annotated strings.
 pub fn C_cstr(cx: @crate_ctxt, +s: ~str) -> ValueRef {
     unsafe {
-        match cx.const_cstr_cache.find(s) {
+        match cx.const_cstr_cache.find(/*bad*/copy s) {
           Some(llval) => return llval,
           None => ()
         }
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index b4dd59cd624..6498b69fbc0 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -41,45 +41,35 @@
  *   convenient for interfacing with the various code floating around
  *   that predates datums.
  *
- * # Datum sources
+ * # Datum cleanup styles
  *
- * Each datum carries with it an idea of its "source".  This indicates
- * the kind of expression from which the datum originated.  The source
- * affects what happens when the datum is stored or moved.
+ * Each datum carries with it an idea of how its value will be cleaned
+ * up.  This is important after a move, because we need to know how to
+ * cancel the cleanup (since the value has been moved and therefore does
+ * not need to be freed).  There are two options:
  *
- * There are three options:
+ * 1. `RevokeClean`: To cancel the cleanup, we invoke `revoke_clean()`.
+ *    This is used for temporary rvalues.
  *
- * 1. `FromRvalue`: This value originates from some temporary rvalue.
- *    This is therefore the owning reference to the datum.  If the
- *    datum is stored, then, it will be *moved* into its new home.
- *    Furthermore, we will not zero out the datum but rather use
- *    `revoke_clean()` to cancel any cleanup.
+ * 2. `ZeroMem`: To cancel the cleanup, we zero out the memory where
+ *    the value resides.  This is used for lvalues.
  *
- * 2. `FromLvalue`: This value originates from an lvalue.  If the datum
- *    is stored, it will be *copied* into its new home.  If the datum
- *    is moved, it will be zeroed out.
+ * # Copying, moving, and storing
  *
- * 3. `FromLastUseLvalue`: The same as FromLvalue, except that it
- *    originates from the *last use* of an lvalue.  If the datum is
- *    stored, then, it will be moved (and zeroed out).
+ * There are three methods for moving the value into a new
+ * location:
  *
- * # Storing, copying, and moving
+ * - `copy_to()` will copy the value into a new location, meaning that
+ *    the value is first mem-copied and then the new location is "taken"
+ *    via the take glue, in effect creating a deep clone.
  *
- * There are three kinds of methods for moving the value into a new
- * location.  *Storing* a datum is probably the one you want to reach
- * for first: it is used when you will no longer use the datum and
- * would like to place it somewhere.  It may translate to a copy or a
- * move, depending on the source of the datum.  After a store, the
- * datum may or may not be usable anymore, so you must assume it is
- * not.
+ * - `move_to()` will copy the value, meaning that the value is mem-copied
+ *   into its new home and then the cleanup on the this datum is revoked.
+ *   This is a "shallow" clone.  After `move_to()`, the current datum
+ *   is invalid and should no longer be used.
  *
- * Sometimes, though, you want to use an explicit copy or move.  A
- * copy copies the data from the datum into a new location and
- * executes the take glue on that location, thus leaving the datum
- * valid for further use.  Moving, in contrast, copies the data into
- * the new location and then cancels any cleanups on the current datum
- * (as appropriate for the source).  No glue code is executed.  After
- * a move, the datum is no longer usable.
+ * - `store_to()` either performs a copy or a move by consulting the
+ *   moves_map computed by `middle::moves`.
  *
  * # Scratch datum
  *
@@ -133,8 +123,8 @@ pub struct Datum {
     /// How did this value originate?  This is particularly important
     /// if the value is MOVED or prematurely DROPPED, because it
     /// describes how to cancel the cleanup that was scheduled before.
-    /// See the def'n of the `DatumSource` type.
-    source: DatumSource
+    /// See the def'n of the `DatumCleanup` type.
+    source: DatumCleanup
 }
 
 pub struct DatumBlock {
@@ -173,32 +163,16 @@ pub impl DatumMode: to_bytes::IterBytes {
     }
 }
 
-/// See `Datum Sources` section at the head of this module.
-pub enum DatumSource {
-    FromRvalue,
-    FromLvalue,
-    FromLastUseLvalue,
-}
-
-pub impl DatumSource {
-    fn is_rvalue() -> bool {
-        match self {
-            FromRvalue => true,
-            FromLvalue | FromLastUseLvalue => false
-        }
-    }
-
-    fn is_any_lvalue() -> bool {
-        match self {
-            FromRvalue => false,
-            FromLvalue | FromLastUseLvalue => true
-        }
-    }
+/// See `Datum cleanup styles` section at the head of this module.
+#[deriving_eq]
+pub enum DatumCleanup {
+    RevokeClean,
+    ZeroMem
 }
 
 pub fn immediate_rvalue(val: ValueRef, ty: ty::t) -> Datum {
     return Datum {val: val, ty: ty,
-                  mode: ByValue, source: FromRvalue};
+                  mode: ByValue, source: RevokeClean};
 }
 
 pub fn immediate_rvalue_bcx(bcx: block,
@@ -221,7 +195,7 @@ pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum {
 
     let llty = type_of::type_of(bcx.ccx(), ty);
     let scratch = alloca_maybe_zeroed(bcx, llty, zero);
-    Datum { val: scratch, ty: ty, mode: ByRef, source: FromRvalue }
+    Datum { val: scratch, ty: ty, mode: ByRef, source: RevokeClean }
 }
 
 pub fn appropriate_mode(ty: ty::t) -> DatumMode {
@@ -241,42 +215,39 @@ pub fn appropriate_mode(ty: ty::t) -> DatumMode {
 }
 
 pub impl Datum {
-    fn store_will_move() -> bool {
-        match self.source {
-            FromRvalue | FromLastUseLvalue => true,
-            FromLvalue => false
-        }
-    }
-
-    fn store_to(bcx: block, action: CopyAction, dst: ValueRef) -> block {
+    fn store_to(bcx: block, id: ast::node_id,
+                action: CopyAction, dst: ValueRef) -> block {
         /*!
          *
          * Stores this value into its final home.  This moves if
-         * possible, but copies otherwise. */
+         * `id` is located in the move table, but copies otherwise.
+         */
 
-        if self.store_will_move() {
+        if bcx.ccx().maps.moves_map.contains_key(id) {
             self.move_to(bcx, action, dst)
         } else {
             self.copy_to(bcx, action, dst)
         }
     }
 
-    fn store_to_dest(bcx: block, dest: expr::Dest) -> block {
+    fn store_to_dest(bcx: block, id: ast::node_id,
+                     dest: expr::Dest) -> block {
         match dest {
             expr::Ignore => {
                 return bcx;
             }
             expr::SaveIn(addr) => {
-                return self.store_to(bcx, INIT, addr);
+                return self.store_to(bcx, id, INIT, addr);
             }
         }
     }
 
-    fn store_to_datum(bcx: block, action: CopyAction, datum: Datum) -> block {
+    fn store_to_datum(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, action, datum.val)
+        self.store_to(bcx, id, action, datum.val)
     }
 
     fn move_to_datum(bcx: block, action: CopyAction, datum: Datum) -> block {
@@ -396,7 +367,7 @@ pub impl Datum {
          * Schedules this datum for cleanup in `bcx`.  The datum
          * must be an rvalue. */
 
-        assert self.source.is_rvalue();
+        assert self.source == RevokeClean;
         match self.mode {
             ByValue => {
                 add_clean_temp_immediate(bcx, self.val, self.ty);
@@ -410,10 +381,10 @@ pub impl Datum {
     fn cancel_clean(bcx: block) {
         if ty::type_needs_drop(bcx.tcx(), self.ty) {
             match self.source {
-                FromRvalue => {
+                RevokeClean => {
                     revoke_clean(bcx, self.val);
                 }
-                FromLvalue | FromLastUseLvalue => {
+                ZeroMem => {
                     // Lvalues which potentially need to be dropped
                     // must be passed by ref, so that we can zero them
                     // out.
@@ -444,7 +415,7 @@ pub impl Datum {
             ByValue => self,
             ByRef => {
                 Datum {val: self.to_value_llval(bcx), mode: ByValue,
-                       ty: self.ty, source: FromRvalue}
+                       ty: self.ty, source: RevokeClean}
             }
         }
     }
@@ -476,7 +447,7 @@ pub impl Datum {
             ByRef => self,
             ByValue => {
                 Datum {val: self.to_ref_llval(bcx), mode: ByRef,
-                       ty: self.ty, source: FromRvalue}
+                       ty: self.ty, source: RevokeClean}
             }
         }
     }
@@ -527,7 +498,7 @@ pub impl Datum {
     fn GEPi(bcx: block,
             ixs: &[uint],
             ty: ty::t,
-            source: DatumSource)
+            source: DatumCleanup)
          -> Datum {
         let base_val = self.to_ref_llval(bcx);
         Datum {
@@ -618,7 +589,7 @@ pub impl Datum {
 
         let ptr = self.to_value_llval(bcx);
         let body = opaque_box_body(bcx, content_ty, ptr);
-        Datum {val: body, ty: content_ty, mode: ByRef, source: FromLvalue}
+        Datum {val: body, ty: content_ty, mode: ByRef, source: ZeroMem}
     }
 
     fn to_rptr(bcx: block) -> Datum {
@@ -636,7 +607,7 @@ pub impl Datum {
         let rptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::re_static,
                                       self.ty);
         Datum {val: llval, ty: rptr_ty,
-               mode: ByValue, source: FromRvalue}
+               mode: ByValue, source: RevokeClean}
     }
 
     fn try_deref(
@@ -701,7 +672,7 @@ pub impl Datum {
                                 val: PointerCast(bcx, self.val, llty),
                                 ty: ty,
                                 mode: ByRef,
-                                source: FromLvalue
+                                source: ZeroMem
                             }),
                             bcx
                         )
@@ -740,7 +711,7 @@ pub impl Datum {
                                 val: GEPi(bcx, self.val, [0, 0, 0]),
                                 ty: ty,
                                 mode: ByRef,
-                                source: FromLvalue
+                                source: ZeroMem
                             }),
                             bcx
                         )
@@ -768,7 +739,7 @@ pub impl Datum {
                 val: lv.to_value_llval(bcx),
                 ty: ty,
                 mode: ByRef,
-                source: FromLvalue // *p is an lvalue
+                source: ZeroMem // *p is an lvalue
             }
         }
     }
@@ -841,8 +812,9 @@ pub impl DatumBlock {
         self.datum.drop_val(self.bcx)
     }
 
-    fn store_to(action: CopyAction, dst: ValueRef) -> block {
-        self.datum.store_to(self.bcx, action, dst)
+    fn store_to(id: ast::node_id, action: CopyAction,
+                dst: ValueRef) -> block {
+        self.datum.store_to(self.bcx, id, action, dst)
     }
 
     fn copy_to(action: CopyAction, dst: ValueRef) -> block {
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 4580a621f99..7d724ef7441 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -789,10 +789,10 @@ pub fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
       }
       ast_map::node_expr(expr) => {
         match /*bad*/copy expr.node {
-          ast::expr_fn(_, decl, _, _) => {
+          ast::expr_fn(_, decl, _) => {
             ((dbg_cx.names)(~"fn"), decl.output, expr.id)
           }
-          ast::expr_fn_block(decl, _, _) => {
+          ast::expr_fn_block(decl, _) => {
             ((dbg_cx.names)(~"fn"), decl.output, expr.id)
           }
           _ => fcx.ccx.sess.span_bug(expr.span,
@@ -818,7 +818,7 @@ pub fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
     }
 
     let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
-    let file_node = create_file(cx, loc.file.name).node;
+    let file_node = create_file(cx, copy loc.file.name).node;
     let ty_node = if cx.sess.opts.extra_debuginfo {
         match ret_ty.node {
           ast::ty_nil => llnull(),
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 15830e48a07..2a8a6a696c2 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -12,45 +12,53 @@
 
 # Translation of expressions.
 
-## User's guide
-
-If you wish to translate an expression, there are two basic modes:
-
-1. `trans_into(block, expr, Dest) -> block`
-2. `trans_to_datum(block, expr) -> DatumBlock`
-
-`trans_into()` is the preferred form to use whenever possible.  It
-evaluates the expression and stores its 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.
-
-Sometimes, though, you just want to evaluate the expression into
-some memory location so you can go and inspect it (e.g., a `match`
-expression).  In that case, `trans_to_datum()` is your friend.  It
-will evaluate the expression and return a `Datum` describing where
-the result is to be found.  This function 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).
-
-## More specific functions
-
-The two functions above are the most general and can handle any
-situation, but there are a few other functions that are useful
-in specific scenarios:
-
-- `trans_lvalue()` is exactly like `trans_to_datum()` but it only
-  works on lvalues.  This is mostly used as an assertion for those
-  places where only an lvalue is expected.  It also guarantees that
-  you will get a by-ref Datum back (almost, see [1]).
-- `trans_local_var()` can be used to trans a ref to a local variable
-  that is not an expression.
+## Recommended entry point
+
+If you wish to translate an expression, the preferred way to do
+so is to use:
+
+    expr::trans_into(block, expr, Dest) -> block
+
+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.
+
+## Translation to a datum
+
+In some cases, `trans_into()` is too narrow of an interface.
+Generally this occurs either when you know that the result value is
+going to be a scalar, or when you need to evaluate the expression into
+some memory location so you can go and inspect it (e.g., assignments,
+`match` expressions, the `&` operator).
+
+In such cases, you want the following function:
+
+    trans_to_datum(block, expr) -> DatumBlock
+
+This function generates code to evaluate the expression and return a
+`Datum` describing where the result is to be found.  This function
+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).
+
+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.
+
+## Translating local variables
+
+`trans_local_var()` can be used to trans a ref to a local variable
+that is not an expression.  This is needed for captures.
 
 ## Ownership and cleanups
 
@@ -127,7 +135,6 @@ use middle::trans::datum::*;
 use middle::trans::machine;
 use middle::trans::meth;
 use middle::trans::tvec;
-use middle::ty::MoveValue;
 use middle::ty::struct_mutable_fields;
 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
 use util::common::indenter;
@@ -258,21 +265,70 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
 }
 
 pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
-    return match bcx.tcx().adjustments.find(expr.id) {
-        None => trans_into_unadjusted(bcx, expr, dest),
-        Some(_) => {
-            // use trans_to_datum, which is mildly less efficient but
-            // which will perform the adjustments:
-            let datumblock = trans_to_datum(bcx, expr);
+    if bcx.tcx().adjustments.contains_key(expr.id) {
+        // use trans_to_datum, which is mildly less efficient but
+        // which will perform the adjustments:
+        let datumblock = trans_to_datum(bcx, expr);
+        return match dest {
+            Ignore => datumblock.bcx,
+            SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
+        };
+    }
+
+    let ty = expr_ty(bcx, expr);
+
+    debug!("trans_into_unadjusted(expr=%s, dest=%s)",
+           bcx.expr_to_str(expr),
+           dest.to_str(bcx.ccx()));
+    let _indenter = indenter();
+
+    debuginfo::update_source_pos(bcx, expr.span);
+
+    let dest = {
+        if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
+            Ignore
+        } else {
+            dest
+        }
+    };
+
+    let kind = bcx.expr_kind(expr);
+    debug!("expr kind = %?", kind);
+    return match kind {
+        ty::LvalueExpr => {
+            let datumblock = trans_lvalue_unadjusted(bcx, expr);
             match dest {
                 Ignore => datumblock.bcx,
-                SaveIn(lldest) => datumblock.store_to(INIT, lldest)
+                SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
             }
         }
-    }
+        ty::RvalueDatumExpr => {
+            let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
+            match dest {
+                Ignore => datumblock.drop_val(),
+
+                // NB: We always do `move_to()` regardless of the
+                // moves_map because we're processing an rvalue
+                SaveIn(lldest) => datumblock.move_to(INIT, lldest)
+            }
+        }
+        ty::RvalueDpsExpr => {
+            trans_rvalue_dps_unadjusted(bcx, expr, dest)
+        }
+        ty::RvalueStmtExpr => {
+            trans_rvalue_stmt_unadjusted(bcx, expr)
+        }
+    };
 }
 
 fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
+    /*!
+     *
+     * Translates an lvalue expression, always yielding a by-ref
+     * datum.  Generally speaking you should call trans_to_datum()
+     * instead, but sometimes we call trans_lvalue() directly as a
+     * means of asserting that a particular expression is an lvalue. */
+
     return match bcx.tcx().adjustments.find(expr.id) {
         None => trans_lvalue_unadjusted(bcx, expr),
         Some(_) => {
@@ -350,50 +406,6 @@ fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
     }
 }
 
-fn trans_into_unadjusted(bcx: block, expr: @ast::expr, dest: Dest) -> block {
-    let ty = expr_ty(bcx, expr);
-
-    debug!("trans_into_unadjusted(expr=%s, dest=%s)",
-           bcx.expr_to_str(expr),
-           dest.to_str(bcx.ccx()));
-    let _indenter = indenter();
-
-    debuginfo::update_source_pos(bcx, expr.span);
-
-    let dest = {
-        if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
-            Ignore
-        } else {
-            dest
-        }
-    };
-
-    let kind = bcx.expr_kind(expr);
-    debug!("expr kind = %?", kind);
-    match kind {
-        ty::LvalueExpr => {
-            let datumblock = trans_lvalue_unadjusted(bcx, expr);
-            match dest {
-                Ignore => datumblock.bcx,
-                SaveIn(lldest) => datumblock.store_to(INIT, lldest)
-            }
-        }
-        ty::RvalueDatumExpr => {
-            let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
-            match dest {
-                Ignore => datumblock.drop_val(),
-                SaveIn(lldest) => datumblock.store_to(INIT, lldest)
-            }
-        }
-        ty::RvalueDpsExpr => {
-            return trans_rvalue_dps_unadjusted(bcx, expr, dest);
-        }
-        ty::RvalueStmtExpr => {
-            return trans_rvalue_stmt_unadjusted(bcx, expr);
-        }
-    }
-}
-
 fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
     let _icx = bcx.insn_ctxt("trans_rvalue_datum_unadjusted");
 
@@ -472,9 +484,12 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
             return controlflow::trans_loop(bcx, (*body), opt_label);
         }
         ast::expr_assign(dst, src) => {
-            let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
-            let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
-            return src_datum.store_to_datum(bcx, DROP_EXISTING, dst_datum);
+            let src_datum = unpack_datum!(
+                bcx, trans_to_datum(bcx, src));
+            let dst_datum = unpack_datum!(
+                bcx, trans_lvalue(bcx, dst));
+            return src_datum.store_to_datum(
+                bcx, src.id, DROP_EXISTING, dst_datum);
         }
         ast::expr_swap(dst, src) => {
             let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
@@ -509,8 +524,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
 
     trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
 
-    // XXX: This copy is really bad.
-    match /*bad*/copy expr.node {
+    match expr.node {
         ast::expr_paren(e) => {
             return trans_rvalue_dps_unadjusted(bcx, e, dest);
         }
@@ -519,14 +533,14 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
                                             bcx.def(expr.id), dest);
         }
         ast::expr_if(cond, ref thn, els) => {
-            return controlflow::trans_if(bcx, cond, (*thn), els, dest);
+            return controlflow::trans_if(bcx, cond, *thn, els, dest);
         }
         ast::expr_match(discr, ref arms) => {
             return _match::trans_match(bcx, expr, discr, /*bad*/copy *arms,
                                        dest);
         }
         ast::expr_block(ref blk) => {
-            return do base::with_scope(bcx, (*blk).info(),
+            return do base::with_scope(bcx, blk.info(),
                                        ~"block-expr body") |bcx| {
                 controlflow::trans_block(bcx, (*blk), dest)
             };
@@ -535,8 +549,8 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_struct(_, ref fields, base) => {
             return trans_rec_or_struct(bcx, (*fields), base, expr.id, dest);
         }
-        ast::expr_tup(args) => {
-            return trans_tup(bcx, args, dest);
+        ast::expr_tup(ref args) => {
+            return trans_tup(bcx, *args, dest);
         }
         ast::expr_lit(@ast::spanned {node: ast::lit_str(s), _}) => {
             return tvec::trans_lit_str(bcx, expr, s, dest);
@@ -552,15 +566,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
             return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
         }
         // XXX: Bad copy.
-        ast::expr_fn(proto, copy decl, ref body, cap_clause) => {
+        ast::expr_fn(proto, copy decl, ref body) => {
             // Don't use this function for anything real. Use the one in
             // astconv instead.
             return closure::trans_expr_fn(bcx, proto, decl,
                                           /*bad*/copy *body,
                                           expr.id, expr.id,
-                                          cap_clause, None, dest);
+                                          None, dest);
         }
-        ast::expr_fn_block(ref decl, ref body, cap_clause) => {
+        ast::expr_fn_block(ref decl, ref body) => {
             let expr_ty = expr_ty(bcx, expr);
             match ty::get(expr_ty).sty {
                 ty::ty_fn(ref fn_ty) => {
@@ -570,7 +584,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
                     return closure::trans_expr_fn(
                         bcx, fn_ty.meta.proto, /*bad*/copy *decl,
                         /*bad*/copy *body, expr.id, expr.id,
-                        cap_clause, None, dest);
+                        None, dest);
                 }
                 _ => {
                     bcx.sess().impossible_case(
@@ -582,7 +596,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
             match ty::get(expr_ty(bcx, expr)).sty {
                 ty::ty_fn(ref fn_ty) => {
                     match blk.node {
-                        ast::expr_fn_block(copy decl, ref body, cap) => {
+                        ast::expr_fn_block(copy decl, ref body) => {
                             return closure::trans_expr_fn(
                                 bcx,
                                 fn_ty.meta.proto,
@@ -590,7 +604,6 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
                                 /*bad*/copy *body,
                                 expr.id,
                                 blk.id,
-                                cap,
                                 Some(None),
                                 dest);
                         }
@@ -613,26 +626,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
         ast::expr_copy(a) => {
             return trans_into(bcx, a, dest);
         }
-        ast::expr_unary_move(a) => {
-            if bcx.expr_is_lval(a) {
-                let datum = unpack_datum!(bcx, trans_to_datum(bcx, a));
-                return match dest {
-                    Ignore => drop_and_cancel_clean(bcx, datum),
-                    SaveIn(addr) => datum.move_to(bcx, INIT, addr)
-                };
-            } else {
-                return trans_into(bcx, a, dest);
-            }
-        }
-        ast::expr_call(f, args, _) => {
+        ast::expr_call(f, ref args, _) => {
             return callee::trans_call(
-                bcx, expr, f, callee::ArgExprs(args), expr.id, dest);
+                bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
         }
-        ast::expr_method_call(rcvr, _, _, args, _) => {
+        ast::expr_method_call(rcvr, _, _, ref args, _) => {
             return callee::trans_method_call(bcx,
                                              expr,
                                              rcvr,
-                                             callee::ArgExprs(args),
+                                             callee::ArgExprs(*args),
                                              dest);
         }
         ast::expr_binary(_, lhs, rhs) => {
@@ -727,9 +729,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
     /*!
      *
      * Translates an lvalue expression, always yielding a by-ref
-     * datum.  Generally speaking you should call trans_to_datum()
-     * instead, but sometimes we call trans_lvalue() directly as a
-     * means of asserting that a particular expression is an lvalue. */
+     * datum.  Does not apply any adjustments. */
 
     let _icx = bcx.insn_ctxt("trans_lval");
     let mut bcx = bcx;
@@ -752,6 +752,17 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
     return DatumBlock {bcx: bcx, datum: unrooted_datum};
 
     fn unrooted(bcx: block, expr: @ast::expr) -> DatumBlock {
+        /*!
+         *
+         * Translates `expr`.  Note that this version generally
+         * yields an unrooted, unmoved version.  Rooting and possible
+         * moves are dealt with above in trans_lvalue_unadjusted().
+         *
+         * One exception is if `expr` refers to a local variable,
+         * in which case the source may already be FromMovedLvalue
+         * if appropriate.
+         */
+
         let mut bcx = bcx;
 
         match expr.node {
@@ -762,7 +773,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
                 return trans_def_lvalue(bcx, expr, bcx.def(expr.id));
             }
             ast::expr_field(base, ident, _) => {
-                return trans_rec_field(bcx, base, ident, expr.id);
+                return trans_rec_field(bcx, base, ident);
             }
             ast::expr_index(base, idx) => {
                 return trans_index(bcx, expr, base, idx);
@@ -779,52 +790,152 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
             }
         }
     }
-}
 
-fn trans_def_lvalue(bcx: block,
-                    ref_expr: @ast::expr,
-                    def: ast::def)
-                 -> DatumBlock {
-    let _icx = bcx.insn_ctxt("trans_def_lvalue");
-    let ccx = bcx.ccx();
-    match def {
-        ast::def_const(did) => {
-            let const_ty = expr_ty(bcx, ref_expr);
-            let val = if did.crate == ast::local_crate {
-                // The LLVM global has the type of its initializer,
-                // which may not be equal to the enum's type for
-                // non-C-like enums.
-                PointerCast(bcx, base::get_item_val(ccx, did.node),
-                            T_ptr(type_of(bcx.ccx(), const_ty)))
-            } else {
-                base::trans_external_path(ccx, did, const_ty)
-            };
+    fn trans_rec_field(bcx: block,
+                       base: @ast::expr,
+                       field: ast::ident) -> DatumBlock {
+        /*!
+         *
+         * Translates `base.field`.  Note that this version always
+         * yields an unrooted, unmoved version.  Rooting and possible
+         * moves are dealt with above in trans_lvalue_unadjusted().
+         */
+
+        let mut bcx = bcx;
+        let _icx = bcx.insn_ctxt("trans_rec_field");
+
+        let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
+        do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| {
+            let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
             DatumBlock {
-                bcx: bcx,
-                datum: Datum {val: val,
-                              ty: const_ty,
-                              mode: ByRef,
-                              source: FromLvalue}
+                datum: base_datum.GEPi(bcx,
+                                       [0u, 0u, ix],
+                                       field_tys[ix].mt.ty,
+                                       ZeroMem),
+                bcx: bcx
             }
         }
-        _ => {
-            DatumBlock {
-                bcx: bcx,
-                datum: trans_local_var(bcx, def, Some(ref_expr.id))
+    }
+
+    fn trans_index(bcx: block,
+                   index_expr: @ast::expr,
+                   base: @ast::expr,
+                   idx: @ast::expr) -> DatumBlock {
+        /*!
+         *
+         * Translates `base[idx]`.  Note that this version always
+         * yields an unrooted, unmoved version.  Rooting and possible
+         * moves are dealt with above in trans_lvalue_unadjusted().
+         */
+
+        let _icx = bcx.insn_ctxt("trans_index");
+        let ccx = bcx.ccx();
+        let base_ty = expr_ty(bcx, base);
+        let mut bcx = bcx;
+
+        let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
+
+        // Translate index expression and cast to a suitable LLVM integer.
+        // Rust is less strict than LLVM in this regard.
+        let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
+        let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
+        let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
+        let ix_val = {
+            if ix_size < int_size {
+                if ty::type_is_signed(expr_ty(bcx, idx)) {
+                    SExt(bcx, ix_val, ccx.int_type)
+                } else { ZExt(bcx, ix_val, ccx.int_type) }
+            } else if ix_size > int_size {
+                Trunc(bcx, ix_val, ccx.int_type)
+            } else {
+                ix_val
+            }
+        };
+
+        let vt = tvec::vec_types(bcx, base_datum.ty);
+        base::maybe_name_value(bcx.ccx(), vt.llunit_size, ~"unit_sz");
+        let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
+        base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
+
+        let mut (base, len) = base_datum.get_base_and_len(bcx);
+
+        if ty::type_is_str(base_ty) {
+            // acccount for null terminator in the case of string
+            len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
+        }
+
+        debug!("trans_index: base %s", val_str(bcx.ccx().tn, base));
+        debug!("trans_index: len %s", val_str(bcx.ccx().tn, len));
+
+        let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
+        let bcx = do with_cond(bcx, bounds_check) |bcx| {
+            let unscaled_len = UDiv(bcx, len, vt.llunit_size);
+            controlflow::trans_fail_bounds_check(bcx, index_expr.span,
+                                                 ix_val, unscaled_len)
+        };
+        let elt = InBoundsGEP(bcx, base, ~[ix_val]);
+        let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
+        return DatumBlock {
+            bcx: bcx,
+            datum: Datum {val: elt,
+                          ty: vt.unit_ty,
+                          mode: ByRef,
+                          source: ZeroMem}
+        };
+    }
+
+    fn trans_def_lvalue(bcx: block,
+                        ref_expr: @ast::expr,
+                        def: ast::def)
+        -> DatumBlock
+    {
+        /*!
+         *
+         * Translates a reference to a path.  Note that this version
+         * generally yields an unrooted, unmoved version.  Rooting and
+         * possible moves are dealt with above in
+         * trans_lvalue_unadjusted(), with the caveat that local variables
+         * may already be in move mode.
+         */
+
+        let _icx = bcx.insn_ctxt("trans_def_lvalue");
+        let ccx = bcx.ccx();
+        match def {
+            ast::def_const(did) => {
+                let const_ty = expr_ty(bcx, ref_expr);
+                let val = if did.crate == ast::local_crate {
+                    // The LLVM global has the type of its initializer,
+                    // which may not be equal to the enum's type for
+                    // non-C-like enums.
+                    PointerCast(bcx, base::get_item_val(ccx, did.node),
+                                T_ptr(type_of(bcx.ccx(), const_ty)))
+                } else {
+                    base::trans_external_path(ccx, did, const_ty)
+                };
+                DatumBlock {
+                    bcx: bcx,
+                    datum: Datum {val: val,
+                                  ty: const_ty,
+                                  mode: ByRef,
+                                  source: ZeroMem}
+                }
+            }
+            _ => {
+                DatumBlock {
+                    bcx: bcx,
+                    datum: trans_local_var(bcx, def)
+                }
             }
         }
     }
 }
 
-pub fn trans_local_var(bcx: block,
-                       def: ast::def,
-                       expr_id_opt: Option<ast::node_id>)
-                    -> Datum {
+pub fn trans_local_var(bcx: block, def: ast::def) -> Datum {
     let _icx = bcx.insn_ctxt("trans_local_var");
 
     return match def {
         ast::def_upvar(nid, _, _, _) => {
-            // Can't move upvars, so this is never a FromLvalueLastUse.
+            // Can't move upvars, so this is never a ZeroMemLastUse.
             let local_ty = node_id_type(bcx, nid);
             match bcx.fcx.llupvars.find(nid) {
                 Some(val) => {
@@ -832,7 +943,7 @@ pub fn trans_local_var(bcx: block,
                         val: val,
                         ty: local_ty,
                         mode: ByRef,
-                        source: FromLvalue
+                        source: ZeroMem
                     }
                 }
                 None => {
@@ -842,10 +953,10 @@ pub fn trans_local_var(bcx: block,
             }
         }
         ast::def_arg(nid, _, _) => {
-            take_local(bcx, bcx.fcx.llargs, nid, expr_id_opt)
+            take_local(bcx, bcx.fcx.llargs, nid)
         }
         ast::def_local(nid, _) | ast::def_binding(nid, _) => {
-            take_local(bcx, bcx.fcx.lllocals, nid, expr_id_opt)
+            take_local(bcx, bcx.fcx.lllocals, nid)
         }
         ast::def_self(nid, _) => {
             let self_info: ValSelfData = match bcx.fcx.llself {
@@ -867,7 +978,7 @@ pub fn trans_local_var(bcx: block,
                 val: casted_val,
                 ty: self_info.t,
                 mode: ByRef,
-                source: source_from_opt_lvalue_type(bcx.tcx(), expr_id_opt)
+                source: ZeroMem
             }
         }
         _ => {
@@ -878,8 +989,7 @@ pub fn trans_local_var(bcx: block,
 
     fn take_local(bcx: block,
                   table: HashMap<ast::node_id, local_val>,
-                  nid: ast::node_id,
-                  expr_id_opt: Option<ast::node_id>) -> Datum {
+                  nid: ast::node_id) -> Datum {
         let (v, mode) = match table.find(nid) {
             Some(local_mem(v)) => (v, ByRef),
             Some(local_imm(v)) => (v, ByValue),
@@ -897,7 +1007,7 @@ pub fn trans_local_var(bcx: block,
             val: v,
             ty: ty,
             mode: mode,
-            source: source_from_opt_lvalue_type(bcx.tcx(), expr_id_opt)
+            source: ZeroMem
         }
     }
 }
@@ -981,102 +1091,6 @@ pub fn with_field_tys<R>(tcx: ty::ctxt,
     }
 }
 
-fn trans_rec_field(bcx: block,
-                   base: @ast::expr,
-                   field: ast::ident,
-                   expr_id: ast::node_id) -> DatumBlock {
-    let mut bcx = bcx;
-    let _icx = bcx.insn_ctxt("trans_rec_field");
-
-    let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
-    do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| {
-        let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
-        DatumBlock {
-            datum: base_datum.GEPi(bcx,
-                                   [0u, 0u, ix],
-                                   field_tys[ix].mt.ty,
-                                   source_from_opt_lvalue_type(
-                                        bcx.tcx(), Some(expr_id))),
-            bcx: bcx
-        }
-    }
-}
-
-fn source_from_opt_lvalue_type(tcx: ty::ctxt,
-                               expr_id_opt: Option<ast::node_id>)
-                            -> DatumSource {
-    match expr_id_opt {
-        None => FromLvalue,
-        Some(expr_id) => {
-            match tcx.value_modes.find(expr_id) {
-                Some(MoveValue) => FromLastUseLvalue,
-                Some(_) | None => FromLvalue,
-            }
-        }
-    }
-}
-
-fn trans_index(bcx: block,
-               index_expr: @ast::expr,
-               base: @ast::expr,
-               idx: @ast::expr) -> DatumBlock {
-    let _icx = bcx.insn_ctxt("trans_index");
-    let ccx = bcx.ccx();
-    let base_ty = expr_ty(bcx, base);
-    let mut bcx = bcx;
-
-    let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
-
-    // Translate index expression and cast to a suitable LLVM integer.
-    // Rust is less strict than LLVM in this regard.
-    let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
-    let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
-    let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
-    let ix_val = {
-        if ix_size < int_size {
-            if ty::type_is_signed(expr_ty(bcx, idx)) {
-                SExt(bcx, ix_val, ccx.int_type)
-            } else { ZExt(bcx, ix_val, ccx.int_type) }
-        } else if ix_size > int_size {
-            Trunc(bcx, ix_val, ccx.int_type)
-        } else {
-            ix_val
-        }
-    };
-
-    let vt = tvec::vec_types(bcx, base_datum.ty);
-    base::maybe_name_value(bcx.ccx(), vt.llunit_size, ~"unit_sz");
-    let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
-    base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
-
-    let mut (base, len) = base_datum.get_base_and_len(bcx);
-
-    if ty::type_is_str(base_ty) {
-        // acccount for null terminator in the case of string
-        len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
-    }
-
-    debug!("trans_index: base %s", val_str(bcx.ccx().tn, base));
-    debug!("trans_index: len %s", val_str(bcx.ccx().tn, len));
-
-    let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
-    let bcx = do with_cond(bcx, bounds_check) |bcx| {
-        let unscaled_len = UDiv(bcx, len, vt.llunit_size);
-        controlflow::trans_fail_bounds_check(bcx, index_expr.span,
-                                             ix_val, unscaled_len)
-    };
-    let elt = InBoundsGEP(bcx, base, ~[ix_val]);
-    let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty));
-    return DatumBlock {
-        bcx: bcx,
-        datum: Datum {val: elt,
-                      ty: vt.unit_ty,
-                      mode: ByRef,
-                      source: source_from_opt_lvalue_type(
-                            bcx.tcx(), Some(index_expr.id))}
-    };
-}
-
 fn trans_rec_or_struct(bcx: block,
                        fields: &[ast::field],
                        base: Option<@ast::expr>,
@@ -1158,7 +1172,7 @@ fn trans_rec_or_struct(bcx: block,
             let base_datum = unpack_datum!(
                 bcx, trans_to_datum(bcx, *base_expr));
 
-            // Copy over inherited fields
+            // Copy/move over inherited fields
             for field_tys.eachi |i, field_ty| {
                 if !fields.any(|f| f.node.ident == field_ty.ident) {
                     let dest = GEPi(bcx, addr, struct_field(i));
@@ -1166,8 +1180,8 @@ fn trans_rec_or_struct(bcx: block,
                         base_datum.GEPi(bcx,
                                         struct_field(i),
                                         field_ty.mt.ty,
-                                        FromLvalue);
-                    bcx = base_field.store_to(bcx, INIT, dest);
+                                        ZeroMem);
+                    bcx = base_field.store_to(bcx, base_expr.id, INIT, dest);
                 }
             }
         }
@@ -1187,7 +1201,7 @@ fn trans_rec_or_struct(bcx: block,
     }
 }
 
-fn trans_tup(bcx: block, elts: ~[@ast::expr], dest: Dest) -> block {
+fn trans_tup(bcx: block, elts: &[@ast::expr], dest: Dest) -> block {
     let _icx = bcx.insn_ctxt("trans_tup");
     let mut bcx = bcx;
     let addr = match dest {
@@ -1642,7 +1656,7 @@ fn trans_assign_op(bcx: block,
                       trans_eager_binop(
                           bcx, expr, dst_datum.ty, op,
                           &dst_datum, &src_datum));
-    return result_datum.store_to_datum(bcx, DROP_EXISTING, dst_datum);
+    return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
 }
 
 fn shorten(+x: ~str) -> ~str {
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index e725e484a89..0431d0aa4dd 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -69,7 +69,7 @@ fn c_arg_and_ret_lltys(ccx: @crate_ctxt,
         ty::ty_fn(ref fn_ty) => {
             let llargtys = type_of_explicit_args(
                 ccx,
-                /*bad*/copy fn_ty.sig.inputs);
+                fn_ty.sig.inputs);
             let llretty = type_of::type_of(ccx, fn_ty.sig.output);
             (llargtys, llretty, fn_ty.sig.output)
         }
@@ -441,7 +441,7 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
             //
             // - the datum will be by ref if the value is non-immediate;
             //
-            // - the datum has a FromRvalue source because, that way,
+            // - the datum has a RevokeClean source because, that way,
             //   the `move_to()` method does not feel compelled to
             //   zero out the memory where the datum resides.  Zeroing
             //   is not necessary since, for intrinsics, there is no
@@ -449,7 +449,7 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
             let tp_ty = substs.tys[0];
             let mode = appropriate_mode(tp_ty);
             let src = Datum {val: get_param(decl, first_real_arg + 1u),
-                             ty: tp_ty, mode: mode, source: FromRvalue};
+                             ty: tp_ty, mode: mode, source: RevokeClean};
             bcx = src.move_to(bcx, DROP_EXISTING,
                               get_param(decl, first_real_arg));
         }
@@ -458,7 +458,7 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
             let tp_ty = substs.tys[0];
             let mode = appropriate_mode(tp_ty);
             let src = Datum {val: get_param(decl, first_real_arg + 1u),
-                             ty: tp_ty, mode: mode, source: FromRvalue};
+                             ty: tp_ty, mode: mode, source: RevokeClean};
             bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
         }
         ~"min_align_of" => {
@@ -546,16 +546,17 @@ pub fn trans_intrinsic(ccx: @crate_ctxt,
                               onceness: ast::Many,
                               region: ty::re_bound(ty::br_anon(0)),
                               bounds: @~[]},
-                sig: FnSig {inputs: ~[arg {mode: ast::expl(ast::by_val),
+                sig: FnSig {inputs: ~[arg {mode: ast::expl(ast::by_copy),
                                            ty: star_u8}],
                             output: ty::mk_nil(bcx.tcx())}
             });
             let datum = Datum {val: get_param(decl, first_real_arg),
-                               mode: ByRef, ty: fty, source: FromLvalue};
+                               mode: ByRef, ty: fty, source: ZeroMem};
+            let arg_vals = ~[frameaddress_val];
             bcx = trans_call_inner(
                 bcx, None, fty, ty::mk_nil(bcx.tcx()),
                 |bcx| Callee {bcx: bcx, data: Closure(datum)},
-                ArgVals(~[frameaddress_val]), Ignore, DontAutorefArg);
+                ArgVals(arg_vals), Ignore, DontAutorefArg);
         }
         ~"morestack_addr" => {
             // XXX This is a hack to grab the address of this particular
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index f773b09d5de..26ea47d7e73 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -232,7 +232,6 @@ pub impl reflector {
                   ast::expl(e) => match e {
                     ast::by_ref => 1u,
                     ast::by_val => 2u,
-                    ast::by_move => 4u,
                     ast::by_copy => 5u
                   }
                 };
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index c8dc3e702be..6f183aa50b0 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -24,7 +24,7 @@ pub fn type_of_explicit_arg(ccx: @crate_ctxt, arg: ty::arg) -> TypeRef {
     let llty = type_of(ccx, arg.ty);
     match ty::resolved_mode(ccx.tcx, arg.mode) {
         ast::by_val => llty,
-        ast::by_copy | ast::by_move => {
+        ast::by_copy => {
             if ty::type_is_immediate(arg.ty) {
                 llty
             } else {
@@ -35,12 +35,12 @@ pub fn type_of_explicit_arg(ccx: @crate_ctxt, arg: ty::arg) -> TypeRef {
     }
 }
 
-pub fn type_of_explicit_args(ccx: @crate_ctxt, inputs: ~[ty::arg])
-                          -> ~[TypeRef] {
+pub fn type_of_explicit_args(ccx: @crate_ctxt,
+                             inputs: &[ty::arg]) -> ~[TypeRef] {
     inputs.map(|arg| type_of_explicit_arg(ccx, *arg))
 }
 
-pub fn type_of_fn(cx: @crate_ctxt, inputs: ~[ty::arg],
+pub fn type_of_fn(cx: @crate_ctxt, inputs: &[ty::arg],
                   output: ty::t) -> TypeRef {
     unsafe {
         let mut atys: ~[TypeRef] = ~[];
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index c19db4a75b9..d678b76a1e1 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -72,7 +72,7 @@ pub fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
         ty::ty_fn(ref fn_ty) => {
             for vec::each(fn_ty.sig.inputs) |arg| {
                 match ty::resolved_mode(ccx.tcx, arg.mode) {
-                    by_val | by_move | by_copy => {
+                    by_val | by_copy => {
                         type_needs(cx, use_repr, arg.ty);
                     }
                     by_ref => {}
@@ -255,7 +255,7 @@ pub fn mark_for_expr(cx: ctx, e: @expr) {
       expr_rec(_, _) | expr_struct(*) | expr_tup(_) |
       expr_unary(box(_), _) | expr_unary(uniq(_), _) |
       expr_binary(add, _, _) |
-      expr_copy(_) | expr_unary_move(_) | expr_repeat(*) => {
+      expr_copy(_) | expr_repeat(*) => {
         node_type_needs(cx, use_repr, e.id);
       }
       expr_cast(base, _) => {
@@ -316,7 +316,7 @@ pub fn mark_for_expr(cx: ctx, e: @expr) {
               ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, f.id))
           ) |a| {
               match a.mode {
-                  expl(by_move) | expl(by_copy) | expl(by_val) => {
+                  expl(by_copy) | expl(by_val) => {
                       type_needs(cx, use_repr, a.ty);
                   }
                   _ => ()
@@ -330,7 +330,7 @@ pub fn mark_for_expr(cx: ctx, e: @expr) {
         for ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx,
                                                e.callee_id)).each |a| {
           match a.mode {
-              expl(by_move) | expl(by_copy) | expl(by_val) => {
+              expl(by_copy) | expl(by_val) => {
                   type_needs(cx, use_repr, a.ty);
               }
               _ => ()
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 2dd70f2f57d..255b87e2d5e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -99,15 +99,6 @@ pub struct field_ty {
   mutability: ast::struct_mutability,
 }
 
-/// How an lvalue is to be used.
-#[auto_encode]
-#[auto_decode]
-pub enum ValueMode {
-    ReadValue,  // Non-destructively read the value; do not copy or move.
-    CopyValue,  // Copy the value.
-    MoveValue,  // Move the value.
-}
-
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
 #[deriving_eq]
@@ -295,9 +286,6 @@ struct ctxt_ {
     // A method will be in this list if and only if it is a destructor.
     destructors: HashMap<ast::def_id, ()>,
 
-    // Records the value mode (read, copy, or move) for every value.
-    value_modes: HashMap<ast::node_id, ValueMode>,
-
     // Maps a trait onto a mapping from self-ty to impl
     trait_impls: HashMap<ast::def_id, HashMap<t, @Impl>>
 }
@@ -875,7 +863,6 @@ pub fn mk_ctxt(s: session::Session,
         supertraits: HashMap(),
         destructor_for_type: HashMap(),
         destructors: HashMap(),
-        value_modes: HashMap(),
         trait_impls: HashMap()
      }
 }
@@ -2170,7 +2157,14 @@ pub fn type_kind_ext(cx: ctxt, ty: t, allow_ty_var: bool) -> Kind {
       }
 
       ty_param(p) => {
-        param_bounds_to_kind(cx.ty_param_bounds.get(p.def_id.node))
+          // We only ever ask for the kind of types that are defined in the
+          // current crate; therefore, the only type parameters that could be
+          // in scope are those defined in the current crate.  If this
+          // assertion failures, it is likely because of a failure in the
+          // cross-crate inlining code to translate a def-id.
+          assert p.def_id.crate == ast::local_crate;
+
+          param_bounds_to_kind(cx.ty_param_bounds.get(p.def_id.node))
       }
 
       // self is a special type parameter that can only appear in traits; it
@@ -2925,7 +2919,12 @@ pub fn pat_ty(cx: ctxt, pat: @ast::pat) -> t {
 
 // Returns the type of an expression as a monotype.
 //
-// NB: This type doesn't provide type parameter substitutions; e.g. if you
+// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
+// some cases, we insert `AutoAdjustment` annotations such as auto-deref or
+// auto-ref.  The type returned by this function does not consider such
+// adjustments.  See `expr_ty_adjusted()` instead.
+//
+// NB (2): This type doesn't provide type parameter substitutions; e.g. if you
 // ask for the type of "id" in "id(3)", it will return "fn(&int) -> int"
 // instead of "fn(t) -> T with T = int". If this isn't what you want, see
 // expr_ty_params_and_ty() below.
@@ -2933,6 +2932,112 @@ pub fn expr_ty(cx: ctxt, expr: @ast::expr) -> t {
     return node_id_to_type(cx, expr.id);
 }
 
+pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t {
+    /*!
+     *
+     * Returns the type of `expr`, considering any `AutoAdjustment`
+     * entry recorded for that expression.
+     *
+     * It would almost certainly be better to store the adjusted ty in with
+     * the `AutoAdjustment`, but I opted not to do this because it would
+     * require serializing and deserializing the type and, although that's not
+     * hard to do, I just hate that code so much I didn't want to touch it
+     * unless it was to fix it properly, which seemed a distraction from the
+     * task at hand! -nmatsakis
+     */
+
+    let unadjusted_ty = expr_ty(cx, expr);
+
+    return match cx.adjustments.find(expr.id) {
+        None => unadjusted_ty,
+
+        Some(adj) => {
+            let mut adjusted_ty = unadjusted_ty;
+
+            for uint::range(0, adj.autoderefs) |i| {
+                match ty::deref(cx, adjusted_ty, true) {
+                    Some(mt) => { adjusted_ty = mt.ty; }
+                    None => {
+                        cx.sess.span_bug(
+                            expr.span,
+                            fmt!("The %uth autoderef failed: %s",
+                                 i, ty_to_str(cx,
+                                              adjusted_ty)));
+                    }
+                }
+            }
+
+            match adj.autoref {
+                None => adjusted_ty,
+                Some(ref autoref) => {
+                    match autoref.kind {
+                        AutoPtr => {
+                            mk_rptr(cx, autoref.region,
+                                    mt {ty: adjusted_ty,
+                                        mutbl: autoref.mutbl})
+                        }
+
+                        AutoBorrowVec => {
+                            borrow_vec(cx, expr, autoref, adjusted_ty)
+                        }
+
+                        AutoBorrowVecRef => {
+                            adjusted_ty = borrow_vec(cx, expr, autoref,
+                                                     adjusted_ty);
+                            mk_rptr(cx, autoref.region,
+                                    mt {ty: adjusted_ty, mutbl: ast::m_imm})
+                        }
+
+                        AutoBorrowFn => {
+                            borrow_fn(cx, expr, autoref, adjusted_ty)
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    fn borrow_vec(cx: ctxt, expr: @ast::expr,
+                  autoref: &AutoRef, ty: ty::t) -> ty::t {
+        match get(ty).sty {
+            ty_evec(mt, _) => {
+                ty::mk_evec(cx, mt {ty: mt.ty, mutbl: autoref.mutbl},
+                            vstore_slice(autoref.region))
+            }
+
+            ty_estr(_) => {
+                ty::mk_estr(cx, vstore_slice(autoref.region))
+            }
+
+            ref s => {
+                cx.sess.span_bug(
+                    expr.span,
+                    fmt!("borrow-vec associated with bad sty: %?",
+                         s));
+            }
+        }
+    }
+
+    fn borrow_fn(cx: ctxt, expr: @ast::expr,
+                 autoref: &AutoRef, ty: ty::t) -> ty::t {
+        match get(ty).sty {
+            ty_fn(ref fty) => {
+                ty::mk_fn(cx, FnTyBase {meta: FnMeta {proto: ProtoBorrowed,
+                                                      region: autoref.region,
+                                                      ..copy fty.meta},
+                                        sig: copy fty.sig})
+            }
+
+            ref s => {
+                cx.sess.span_bug(
+                    expr.span,
+                    fmt!("borrow-fn associated with bad sty: %?",
+                         s));
+            }
+        }
+    }
+}
+
 pub fn expr_ty_params_and_ty(cx: ctxt,
                              expr: @ast::expr)
                           -> {params: ~[t], ty: t} {
@@ -3060,7 +3165,6 @@ pub fn expr_kind(tcx: ctxt,
         ast::expr_do_body(*) |
         ast::expr_block(*) |
         ast::expr_copy(*) |
-        ast::expr_unary_move(*) |
         ast::expr_repeat(*) |
         ast::expr_lit(@ast::spanned {node: lit_str(_), _}) |
         ast::expr_vstore(_, ast::expr_vstore_slice) |
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index 38788ac0d8d..33250c294e0 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -381,7 +381,7 @@ pub fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
             demand::eqtype(fcx, pat.span, region_ty, typ);
           }
           // otherwise the type of x is the expected type T
-          ast::bind_by_value | ast::bind_by_move | ast::bind_infer => {
+          ast::bind_by_copy | ast::bind_infer => {
             demand::eqtype(fcx, pat.span, expected, typ);
           }
         }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index e360d8e7c88..f13de691a69 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -78,7 +78,6 @@ type parameter).
 
 use core::prelude::*;
 
-use middle::capture;
 use middle::const_eval;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
@@ -1454,7 +1453,7 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         match ast_util::binop_to_method_name(op) {
           Some(ref name) => {
             match lookup_op_method(fcx, ex, lhs_expr, lhs_resolved_t,
-                                   fcx.tcx().sess.ident_of((*name)),
+                                   fcx.tcx().sess.ident_of(copy *name),
                                    ~[rhs], DoDerefArgs) {
               Some(pair) => return pair,
               _ => ()
@@ -1488,9 +1487,11 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
     fn check_user_unop(fcx: @fn_ctxt, op_str: ~str, mname: ~str,
                        ex: @ast::expr,
                        rhs_expr: @ast::expr, rhs_t: ty::t) -> ty::t {
-        match lookup_op_method(fcx, ex, rhs_expr, rhs_t,
-                               fcx.tcx().sess.ident_of(mname), ~[],
-                               DontDerefArgs) {
+        match lookup_op_method(
+            fcx, ex, rhs_expr, rhs_t,
+            fcx.tcx().sess.ident_of(/*bad*/ copy mname), ~[],
+            DontDerefArgs)
+        {
           Some((ret_ty, _)) => ret_ty,
           _ => {
               fcx.type_error_message(ex.span, |actual| {
@@ -2132,7 +2133,7 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
         bot = check_expr_has_type(fcx, e, ty::mk_bool(tcx));
         fcx.write_nil(id);
       }
-      ast::expr_copy(a) | ast::expr_unary_move(a) => {
+      ast::expr_copy(a) => {
         bot = check_expr_with_opt_hint(fcx, a, expected);
         fcx.write_ty(id, fcx.expr_ty(a));
       }
@@ -2163,15 +2164,13 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
       ast::expr_match(discrim, ref arms) => {
         bot = _match::check_match(fcx, expr, discrim, (/*bad*/copy *arms));
       }
-      ast::expr_fn(proto, ref decl, ref body, cap_clause) => {
+      ast::expr_fn(proto, ref decl, ref body) => {
         check_expr_fn(fcx, expr, Some(proto),
                       decl, (*body), Vanilla, expected);
-        capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
-      ast::expr_fn_block(ref decl, ref body, cap_clause) => {
+      ast::expr_fn_block(ref decl, ref body) => {
         check_expr_fn(fcx, expr, None,
                       decl, (*body), Vanilla, expected);
-        capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
       ast::expr_loop_body(b) => {
         // a loop body is the special argument to a `for` loop.  We know that
@@ -2234,7 +2233,7 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
               }
         };
         match b.node {
-                ast::expr_fn_block(ref decl, ref body, cap_clause) => {
+                ast::expr_fn_block(ref decl, ref body) => {
                     // If an error occurred, we pretend this isn't a for
                     // loop, so as to assign types to all nodes while also
                     // propagating ty_err throughout so as to suppress
@@ -2246,7 +2245,6 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
                     check_expr_fn(fcx, b, None,
                                   decl, *body, fn_kind, Some(inner_ty));
                     demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
-                    capture::check_capture_clause(tcx, b.id, cap_clause);
                 }
                 // argh
                 _ => fail ~"expr_fn_block"
@@ -2283,11 +2281,10 @@ pub fn check_expr_with_unifier(fcx: @fn_ctxt,
               }
         };
         match b.node {
-          ast::expr_fn_block(ref decl, ref body, cap_clause) => {
+          ast::expr_fn_block(ref decl, ref body) => {
             check_expr_fn(fcx, b, None,
                           decl, *body, DoBlock, Some(inner_ty));
             demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
-            capture::check_capture_clause(tcx, b.id, cap_clause);
           }
           // argh
           _ => fail ~"expected fn ty"
@@ -3052,7 +3049,7 @@ pub fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
       ~"size_of" |
       ~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint(ccx.tcx)),
       ~"init" => (1u, ~[], param(ccx, 0u)),
-      ~"forget" => (1u, ~[arg(ast::by_move, param(ccx, 0u))],
+      ~"forget" => (1u, ~[arg(ast::by_copy, param(ccx, 0u))],
                     ty::mk_nil(tcx)),
       ~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
                               param(ccx, 1u)),
@@ -3062,7 +3059,7 @@ pub fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
           (1u, ~[arg(ast::by_copy,
                      ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),
                                      param(ccx, 0u))),
-               arg(ast::by_move, param(ccx, 0u))],
+               arg(ast::by_copy, param(ccx, 0u))],
          ty::mk_nil(tcx))
       }
       ~"needs_drop" => (1u, ~[], ty::mk_bool(tcx)),
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index abc79c8af0e..ae8574f8d1e 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -710,7 +710,6 @@ pub mod guarantor {
             ast::expr_do_body(*) |
             ast::expr_block(*) |
             ast::expr_copy(*) |
-            ast::expr_unary_move(*) |
             ast::expr_repeat(*) |
             ast::expr_vec(*) => {
                 assert !ty::expr_is_lval(
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 3548125a39e..85db1fd6e10 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -606,10 +606,10 @@ pub fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
                         ty::ty_uniq(mt) => {
                             // Ensure that the trait vstore and the pointer
                             // type match.
-                            match (ty::get(ty).sty, vstore) {
-                                (ty::ty_box(_), ty::vstore_box) |
-                                (ty::ty_uniq(_), ty::vstore_uniq) |
-                                (ty::ty_rptr(*), ty::vstore_slice(*)) => {
+                            match (&ty::get(ty).sty, vstore) {
+                                (&ty::ty_box(_), ty::vstore_box) |
+                                (&ty::ty_uniq(_), ty::vstore_uniq) |
+                                (&ty::ty_rptr(*), ty::vstore_slice(*)) => {
                                     let location_info =
                                         &location_info_for_expr(ex);
                                     let vtable_opt =
@@ -634,8 +634,8 @@ pub fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
 
                                     // Now, if this is &trait, we need to link
                                     // the regions.
-                                    match (ty::get(ty).sty, vstore) {
-                                        (ty::ty_rptr(ra, _),
+                                    match (&ty::get(ty).sty, vstore) {
+                                        (&ty::ty_rptr(ra, _),
                                          ty::vstore_slice(rb)) => {
                                             infer::mk_subr(fcx.infcx(),
                                                            false,
@@ -646,7 +646,7 @@ pub fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
                                         _ => {}
                                     }
                                 }
-                                (ty::ty_box(_), _) => {
+                                (&ty::ty_box(_), _) => {
                                     fcx.ccx.tcx.sess.span_err(ex.span,
                                                               ~"must cast \
                                                                 a boxed \
@@ -655,7 +655,7 @@ pub fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
                                                                 trait");
                                     err = true;
                                 }
-                                (ty::ty_rptr(*), _) => {
+                                (&ty::ty_rptr(*), _) => {
                                     fcx.ccx.tcx.sess.span_err(ex.span,
                                                               ~"must cast \
                                                                 a borrowed \
@@ -663,7 +663,7 @@ pub fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
                                                                 a borrowed \
                                                                 trait");
                                 }
-                                (ty::ty_uniq(*), _) => {
+                                (&ty::ty_uniq(*), _) => {
                                     fcx.ccx.tcx.sess.span_err(ex.span,
                                                               ~"must cast \
                                                                 a unique \
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index a72dfc0a934..8fe9b140406 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -165,7 +165,7 @@ fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
     resolve_method_map_entry(wbcx.fcx, e.span, e.id);
     resolve_method_map_entry(wbcx.fcx, e.span, e.callee_id);
     match e.node {
-      ast::expr_fn_block(ref decl, _, _) => {
+      ast::expr_fn_block(ref decl, _) => {
           for vec::each(decl.inputs) |input| {
               let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
 
diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs
index 5ea7937845d..4f7bedd8149 100644
--- a/src/librustc/middle/typeck/infer/lattice.rs
+++ b/src/librustc/middle/typeck/infer/lattice.rs
@@ -362,11 +362,11 @@ pub fn super_lattice_tys<L:LatticeDir TyLatticeDir Combine>(
 
     let tcx = self.infcx().tcx;
 
-    match (ty::get(a).sty, ty::get(b).sty) {
-        (ty::ty_bot, _) => { return self.ty_bot(b); }
-        (_, ty::ty_bot) => { return self.ty_bot(a); }
+    match (&ty::get(a).sty, &ty::get(b).sty) {
+        (&ty::ty_bot, _) => { return self.ty_bot(b); }
+        (_, &ty::ty_bot) => { return self.ty_bot(a); }
 
-        (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
+        (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
             let r = if_ok!(lattice_vars(self, a_id, b_id,
                                         |x, y| self.tys(*x, *y)));
             return match r {
@@ -375,12 +375,12 @@ pub fn super_lattice_tys<L:LatticeDir TyLatticeDir Combine>(
             };
         }
 
-        (ty::ty_infer(TyVar(a_id)), _) => {
+        (&ty::ty_infer(TyVar(a_id)), _) => {
             return lattice_var_and_t(self, a_id, &b,
                                      |x, y| self.tys(*x, *y));
         }
 
-        (_, ty::ty_infer(TyVar(b_id))) => {
+        (_, &ty::ty_infer(TyVar(b_id))) => {
             return lattice_var_and_t(self, b_id, &a,
                                      |x, y| self.tys(*x, *y));
         }
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index 158cbb41abd..2e30bdc5888 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -106,25 +106,25 @@ pub impl Sub: Combine {
                a.inf_str(self.infcx), b.inf_str(self.infcx));
         if a == b { return Ok(a); }
         let _indenter = indenter();
-        match (ty::get(a).sty, ty::get(b).sty) {
-            (ty::ty_bot, _) => {
+        match (&ty::get(a).sty, &ty::get(b).sty) {
+            (&ty::ty_bot, _) => {
                 Ok(a)
             }
 
-            (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
+            (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
                 if_ok!(self.var_sub_var(a_id, b_id));
                 Ok(a)
             }
-            (ty::ty_infer(TyVar(a_id)), _) => {
+            (&ty::ty_infer(TyVar(a_id)), _) => {
                 if_ok!(self.var_sub_t(a_id, b));
                 Ok(a)
             }
-            (_, ty::ty_infer(TyVar(b_id))) => {
+            (_, &ty::ty_infer(TyVar(b_id))) => {
                 if_ok!(self.t_sub_var(a, b_id));
                 Ok(a)
             }
 
-            (_, ty::ty_bot) => {
+            (_, &ty::ty_bot) => {
                 Err(ty::terr_sorts(expected_found(&self, a, b)))
             }
 
diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc
index 738665abb25..71a4600f4ad 100644
--- a/src/librustc/rustc.rc
+++ b/src/librustc/rustc.rc
@@ -91,14 +91,13 @@ pub mod middle {
     pub mod liveness;
     pub mod kind;
     pub mod freevars;
-    pub mod capture;
     pub mod pat_util;
     pub mod region;
     pub mod const_eval;
     pub mod astencode;
     pub mod lang_items;
     pub mod privacy;
-    pub mod mode;
+    pub mod moves;
 }
 
 pub mod front {
@@ -221,9 +220,9 @@ pub fn run_compiler(args: &~[~str], demitter: diagnostic::emitter) {
 
     let matches =
         &match getopts::groups::getopts(args, optgroups()) {
-          Ok(ref m) => (*m),
-          Err(ref f) => {
-            early_error(demitter, getopts::fail_str((*f)))
+          Ok(m) => m,
+          Err(f) => {
+            early_error(demitter, getopts::fail_str(f));
           }
         };
 
@@ -375,7 +374,7 @@ pub fn monitor(+f: fn~(diagnostic::emitter)) {
 }
 
 pub fn main() {
-    let mut args = os::args();
+    let args = os::args();
     do monitor |move args, demitter| {
         run_compiler(&args, demitter);
     }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index fbbcc904160..10d49ad4b0f 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -421,8 +421,15 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
       }
       ty_infer(infer_ty) => infer_ty.to_str(),
       ty_err => ~"[type error]",
-      ty_param(param_ty {idx: id, _}) => {
-        ~"'" + str::from_bytes(~[('a' as u8) + (id as u8)])
+      ty_param(param_ty {idx: id, def_id: did}) => {
+          if cx.sess.verbose() {
+              fmt!("'%s:%?",
+                   str::from_bytes(~[('a' as u8) + (id as u8)]),
+                   did)
+          } else {
+              fmt!("'%s",
+                   str::from_bytes(~[('a' as u8) + (id as u8)]))
+          }
       }
       ty_self => ~"self",
       ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs
index f8fa3ccd3d9..f3826af6cae 100644
--- a/src/librustdoc/attr_pass.rs
+++ b/src/librustdoc/attr_pass.rs
@@ -166,20 +166,27 @@ fn fold_enum(
     doc::EnumDoc {
         variants: do par::map(doc.variants) |variant| {
             let variant = copy *variant;
-            let desc = do astsrv::exec(srv) |ctxt, copy variant| {
-                match ctxt.ast_map.get(doc_id) {
-                  ast_map::node_item(@ast::item {
-                    node: ast::item_enum(ref enum_definition, _), _
-                  }, _) => {
-                    let ast_variant = option::get(
-                        vec::find(enum_definition.variants, |v| {
-                            to_str(v.node.name) == variant.name
-                        }));
-
-                    attr_parser::parse_desc(copy ast_variant.node.attrs)
-                  }
-                  _ => fail fmt!("Enum variant %s has id that's not bound \
-                         to an enum item", variant.name)
+            let desc = {
+                let variant = copy variant;
+                do astsrv::exec(srv) |ctxt| {
+                    match ctxt.ast_map.get(doc_id) {
+                        ast_map::node_item(@ast::item {
+                            node: ast::item_enum(ref enum_definition, _), _
+                        }, _) => {
+                            let ast_variant = option::get(
+                                vec::find(enum_definition.variants, |v| {
+                                    to_str(v.node.name) == variant.name
+                                }));
+
+                            attr_parser::parse_desc(
+                                copy ast_variant.node.attrs)
+                        }
+                        _ => {
+                            fail fmt!("Enum variant %s has id that's \
+                                       not bound to an enum item",
+                                      variant.name)
+                        }
+                    }
                 }
             };
 
diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs
index 9cb74a522a7..6b04903601c 100644
--- a/src/librustdoc/desc_to_brief_pass.rs
+++ b/src/librustdoc/desc_to_brief_pass.rs
@@ -26,6 +26,7 @@ use pass::Pass;
 
 use core::str;
 use core::vec;
+use core::util;
 use std::par;
 
 pub fn mk_pass() -> Pass {
@@ -194,8 +195,8 @@ fn paragraphs(s: ~str) -> ~[~str] {
         } else {
             if whitespace_lines > 0 {
                 if !accum.is_empty() {
-                    res += ~[accum];
-                    accum = ~"";
+                    let v = util::replace(&mut accum, ~"");
+                    res.push(v);
                 }
             }
 
diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs
index 0c5a31ea7ed..c5db7685080 100644
--- a/src/librustdoc/markdown_index_pass.rs
+++ b/src/librustdoc/markdown_index_pass.rs
@@ -102,10 +102,11 @@ fn item_to_entry(
     let link = match doc {
       doc::ModTag(_) | doc::NmodTag(_)
       if config.output_style == config::DocPerMod => {
-        markdown_writer::make_filename(config, doc::ItemPage(doc)).to_str()
+        markdown_writer::make_filename(config,
+                                       doc::ItemPage(copy doc)).to_str()
       }
       _ => {
-        ~"#" + pandoc_header_id(markdown_pass::header_text(doc))
+        ~"#" + pandoc_header_id(markdown_pass::header_text(copy doc))
       }
     };
 
diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs
index 6bd461d1f92..359d0097165 100644
--- a/src/librustdoc/markdown_pass.rs
+++ b/src/librustdoc/markdown_pass.rs
@@ -291,12 +291,13 @@ pub fn header_text(doc: doc::ItemTag) -> ~str {
             fmt!("of `%s` for `%s`", ImplDoc.trait_types[0],
                  (&ImplDoc.self_ty).get())
         };
-        fmt!("%s %s", header_kind, desc)
-      }
-      _ => {
-        header_text_(header_kind(doc), header_name(doc))
+        return fmt!("%s %s", header_kind, desc);
       }
+      _ => {}
     }
+
+    header_text_(header_kind(copy doc),
+                 header_name(doc))
 }
 
 fn header_text_(kind: &str, name: &str) -> ~str {
diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs
index f276854c4ec..d5c4dda6d95 100644
--- a/src/librustdoc/text_pass.rs
+++ b/src/librustdoc/text_pass.rs
@@ -73,7 +73,7 @@ fn fold_item(
 }
 
 fn apply_to_sections(
-    op: NominalOp<Op>,
+    +op: NominalOp<Op>,
     sections: ~[doc::Section]
 ) -> ~[doc::Section] {
     par::map(sections, |section, copy op| doc::Section {
@@ -115,7 +115,8 @@ fn apply_to_methods(
     op: NominalOp<Op>,
     docs: ~[doc::MethodDoc]
 ) -> ~[doc::MethodDoc] {
-    do par::map(docs) |doc, copy op| {
+    let op = copy op;
+    do par::map(docs) |doc| {
         doc::MethodDoc {
             brief: maybe_apply_op(copy op, &doc.brief),
             desc: maybe_apply_op(copy op, &doc.desc),
diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs
index f790c37e6ea..016c554be27 100644
--- a/src/librustdoc/tystr_pass.rs
+++ b/src/librustdoc/tystr_pass.rs
@@ -103,16 +103,18 @@ fn fold_const(
     let srv = fold.ctxt;
 
     doc::SimpleItemDoc {
-        sig: Some(do astsrv::exec(srv) |copy doc, ctxt| {
-            match ctxt.ast_map.get(doc.id()) {
-              ast_map::node_item(@ast::item {
-                node: ast::item_const(ty, _), _
-              }, _) => {
-                pprust::ty_to_str(ty, extract::interner())
-              }
-              _ => fail ~"fold_const: id not bound to a const item"
-            }
-        }),
+        sig: Some({
+            let doc = copy doc;
+            do astsrv::exec(srv) |ctxt| {
+                match ctxt.ast_map.get(doc.id()) {
+                    ast_map::node_item(@ast::item {
+                        node: ast::item_const(ty, _), _
+                    }, _) => {
+                        pprust::ty_to_str(ty, extract::interner())
+                    }
+                    _ => fail ~"fold_const: id not bound to a const item"
+                }
+            }}),
         .. doc
     }
 }
@@ -132,26 +134,29 @@ fn fold_enum(
 
     doc::EnumDoc {
         variants: do par::map(doc.variants) |variant| {
-            let variant = copy *variant;
-            let sig = do astsrv::exec(srv) |copy variant, ctxt| {
-                match ctxt.ast_map.get(doc_id) {
-                  ast_map::node_item(@ast::item {
-                    node: ast::item_enum(ref enum_definition, _), _
-                  }, _) => {
-                    let ast_variant =
-                        do vec::find(enum_definition.variants) |v| {
-                            to_str(v.node.name) == variant.name
-                        }.get();
-
-                    pprust::variant_to_str(ast_variant, extract::interner())
-                  }
-                  _ => fail ~"enum variant not bound to an enum item"
+            let sig = {
+                let variant = copy *variant;
+                do astsrv::exec(srv) |copy variant, ctxt| {
+                    match ctxt.ast_map.get(doc_id) {
+                        ast_map::node_item(@ast::item {
+                            node: ast::item_enum(ref enum_definition, _), _
+                        }, _) => {
+                            let ast_variant =
+                                do vec::find(enum_definition.variants) |v| {
+                                to_str(v.node.name) == variant.name
+                            }.get();
+
+                            pprust::variant_to_str(
+                                ast_variant, extract::interner())
+                        }
+                        _ => fail ~"enum variant not bound to an enum item"
+                    }
                 }
             };
 
             doc::VariantDoc {
                 sig: Some(sig),
-                .. variant
+                .. copy *variant
             }
         },
         .. doc
@@ -262,18 +267,22 @@ fn fold_impl(
 
     let srv = fold.ctxt;
 
-    let (trait_types, self_ty) = do astsrv::exec(srv) |copy doc, ctxt| {
-        match ctxt.ast_map.get(doc.id()) {
-          ast_map::node_item(@ast::item {
-            node: ast::item_impl(_, opt_trait_type, self_ty, _), _
-          }, _) => {
-            let trait_types = opt_trait_type.map_default(~[], |p| {
-                ~[pprust::path_to_str(p.path, extract::interner())]
-            });
-            (trait_types, Some(pprust::ty_to_str(self_ty,
-                                                 extract::interner())))
-          }
-          _ => fail ~"expected impl"
+    let (trait_types, self_ty) = {
+        let doc = copy doc;
+        do astsrv::exec(srv) |ctxt| {
+            match ctxt.ast_map.get(doc.id()) {
+                ast_map::node_item(@ast::item {
+                    node: ast::item_impl(_, opt_trait_type, self_ty, _), _
+                }, _) => {
+                    let trait_types = opt_trait_type.map_default(~[], |p| {
+                        ~[pprust::path_to_str(p.path, extract::interner())]
+                    });
+                    (trait_types,
+                     Some(pprust::ty_to_str(
+                         self_ty, extract::interner())))
+                }
+                _ => fail ~"expected impl"
+            }
         }
     };
 
@@ -318,20 +327,25 @@ fn fold_type(
     let srv = fold.ctxt;
 
     doc::SimpleItemDoc {
-        sig: do astsrv::exec(srv) |copy doc, ctxt| {
-            match ctxt.ast_map.get(doc.id()) {
-              ast_map::node_item(@ast::item {
-                ident: ident,
-                node: ast::item_ty(ty, ref params), _
-              }, _) => {
-                Some(fmt!(
-                    "type %s%s = %s",
-                    to_str(ident),
-                    pprust::typarams_to_str(*params, extract::interner()),
-                    pprust::ty_to_str(ty, extract::interner())
-                ))
-              }
-              _ => fail ~"expected type"
+        sig: {
+            let doc = copy doc;
+            do astsrv::exec(srv) |ctxt| {
+                match ctxt.ast_map.get(doc.id()) {
+                    ast_map::node_item(@ast::item {
+                        ident: ident,
+                        node: ast::item_ty(ty, ref params), _
+                    }, _) => {
+                        Some(fmt!(
+                            "type %s%s = %s",
+                            to_str(ident),
+                            pprust::typarams_to_str(*params,
+                                                    extract::interner()),
+                            pprust::ty_to_str(ty,
+                                              extract::interner())
+                        ))
+                    }
+                    _ => fail ~"expected type"
+                }
             }
         },
         .. doc
@@ -351,14 +365,17 @@ fn fold_struct(
     let srv = fold.ctxt;
 
     doc::StructDoc {
-        sig: do astsrv::exec(srv) |copy doc, ctxt| {
-            match ctxt.ast_map.get(doc.id()) {
-                ast_map::node_item(item, _) => {
-                    let item = strip_struct_extra_stuff(item);
-                    Some(pprust::item_to_str(item,
-                                             extract::interner()))
+        sig: {
+            let doc = copy doc;
+            do astsrv::exec(srv) |ctxt| {
+                match ctxt.ast_map.get(doc.id()) {
+                    ast_map::node_item(item, _) => {
+                        let item = strip_struct_extra_stuff(item);
+                        Some(pprust::item_to_str(item,
+                                                 extract::interner()))
+                    }
+                    _ => fail ~"not an item"
                 }
-                _ => fail ~"not an item"
             }
         },
         .. doc
diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs
index f032d19271d..e108643790e 100644
--- a/src/libstd/flatpipes.rs
+++ b/src/libstd/flatpipes.rs
@@ -788,13 +788,14 @@ mod test {
         // The main task will wait until the test is over to proceed
         let (finish_port, finish_chan) = pipes::stream();
 
-        let addr = ip::v4::parse_addr("127.0.0.1");
+        let addr0 = ip::v4::parse_addr("127.0.0.1");
 
         let begin_connect_chan = Cell(move begin_connect_chan);
         let accept_chan = Cell(move accept_chan);
 
         // The server task
-        do task::spawn |copy addr, move begin_connect_chan,
+        let addr = copy addr0;
+        do task::spawn |move begin_connect_chan,
                         move accept_chan| {
             let iotask = &uv::global_loop::get();
             let begin_connect_chan = begin_connect_chan.take();
@@ -821,7 +822,8 @@ mod test {
         }
 
         // Client task
-        do task::spawn |copy addr, move begin_connect_port,
+        let addr = copy addr0;
+        do task::spawn |move begin_connect_port,
                         move writer_chan| {
 
             // Wait for the server to start listening
diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs
index 839d0d23a61..2447c2eb530 100644
--- a/src/libstd/net_ip.rs
+++ b/src/libstd/net_ip.rs
@@ -117,8 +117,9 @@ enum IpGetAddrErr {
 pub fn get_addr(node: &str, iotask: &iotask)
     -> result::Result<~[IpAddr], IpGetAddrErr> {
     let (output_po, output_ch) = stream();
-    let output_ch = SharedChan(output_ch);
+    let mut output_ch = Some(SharedChan(output_ch));
     do str::as_buf(node) |node_ptr, len| {
+        let output_ch = output_ch.swap_unwrap();
         unsafe {
             log(debug, fmt!("slice len %?", len));
             let handle = create_uv_getaddrinfo_t();
diff --git a/src/libstd/par.rs b/src/libstd/par.rs
index 04d88af1100..779dda0ab29 100644
--- a/src/libstd/par.rs
+++ b/src/libstd/par.rs
@@ -59,7 +59,8 @@ fn map_slices<A: Copy Owned, B: Copy Owned>(
             let end = uint::min(len, base + items_per_task);
             do vec::as_imm_buf(xs) |p, _len| {
                 let f = f();
-                let f = do future_spawn() |move f, copy base| {
+                let base = base;
+                let f = do future_spawn() |move f| {
                     unsafe {
                         let len = end - base;
                         let slice = (ptr::offset(p, base),
@@ -94,7 +95,8 @@ fn map_slices<A: Copy Owned, B: Copy Owned>(
 pub fn map<A: Copy Owned, B: Copy Owned>(
     xs: &[A], f: fn~(&A) -> B) -> ~[B] {
     vec::concat(map_slices(xs, || {
-        fn~(_base: uint, slice : &[A], copy f) -> ~[B] {
+        let f = copy f;
+        fn~(_base: uint, slice : &[A]) -> ~[B] {
             vec::map(slice, |x| f(x))
         }
     }))
@@ -104,6 +106,7 @@ pub fn map<A: Copy Owned, B: Copy Owned>(
 pub fn mapi<A: Copy Owned, B: Copy Owned>(xs: &[A],
                                     f: fn~(uint, &A) -> B) -> ~[B] {
     let slices = map_slices(xs, || {
+        let f = copy f;
         fn~(base: uint, slice : &[A], copy f) -> ~[B] {
             vec::mapi(slice, |i, x| {
                 f(i + base, x)
@@ -141,6 +144,7 @@ pub fn mapi_factory<A: Copy Owned, B: Copy Owned>(
 /// Returns true if the function holds for all elements in the vector.
 pub fn alli<A: Copy Owned>(xs: &[A], f: fn~(uint, &A) -> bool) -> bool {
     do vec::all(map_slices(xs, || {
+        let f = copy f;
         fn~(base: uint, slice : &[A], copy f) -> bool {
             vec::alli(slice, |i, x| {
                 f(i + base, x)
@@ -152,6 +156,7 @@ pub fn alli<A: Copy Owned>(xs: &[A], f: fn~(uint, &A) -> bool) -> bool {
 /// Returns true if the function holds for any elements in the vector.
 pub fn any<A: Copy Owned>(xs: &[A], f: fn~(&A) -> bool) -> bool {
     do vec::any(map_slices(xs, || {
+        let f = copy f;
         fn~(_base : uint, slice: &[A], copy f) -> bool {
             vec::any(slice, |x| f(x))
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 0b250c2e421..435e514df44 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -337,9 +337,9 @@ pub struct field_pat {
 
 #[auto_encode]
 #[auto_decode]
+#[deriving_eq]
 pub enum binding_mode {
-    bind_by_value,
-    bind_by_move,
+    bind_by_copy,
     bind_by_ref(mutability),
     bind_infer
 }
@@ -347,51 +347,17 @@ pub enum binding_mode {
 pub impl binding_mode : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
         match *self {
-          bind_by_value => 0u8.iter_bytes(lsb0, f),
-
-          bind_by_move => 1u8.iter_bytes(lsb0, f),
+          bind_by_copy => 0u8.iter_bytes(lsb0, f),
 
           bind_by_ref(ref m) =>
-          to_bytes::iter_bytes_2(&2u8, m, lsb0, f),
+          to_bytes::iter_bytes_2(&1u8, m, lsb0, f),
 
           bind_infer =>
-          3u8.iter_bytes(lsb0, f),
+          2u8.iter_bytes(lsb0, f),
         }
     }
 }
 
-pub impl binding_mode : cmp::Eq {
-    pure fn eq(&self, other: &binding_mode) -> bool {
-        match (*self) {
-            bind_by_value => {
-                match (*other) {
-                    bind_by_value => true,
-                    _ => false
-                }
-            }
-            bind_by_move => {
-                match (*other) {
-                    bind_by_move => true,
-                    _ => false
-                }
-            }
-            bind_by_ref(e0a) => {
-                match (*other) {
-                    bind_by_ref(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            bind_infer => {
-                match (*other) {
-                    bind_infer => true,
-                    _ => false
-                }
-            }
-        }
-    }
-    pure fn ne(&self, other: &binding_mode) -> bool { !(*self).eq(other) }
-}
-
 #[auto_encode]
 #[auto_decode]
 pub enum pat_ {
@@ -603,7 +569,7 @@ pub impl<T:cmp::Eq> inferable<T> : cmp::Eq {
 // "resolved" mode: the real modes.
 #[auto_encode]
 #[auto_decode]
-pub enum rmode { by_ref, by_val, by_move, by_copy }
+pub enum rmode { by_ref, by_val, by_copy }
 
 pub impl rmode : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
@@ -729,8 +695,8 @@ pub enum expr_ {
        (implicit) condition is always true. */
     expr_loop(blk, Option<ident>),
     expr_match(@expr, ~[arm]),
-    expr_fn(Proto, fn_decl, blk, capture_clause),
-    expr_fn_block(fn_decl, blk, capture_clause),
+    expr_fn(Proto, fn_decl, blk),
+    expr_fn_block(fn_decl, blk),
     // Inner expr is always an expr_fn_block. We need the wrapping node to
     // easily type this (a function returning nil on the inside but bool on
     // the outside).
@@ -740,7 +706,6 @@ pub enum expr_ {
     expr_block(blk),
 
     expr_copy(@expr),
-    expr_unary_move(@expr),
     expr_assign(@expr, @expr),
     expr_swap(@expr, @expr),
     expr_assign_op(binop, @expr, @expr),
@@ -769,20 +734,6 @@ pub enum expr_ {
     expr_paren(@expr)
 }
 
-#[auto_encode]
-#[auto_decode]
-pub struct capture_item_ {
-    id: int,
-    is_move: bool,
-    name: ident, // Currently, can only capture a local var.
-    span: span,
-}
-
-pub type capture_item = @capture_item_;
-
-pub type capture_clause = @~[capture_item];
-
-//
 // When the main rust parser encounters a syntax-extension invocation, it
 // parses the arguments to the invocation as a token-tree. This is a very
 // loose structure, such that all sorts of different AST-fragments can
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 7b742019f0e..1ae23240404 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -256,7 +256,7 @@ pub fn ident_to_path(s: span, +i: ident) -> @path {
 
 pub fn ident_to_pat(id: node_id, s: span, +i: ident) -> @pat {
     @ast::pat { id: id,
-                node: pat_ident(bind_by_value, ident_to_path(s, i), None),
+                node: pat_ident(bind_by_copy, ident_to_path(s, i), None),
                 span: s }
 }
 
@@ -503,11 +503,8 @@ pub fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
                     vfn(m.self_id);
                     for vec::each(tps) |tp| { vfn(tp.id); }
                 }
-                visit::fk_anon(_, capture_clause) |
-                visit::fk_fn_block(capture_clause) => {
-                    for vec::each(*capture_clause) |clause| {
-                        vfn(clause.id);
-                    }
+                visit::fk_anon(_) |
+                visit::fk_fn_block => {
                 }
             }
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 60b1b98915f..dd6a996b730 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -173,8 +173,8 @@ pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
  * Returns true if a list of meta items contains another meta item. The
  * comparison is performed structurally.
  */
-pub fn contains(haystack: ~[@ast::meta_item], needle: @ast::meta_item)
-             -> bool {
+pub fn contains(haystack: &[@ast::meta_item],
+                needle: @ast::meta_item) -> bool {
     for haystack.each |item| {
         if eq(*item, needle) { return true; }
     }
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index e4ad518cc80..a2484e2d6df 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -569,7 +569,7 @@ fn mk_ser_method(
         pat: @ast::pat {
             id: cx.next_id(),
             node: ast::pat_ident(
-                ast::bind_by_value,
+                ast::bind_by_copy,
                 ast_util::ident_to_path(span, cx.ident_of(~"__s")),
                 None),
             span: span,
@@ -633,7 +633,7 @@ fn mk_deser_method(
         pat: @ast::pat {
             id: cx.next_id(),
             node: ast::pat_ident(
-                ast::bind_by_value,
+                ast::bind_by_copy,
                 ast_util::ident_to_path(span, cx.ident_of(~"__d")),
                 None),
             span: span,
@@ -1095,7 +1095,7 @@ fn mk_enum_deser_body(
                     pat: @ast::pat {
                         id: cx.next_id(),
                         node: ast::pat_ident(
-                            ast::bind_by_value,
+                            ast::bind_by_copy,
                             ast_util::ident_to_path(span, cx.ident_of(~"i")),
                             None),
                         span: span,
@@ -1114,8 +1114,7 @@ fn mk_enum_deser_body(
                     span,
                     ast::expr_match(cx.expr_var(span, ~"i"), arms)
                 )
-            ),
-            @~[]
+            )
         )
     );
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index d4da5a2034e..6d44a412742 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -203,7 +203,7 @@ pub fn mk_local(cx: ext_ctxt, sp: span, mutbl: bool,
     let pat = @ast::pat {
         id: cx.next_id(),
         node: ast::pat_ident(
-            ast::bind_by_value,
+            ast::bind_by_copy,
             mk_raw_path(sp, ~[ident]),
             None),
         span: sp,
@@ -279,9 +279,8 @@ pub fn mk_pat(cx: ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat {
 }
 pub fn mk_pat_ident(cx: ext_ctxt,
                     span: span,
-                    ident: ast::ident)
-                 -> @ast::pat {
-    mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_value)
+                    ident: ast::ident) -> @ast::pat {
+    mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_copy)
 }
 pub fn mk_pat_ident_with_binding_mode(cx: ext_ctxt,
                                       span: span,
diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs
index a85898390a4..8abca3d97f9 100644
--- a/src/libsyntax/ext/pipes/ast_builder.rs
+++ b/src/libsyntax/ext/pipes/ast_builder.rs
@@ -105,7 +105,6 @@ pub trait ext_ctxt_ast_builder {
     fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt;
     fn stmt_expr(e: @ast::expr) -> @ast::stmt;
     fn block_expr(b: ast::blk) -> @ast::expr;
-    fn move_expr(e: @ast::expr) -> @ast::expr;
     fn ty_option(ty: @ast::Ty) -> @ast::Ty;
     fn ty_infer() -> @ast::Ty;
     fn ty_nil_ast_builder() -> @ast::Ty;
@@ -130,15 +129,6 @@ pub impl ext_ctxt: ext_ctxt_ast_builder {
         }
     }
 
-    fn move_expr(e: @ast::expr) -> @ast::expr {
-        @expr {
-            id: self.next_id(),
-            callee_id: self.next_id(),
-            node: ast::expr_unary_move(e),
-            span: e.span,
-        }
-    }
-
     fn stmt_expr(e: @ast::expr) -> @ast::stmt {
         @spanned { node: ast::stmt_expr(e, self.next_id()),
                    span: dummy_sp()}
@@ -205,7 +195,7 @@ pub impl ext_ctxt: ext_ctxt_ast_builder {
             pat: @ast::pat {
                 id: self.next_id(),
                 node: ast::pat_ident(
-                    ast::bind_by_value,
+                    ast::bind_by_copy,
                     ast_util::ident_to_path(dummy_sp(), name),
                     None),
                 span: dummy_sp(),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index e8557558f17..2c2ecb91e21 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -466,30 +466,17 @@ pub fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
             expr_match(fld.fold_expr(expr),
                      vec::map((*arms), |x| fld.fold_arm(*x)))
           }
-          expr_fn(proto, decl, ref body, captures) => {
-            let captures = do captures.map |cap_item| {
-                @ast::capture_item_ {
-                    id: fld.new_id(cap_item.id),
-                    ..**cap_item
-                }
-            };
-            expr_fn(proto, fold_fn_decl(decl, fld),
-                    fld.fold_block((*body)),
-                    @captures)
+          expr_fn(proto, decl, ref body) => {
+            expr_fn(proto,
+                    fold_fn_decl(decl, fld),
+                    fld.fold_block(*body))
           }
-          expr_fn_block(decl, ref body, captures) => {
-            let captures = do captures.map |cap_item| {
-                @ast::capture_item_ {
-                    id: fld.new_id(cap_item.id),
-                    ..**cap_item
-                }
-            };
-            expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block((*body)),
-                          @captures)
+          expr_fn_block(decl, ref body) => {
+            expr_fn_block(fold_fn_decl(decl, fld),
+                          fld.fold_block(*body))
           }
           expr_block(ref blk) => expr_block(fld.fold_block((*blk))),
           expr_copy(e) => expr_copy(fld.fold_expr(e)),
-          expr_unary_move(e) => expr_unary_move(fld.fold_expr(e)),
           expr_assign(el, er) => {
             expr_assign(fld.fold_expr(el), fld.fold_expr(er))
           }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d41fedebde3..81393310cda 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -13,9 +13,9 @@ use core::prelude::*;
 use ast::{ProtoBox, ProtoUniq, RegionTyParamBound, TraitTyParamBound};
 use ast::{provided, public, pure_fn, purity, re_static};
 use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer};
-use ast::{bind_by_value, bind_by_move, bitand, bitor, bitxor, blk};
-use ast::{blk_check_mode, box, by_copy, by_move, by_ref, by_val};
-use ast::{capture_clause, capture_item, crate, crate_cfg, decl, decl_item};
+use ast::{bind_by_copy, bitand, bitor, bitxor, blk};
+use ast::{blk_check_mode, box, by_copy, by_ref, by_val};
+use ast::{crate, crate_cfg, decl, decl_item};
 use ast::{decl_local, default_blk, deref, div, enum_def, enum_variant_kind};
 use ast::{expl, expr, expr_, expr_addr_of, expr_match, expr_again};
 use ast::{expr_assert, expr_assign, expr_assign_op, expr_binary, expr_block};
@@ -24,7 +24,7 @@ use ast::{expr_fail, expr_field, expr_fn, expr_fn_block, expr_if, expr_index};
 use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
 use ast::{expr_method_call, expr_paren, expr_path, expr_rec, expr_repeat};
 use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
-use ast::{expr_unary_move, expr_vec, expr_vstore, expr_vstore_mut_box};
+use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
 use ast::{expr_vstore_fixed, expr_vstore_slice, expr_vstore_box};
 use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
 use ast::{expr_vstore_uniq, TyFn, Onceness, Once, Many};
@@ -102,7 +102,7 @@ enum restriction {
 enum class_contents { dtor_decl(blk, ~[attribute], codemap::span),
                       members(~[@struct_field]) }
 
-type arg_or_capture_item = Either<arg, capture_item>;
+type arg_or_capture_item = Either<arg, ()>;
 type item_info = (ident, item_, Option<~[attribute]>);
 
 pub enum item_or_view_item {
@@ -401,7 +401,7 @@ pub impl Parser {
 
             let tps = p.parse_ty_params();
 
-            let (self_ty, d, _) = do self.parse_fn_decl_with_self() |p| {
+            let (self_ty, d) = do self.parse_fn_decl_with_self() |p| {
                 // This is somewhat dubious; We don't want to allow argument
                 // names to be left off if there is a definition...
                 either::Left(p.parse_arg_general(false))
@@ -651,7 +651,7 @@ pub impl Parser {
 
     fn parse_arg_mode() -> mode {
         if self.eat(token::BINOP(token::MINUS)) {
-            expl(by_move)
+            expl(by_copy) // NDM outdated syntax
         } else if self.eat(token::ANDAND) {
             expl(by_ref)
         } else if self.eat(token::BINOP(token::PLUS)) {
@@ -689,23 +689,12 @@ pub impl Parser {
     }
 
     fn parse_capture_item_or(parse_arg_fn: fn(Parser) -> arg_or_capture_item)
-        -> arg_or_capture_item {
-
-        fn parse_capture_item(p:Parser, is_move: bool) -> capture_item {
-            let sp = mk_sp(p.span.lo, p.span.hi);
-            let ident = p.parse_ident();
-            @ast::capture_item_ {
-                id: p.get_id(),
-                is_move: is_move,
-                name: ident,
-                span: sp,
-            }
-        }
-
-        if self.eat_keyword(~"move") {
-            either::Right(parse_capture_item(self, true))
-        } else if self.eat_keyword(~"copy") {
-            either::Right(parse_capture_item(self, false))
+        -> arg_or_capture_item
+    {
+        if self.eat_keyword(~"move") || self.eat_keyword(~"copy") {
+            // XXX outdated syntax now that moves-based-on-type has gone in
+            self.parse_ident();
+            either::Right(())
         } else {
             parse_arg_fn(self)
         }
@@ -1078,9 +1067,8 @@ pub impl Parser {
             ex = expr_copy(e);
             hi = e.span.hi;
         } else if self.eat_keyword(~"move") {
-            let e = self.parse_expr();
-            ex = expr_unary_move(e);
-            hi = e.span.hi;
+            // XXX move keyword is no longer important, remove after snapshot
+            return self.parse_expr();
         } else if self.token == token::MOD_SEP ||
             is_ident(self.token) && !self.is_keyword(~"true") &&
             !self.is_keyword(~"false") {
@@ -1576,12 +1564,10 @@ pub impl Parser {
 
         // if we want to allow fn expression argument types to be inferred in
         // the future, just have to change parse_arg to parse_fn_block_arg.
-        let (decl, capture_clause) =
-            self.parse_fn_decl(|p| p.parse_arg_or_capture_item());
+        let decl = self.parse_fn_decl(|p| p.parse_arg_or_capture_item());
 
         let body = self.parse_block();
-        return self.mk_expr(lo, body.span.hi,
-                         expr_fn(proto, decl, body, capture_clause));
+        return self.mk_expr(lo, body.span.hi,expr_fn(proto, decl, body));
     }
 
     // `|args| { ... }` like in `do` expressions
@@ -1594,18 +1580,15 @@ pub impl Parser {
                   }
                   _ => {
                     // No argument list - `do foo {`
-                    (
-                        ast::fn_decl {
-                            inputs: ~[],
-                            output: @Ty {
-                                id: self.get_id(),
-                                node: ty_infer,
-                                span: self.span
-                            },
-                            cf: return_val
-                        },
-                        @~[]
-                    )
+                      ast::fn_decl {
+                          inputs: ~[],
+                          output: @Ty {
+                              id: self.get_id(),
+                              node: ty_infer,
+                              span: self.span
+                          },
+                          cf: return_val
+                      }
                   }
                 }
             },
@@ -1621,10 +1604,10 @@ pub impl Parser {
                                 || self.parse_expr())
     }
 
-    fn parse_lambda_expr_(parse_decl: fn&() -> (fn_decl, capture_clause),
+    fn parse_lambda_expr_(parse_decl: fn&() -> fn_decl,
                           parse_body: fn&() -> @expr) -> @expr {
         let lo = self.last_span.lo;
-        let (decl, captures) = parse_decl();
+        let decl = parse_decl();
         let body = parse_body();
         let fakeblock = ast::blk_ {
             view_items: ~[],
@@ -1636,7 +1619,7 @@ pub impl Parser {
         let fakeblock = spanned(body.span.lo, body.span.hi,
                                 fakeblock);
         return self.mk_expr(lo, body.span.hi,
-                         expr_fn_block(decl, fakeblock, captures));
+                            expr_fn_block(decl, fakeblock));
     }
 
     fn parse_else_expr() -> @expr {
@@ -2065,22 +2048,16 @@ pub impl Parser {
                 let mutbl = self.parse_mutability();
                 pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl));
             } else if self.eat_keyword(~"copy") {
-                pat = self.parse_pat_ident(refutable, bind_by_value);
-            } else if self.eat_keyword(~"move") {
-                pat = self.parse_pat_ident(refutable, bind_by_move);
+                pat = self.parse_pat_ident(refutable, bind_by_copy);
             } else {
-                let binding_mode;
-                // XXX: Aren't these two cases deadcode? -- bblum
-                if self.eat_keyword(~"copy") {
-                    binding_mode = bind_by_value;
-                } else if self.eat_keyword(~"move") {
-                    binding_mode = bind_by_move;
-                } else if refutable {
-                    binding_mode = bind_infer;
-                } else {
-                    binding_mode = bind_by_value;
+                if self.eat_keyword(~"move") {
+                    /* XXX---remove move keyword */
                 }
 
+                // XXX---refutable match bindings should work same as let
+                let binding_mode =
+                    if refutable {bind_infer} else {bind_by_copy};
+
                 let cannot_be_enum_or_struct;
                 match self.look_ahead(1) {
                     token::LPAREN | token::LBRACKET | token::LT |
@@ -2560,25 +2537,21 @@ pub impl Parser {
     }
 
     fn parse_fn_decl(parse_arg_fn: fn(Parser) -> arg_or_capture_item)
-        -> (fn_decl, capture_clause) {
-
+        -> fn_decl
+    {
         let args_or_capture_items: ~[arg_or_capture_item] =
             self.parse_unspanned_seq(
                 token::LPAREN, token::RPAREN,
                 seq_sep_trailing_disallowed(token::COMMA), parse_arg_fn);
 
         let inputs = either::lefts(args_or_capture_items);
-        let capture_clause = @either::rights(args_or_capture_items);
 
         let (ret_style, ret_ty) = self.parse_ret_ty();
-        (
-            ast::fn_decl {
-                inputs: inputs,
-                output: ret_ty,
-                cf: ret_style,
-            },
-            capture_clause
-        )
+        ast::fn_decl {
+            inputs: inputs,
+            output: ret_ty,
+            cf: ret_style,
+        }
     }
 
     fn is_self_ident() -> bool {
@@ -2598,8 +2571,8 @@ pub impl Parser {
     }
 
     fn parse_fn_decl_with_self(parse_arg_fn:
-                                    fn(Parser) -> arg_or_capture_item)
-                            -> (self_ty, fn_decl, capture_clause) {
+                               fn(Parser) -> arg_or_capture_item)
+                            -> (self_ty, fn_decl) {
 
         fn maybe_parse_self_ty(cnstr: fn(+v: mutability) -> ast::self_ty_,
                                p: Parser) -> ast::self_ty_ {
@@ -2675,7 +2648,6 @@ pub impl Parser {
         let hi = self.span.hi;
 
         let inputs = either::lefts(args_or_capture_items);
-        let capture_clause = @either::rights(args_or_capture_items);
         let (ret_style, ret_ty) = self.parse_ret_ty();
 
         let fn_decl = ast::fn_decl {
@@ -2684,10 +2656,10 @@ pub impl Parser {
             cf: ret_style
         };
 
-        (spanned(lo, hi, self_ty), fn_decl, capture_clause)
+        (spanned(lo, hi, self_ty), fn_decl)
     }
 
-    fn parse_fn_block_decl() -> (fn_decl, capture_clause) {
+    fn parse_fn_block_decl() -> fn_decl {
         let inputs_captures = {
             if self.eat(token::OROR) {
                 ~[]
@@ -2704,14 +2676,11 @@ pub impl Parser {
             @Ty { id: self.get_id(), node: ty_infer, span: self.span }
         };
 
-        (
-            ast::fn_decl {
-                inputs: either::lefts(inputs_captures),
-                output: output,
-                cf: return_val,
-            },
-            @either::rights(inputs_captures)
-        )
+        ast::fn_decl {
+            inputs: either::lefts(inputs_captures),
+            output: output,
+            cf: return_val,
+        }
     }
 
     fn parse_fn_header() -> {ident: ident, tps: ~[ty_param]} {
@@ -2733,7 +2702,7 @@ pub impl Parser {
 
     fn parse_item_fn(purity: purity) -> item_info {
         let t = self.parse_fn_header();
-        let (decl, _) = self.parse_fn_decl(|p| p.parse_arg());
+        let decl = self.parse_fn_decl(|p| p.parse_arg());
         let (inner_attrs, body) = self.parse_inner_attrs_and_block(true);
         (t.ident, item_fn(decl, purity, t.tps, body), Some(inner_attrs))
     }
@@ -2753,7 +2722,7 @@ pub impl Parser {
         let pur = self.parse_fn_purity();
         let ident = self.parse_method_name();
         let tps = self.parse_ty_params();
-        let (self_ty, decl, _) = do self.parse_fn_decl_with_self() |p| {
+        let (self_ty, decl) = do self.parse_fn_decl_with_self() |p| {
             p.parse_arg()
         };
         // XXX: interaction between staticness, self_ty is broken now
@@ -3262,7 +3231,7 @@ pub impl Parser {
         let vis = self.parse_visibility();
         let purity = self.parse_fn_purity();
         let t = self.parse_fn_header();
-        let (decl, _) = self.parse_fn_decl(|p| p.parse_arg());
+        let decl = self.parse_fn_decl(|p| p.parse_arg());
         let mut hi = self.span.hi;
         self.expect(token::SEMI);
         @ast::foreign_item { ident: t.ident,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7f03158a4df..39fb98aea26 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1305,24 +1305,24 @@ pub fn print_expr(s: ps, &&expr: @ast::expr) {
         }
         bclose_(s, expr.span, match_indent_unit);
       }
-      ast::expr_fn(proto, decl, ref body, cap_clause) => {
+      ast::expr_fn(proto, decl, ref body) => {
         // containing cbox, will be closed by print-block at }
         cbox(s, indent_unit);
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
         print_fn_header_info(s, None, None, ast::Many,
                              Some(proto), ast::inherited);
-        print_fn_args_and_ret(s, decl, *cap_clause, None);
+        print_fn_args_and_ret(s, decl, None);
         space(s.s);
         print_block(s, (*body));
       }
-      ast::expr_fn_block(decl, ref body, cap_clause) => {
+      ast::expr_fn_block(decl, ref body) => {
         // in do/for blocks we don't want to show an empty
         // argument list, but at this point we don't know which
         // we are inside.
         //
         // if !decl.inputs.is_empty() {
-        print_fn_block_args(s, decl, *cap_clause);
+        print_fn_block_args(s, decl);
         space(s.s);
         // }
         assert (*body).node.stmts.is_empty();
@@ -1357,10 +1357,6 @@ pub fn print_expr(s: ps, &&expr: @ast::expr) {
         print_block(s, (*blk));
       }
       ast::expr_copy(e) => { word_space(s, ~"copy"); print_expr(s, e); }
-      ast::expr_unary_move(e) => {
-          word_space(s, ~"move");
-          print_expr(s, e);
-      }
       ast::expr_assign(lhs, rhs) => {
         print_expr(s, lhs);
         space(s.s);
@@ -1554,10 +1550,7 @@ pub fn print_pat(s: ps, &&pat: @ast::pat, refutable: bool) {
                       word_nbsp(s, ~"ref");
                       print_mutability(s, mutbl);
                   }
-                  ast::bind_by_move => {
-                      word_nbsp(s, ~"move");
-                  }
-                  ast::bind_by_value => {
+                  ast::bind_by_copy => {
                       word_nbsp(s, ~"copy");
                   }
                   ast::bind_infer => {}
@@ -1693,16 +1686,14 @@ pub fn print_fn(s: ps,
     nbsp(s);
     print_ident(s, name);
     print_type_params(s, typarams);
-    print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
+    print_fn_args_and_ret(s, decl, opt_self_ty);
 }
 
 pub fn print_fn_args(s: ps, decl: ast::fn_decl,
-                     cap_items: ~[ast::capture_item],
-                     opt_self_ty: Option<ast::self_ty_>) {
-    // It is unfortunate to duplicate the commasep logic, but we
-    // we want the self type, the args, and the capture clauses all
-    // in the same box.
-    box(s, 0, inconsistent);
+                 opt_self_ty: Option<ast::self_ty_>) {
+    // It is unfortunate to duplicate the commasep logic, but we we want the
+    // self type and the args all in the same box.
+    box(s, 0u, inconsistent);
     let mut first = true;
     for opt_self_ty.each |self_ty| {
         first = !print_self_ty(s, *self_ty);
@@ -1713,21 +1704,13 @@ pub fn print_fn_args(s: ps, decl: ast::fn_decl,
         print_arg(s, *arg);
     }
 
-    for cap_items.each |cap_item| {
-        if first { first = false; } else { word_space(s, ~","); }
-        if cap_item.is_move { word_nbsp(s, ~"move") }
-        else { word_nbsp(s, ~"copy") }
-        print_ident(s, cap_item.name);
-    }
-
     end(s);
 }
 
 pub fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl,
-                             cap_items: ~[ast::capture_item],
                              opt_self_ty: Option<ast::self_ty_>) {
     popen(s);
-    print_fn_args(s, decl, cap_items, opt_self_ty);
+    print_fn_args(s, decl, opt_self_ty);
     pclose(s);
 
     maybe_print_comment(s, decl.output.span.lo);
@@ -1741,10 +1724,9 @@ pub fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl,
     }
 }
 
-pub fn print_fn_block_args(s: ps, decl: ast::fn_decl,
-                           cap_items: ~[ast::capture_item]) {
+pub fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
     word(s.s, ~"|");
-    print_fn_args(s, decl, cap_items, None);
+    print_fn_args(s, decl, None);
     word(s.s, ~"|");
 
     match decl.output.node {
@@ -1761,10 +1743,9 @@ pub fn print_fn_block_args(s: ps, decl: ast::fn_decl,
 
 pub fn mode_to_str(m: ast::mode) -> ~str {
     match m {
-      ast::expl(ast::by_move) => ~"-",
       ast::expl(ast::by_ref) => ~"&&",
-      ast::expl(ast::by_val) => ~"++",
       ast::expl(ast::by_copy) => ~"+",
+      ast::expl(ast::by_val) => ~"++",
       ast::infer(_) => ~""
     }
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 196ee349b79..dd7f274b5ba 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -32,8 +32,8 @@ pub enum vt<E> { mk_vt(visitor<E>), }
 pub enum fn_kind {
     fk_item_fn(ident, ~[ty_param], purity), //< an item declared with fn()
     fk_method(ident, ~[ty_param], @method),
-    fk_anon(Proto, capture_clause),  //< an anonymous function like fn@(...)
-    fk_fn_block(capture_clause),     //< a block {||...}
+    fk_anon(Proto),    //< an anonymous function like fn@(...)
+    fk_fn_block,       //< a block {||...}
     fk_dtor(~[ty_param], ~[attribute], node_id /* self id */,
             def_id /* parent class id */) // class destructor
 
@@ -457,12 +457,12 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
         (v.visit_expr)(x, e, v);
         for (*arms).each |a| { (v.visit_arm)(*a, e, v); }
       }
-      expr_fn(proto, decl, ref body, cap_clause) => {
-        (v.visit_fn)(fk_anon(proto, cap_clause), decl, (*body),
+      expr_fn(proto, decl, ref body) => {
+        (v.visit_fn)(fk_anon(proto), decl, (*body),
                      ex.span, ex.id, e, v);
       }
-      expr_fn_block(decl, ref body, cap_clause) => {
-        (v.visit_fn)(fk_fn_block(cap_clause), decl, (*body),
+      expr_fn_block(decl, ref body) => {
+        (v.visit_fn)(fk_fn_block, decl, (*body),
                      ex.span, ex.id, e, v);
       }
       expr_block(ref b) => (v.visit_block)((*b), e, v),
@@ -471,7 +471,6 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
         (v.visit_expr)(a, e, v);
       }
       expr_copy(a) => (v.visit_expr)(a, e, v),
-      expr_unary_move(a) => (v.visit_expr)(a, e, v),
       expr_swap(a, b) => { (v.visit_expr)(a, e, v); (v.visit_expr)(b, e, v); }
       expr_assign_op(_, a, b) => {
         (v.visit_expr)(b, e, v);
diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs
index 5ae2996f39e..9667c1d82d8 100644
--- a/src/test/bench/graph500-bfs.rs
+++ b/src/test/bench/graph500-bfs.rs
@@ -377,7 +377,8 @@ fn validate(edges: ~[(node_id, node_id)],
 
     log(info, ~"Verifying tree and graph edges...");
 
-    let status = do par::alli(tree) |u, v, copy edges| {
+    let edges = copy edges;
+    let status = do par::alli(tree) |u, v| {
         let u = u as node_id;
         if *v == -1i64 || u == root {
             true
diff --git a/src/test/compile-fail/alt-vec-tail-move.rs b/src/test/compile-fail/alt-vec-tail-move.rs
deleted file mode 100644
index cd85cb19778..00000000000
--- a/src/test/compile-fail/alt-vec-tail-move.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn main() {
-    let a = [mut 1, 2, 3, 4];
-    let _ = match a {
-        [1, 2, ..move tail] => tail,
-        _ => core::util::unreachable()
-    };
-    a[0] = 0; //~ ERROR: use of moved value
-}
diff --git a/src/test/compile-fail/block-deinitializes-upvar.rs b/src/test/compile-fail/block-deinitializes-upvar.rs
deleted file mode 100644
index 366cf5a48ea..00000000000
--- a/src/test/compile-fail/block-deinitializes-upvar.rs
+++ /dev/null
@@ -1,18 +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.
-
-// error-pattern:moving out of captured outer immutable variable in a stack closure
-fn force(f: fn()) { f(); }
-fn main() {
-    let mut x = @{x: 17, y: 2};
-    let y = @{x: 5, y: 5};
-
-    force(|| x = move y );
-}
diff --git a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs
index 0b236b986e1..50bedc57340 100644
--- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs
+++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs
@@ -13,18 +13,18 @@ fn borrow(v: &int, f: fn(x: &int)) {
 }
 
 fn box_imm() {
-    let mut v = ~3;
-    let _w = &mut v; //~ NOTE loan of mutable local variable granted here
-    do task::spawn |move v| {
-        //~^ ERROR moving out of mutable local variable prohibited due to outstanding loan
+    let v = ~3;
+    let _w = &v; //~ NOTE loan of immutable local variable granted here
+    do task::spawn {
         debug!("v=%d", *v);
+        //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan
     }
 
-    let mut v = ~3;
-    let _w = &mut v; //~ NOTE loan of mutable local variable granted here
-    task::spawn(fn~(move v) {
-        //~^ ERROR moving out of mutable local variable prohibited due to outstanding loan
+    let v = ~3;
+    let _w = &v; //~ NOTE loan of immutable local variable granted here
+    task::spawn(fn~() {
         debug!("v=%d", *v);
+        //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan
     });
 }
 
diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs
new file mode 100644
index 00000000000..d80c56eb64f
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-by-capture.rs
@@ -0,0 +1,18 @@
+extern mod std;
+
+use std::ebml::reader;
+use std::ebml::writer;
+use std::serialize;
+
+fn main() {
+    let foo = ~3;
+    let _pfoo = &foo;
+    let _f: @fn() -> int = || *foo + 5;
+    //~^ ERROR by-move capture
+
+    let bar = ~3;
+    let _g = || {
+        let _h: @fn() -> int = || *bar;
+        //~^ ERROR illegal by-move capture
+    };
+}
diff --git a/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs
new file mode 100644
index 00000000000..941883f80f9
--- /dev/null
+++ b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs
@@ -0,0 +1,8 @@
+fn main() {
+    let a = [mut 1, 2, 3, 4];
+    let _ = match a {
+        [1, 2, ..tail] => tail,
+        _ => core::util::unreachable()
+    };
+    a[0] = 0; //~ ERROR: assigning to mutable vec content prohibited due to outstanding loan
+}
diff --git a/src/test/compile-fail/cap-clause-both-copy-and-move.rs b/src/test/compile-fail/cap-clause-both-copy-and-move.rs
deleted file mode 100644
index 174715807ec..00000000000
--- a/src/test/compile-fail/cap-clause-both-copy-and-move.rs
+++ /dev/null
@@ -1,15 +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.
-
-// error-pattern:variable `x` captured more than once
-fn main() {
-    let x = 5;
-    let y = fn~(move x, copy x) -> int { x };
-}
diff --git a/src/test/compile-fail/cap-clause-double-copy.rs b/src/test/compile-fail/cap-clause-double-copy.rs
deleted file mode 100644
index 5c083821538..00000000000
--- a/src/test/compile-fail/cap-clause-double-copy.rs
+++ /dev/null
@@ -1,15 +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.
-
-// error-pattern:variable `x` captured more than once
-fn main() {
-    let x = 5;
-    let y = fn~(copy x, copy x) -> int { x };
-}
diff --git a/src/test/compile-fail/cap-clause-double-move.rs b/src/test/compile-fail/cap-clause-double-move.rs
deleted file mode 100644
index d87d0804e99..00000000000
--- a/src/test/compile-fail/cap-clause-double-move.rs
+++ /dev/null
@@ -1,15 +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.
-
-// error-pattern:variable `x` captured more than once
-fn main() {
-    let x = 5;
-    let y = fn~(move x, move x) -> int { x };
-}
diff --git a/src/test/compile-fail/cap-clause-illegal-cap.rs b/src/test/compile-fail/cap-clause-illegal-cap.rs
deleted file mode 100644
index 46a858a7cb2..00000000000
--- a/src/test/compile-fail/cap-clause-illegal-cap.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.
-
-// error-pattern: copying a noncopyable value
-
-struct foo { x: int, }
-
-impl foo : Drop {
-    fn finalize(&self) {}
-}
-
-fn foo(x: int) -> foo {
-    foo {
-        x: x
-    }
-}
-
-fn to_lambda2(b: foo) -> fn@(uint) -> uint {
-    // test case where copy clause specifies a value that is not used
-    // in fn@ body, but value is illegal to copy:
-    return fn@(u: uint, copy b) -> uint { 22u };
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/cap-clause-move-upvar.rs b/src/test/compile-fail/cap-clause-move-upvar.rs
deleted file mode 100644
index 255a17ac426..00000000000
--- a/src/test/compile-fail/cap-clause-move-upvar.rs
+++ /dev/null
@@ -1,17 +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.
-
-fn main() {
-    let x = 5;
-    let _y = fn~(move x) -> int {
-        let _z = fn~(move x) -> int { x }; //~ ERROR moving out of captured outer variable in a heap closure
-        22
-    };
-}
diff --git a/src/test/compile-fail/cap-clause-unresolved-copy.rs b/src/test/compile-fail/cap-clause-unresolved-copy.rs
deleted file mode 100644
index 3d38008c675..00000000000
--- a/src/test/compile-fail/cap-clause-unresolved-copy.rs
+++ /dev/null
@@ -1,16 +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.
-
-// error-pattern:unresolved name
-fn main() {
-    let x = 5;
-    let y = fn~(copy z, copy x) {
-    };
-}
diff --git a/src/test/compile-fail/cap-clause-unresolved-move.rs b/src/test/compile-fail/cap-clause-unresolved-move.rs
deleted file mode 100644
index ada8b0d001b..00000000000
--- a/src/test/compile-fail/cap-clause-unresolved-move.rs
+++ /dev/null
@@ -1,16 +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.
-
-// error-pattern:unresolved name
-fn main() {
-    let x = 5;
-    let y = fn~(move z, move x) {
-    };
-}
diff --git a/src/test/compile-fail/cap-clause-use-after-move.rs b/src/test/compile-fail/cap-clause-use-after-move.rs
deleted file mode 100644
index 097158843a2..00000000000
--- a/src/test/compile-fail/cap-clause-use-after-move.rs
+++ /dev/null
@@ -1,15 +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.
-
-fn main() {
-    let x = 5;
-    let _y = fn~(move x) { }; //~ WARNING captured variable `x` not used in closure
-    let _z = x; //~ ERROR use of moved value: `x`
-}
diff --git a/src/test/compile-fail/cap-clause-with-stack-closure.rs b/src/test/compile-fail/cap-clause-with-stack-closure.rs
deleted file mode 100644
index 13d91eabcde..00000000000
--- a/src/test/compile-fail/cap-clause-with-stack-closure.rs
+++ /dev/null
@@ -1,24 +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.
-
-fn foo(_f: fn()) {}
-fn bar(_f: @int) {}
-
-fn main() {
-    let x = @3;
-    foo(|| bar(x) );
-
-    let x = @3;
-    foo(|copy x| bar(x) ); //~ ERROR cannot capture values explicitly with a block closure
-
-    let x = @3;
-    foo(|move x| bar(x) ); //~ ERROR cannot capture values explicitly with a block closure
-}
-
diff --git a/src/test/compile-fail/copy-into-closure.rs b/src/test/compile-fail/copy-into-closure.rs
deleted file mode 100644
index 21d4fa8eab8..00000000000
--- a/src/test/compile-fail/copy-into-closure.rs
+++ /dev/null
@@ -1,30 +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.
-
-fn closure2(+x: core::util::NonCopyable)
-        -> (core::util::NonCopyable, fn@() -> core::util::NonCopyable) {
-    let f = fn@(copy x) -> core::util::NonCopyable {
-        //~^ ERROR copying a noncopyable value
-        //~^^ NOTE non-copyable value cannot be copied into a @fn closure
-        copy x
-        //~^ ERROR copying a noncopyable value
-    };
-    (move x,f)
-}
-fn closure3(+x: core::util::NonCopyable) {
-    do task::spawn |copy x| {
-        //~^ ERROR copying a noncopyable value
-        //~^^ NOTE non-copyable value cannot be copied into a ~fn closure
-        error!("%?", x);
-    }
-    error!("%?", x);
-}
-fn main() {
-}
diff --git a/src/test/compile-fail/functional-struct-update.rs b/src/test/compile-fail/functional-struct-update.rs
index 98627ce73c0..c0430a6a8bb 100644
--- a/src/test/compile-fail/functional-struct-update.rs
+++ b/src/test/compile-fail/functional-struct-update.rs
@@ -25,7 +25,7 @@ struct Foo {
 
 fn main() {
     let a = Foo { x: 1, y: Bar { x: 5 } };
-    let c = Foo { x: 4, .. a}; //~ ERROR copying a noncopyable value
+    let c = Foo { x: 4, .. a}; //~ ERROR cannot copy field `y` of base expression, which has a noncopyable type
     io::println(fmt!("%?", c));
 }
 
diff --git a/src/test/compile-fail/issue-1965.rs b/src/test/compile-fail/issue-1965.rs
deleted file mode 100644
index a93b74461a1..00000000000
--- a/src/test/compile-fail/issue-1965.rs
+++ /dev/null
@@ -1,17 +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.
-
-// error-pattern:moving out of captured outer immutable variable in a stack closure
-fn test(-x: uint) {}
-
-fn main() {
-    let i = 3;
-    for uint::range(0, 10) |_x| {test(move i)}
-}
diff --git a/src/test/compile-fail/kindck-implicit-close-over-mut-var.rs b/src/test/compile-fail/kindck-implicit-close-over-mut-var.rs
index 5a0a964b717..c2732d383ab 100644
--- a/src/test/compile-fail/kindck-implicit-close-over-mut-var.rs
+++ b/src/test/compile-fail/kindck-implicit-close-over-mut-var.rs
@@ -31,11 +31,14 @@ fn bar() {
 }
 
 fn car() {
-    // Here, i is mutable, but *explicitly* copied:
+    // Here, i is mutable, but *explicitly* shadowed copied:
     let mut i = 0;
     while i < 10 {
-        do task::spawn |copy i| {
-            user(i);
+        {
+            let i = i;
+            do task::spawn {
+                user(i);
+            }
         }
         i += 1;
     }
diff --git a/src/test/compile-fail/unary-move.rs b/src/test/compile-fail/liveness-move-call-arg.rs
index 2afecee6e1c..ae1c086b340 100644
--- a/src/test/compile-fail/unary-move.rs
+++ b/src/test/compile-fail/liveness-move-call-arg.rs
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: use of moved value
+fn take(_x: ~int) {}
 
 fn main() {
-    let x = 3;
-    let y = move x;
-    debug!("%d", x);
-}
 
+    let x: ~int = ~25;
+    loop {
+        take(x); //~ ERROR use of moved value: `x`
+    }
+}
diff --git a/src/test/compile-fail/liveness-move-from-args.rs b/src/test/compile-fail/liveness-move-from-args.rs
index 7a44cd901b8..d6c0be9f183 100644
--- a/src/test/compile-fail/liveness-move-from-args.rs
+++ b/src/test/compile-fail/liveness-move-from-args.rs
@@ -8,22 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn take(-_x: int) { }
+fn take(_x: ~int) { }
 
-fn from_by_value_arg(++x: int) {
-    take(move x);  //~ ERROR illegal move from argument `x`, which is not copy or move mode
+fn from_by_value_arg(++x: ~int) {
+    take(x);  //~ ERROR illegal move from argument `x`, which is not copy or move mode
 }
 
-fn from_by_ref_arg(&&x: int) {
-    take(move x);  //~ ERROR illegal move from argument `x`, which is not copy or move mode
+fn from_by_ref_arg(&&x: ~int) {
+    take(x);  //~ ERROR illegal move from argument `x`, which is not copy or move mode
 }
 
-fn from_copy_arg(+x: int) {
-    take(move x);
-}
-
-fn from_move_arg(-x: int) {
-    take(move x);
+fn from_copy_arg(+x: ~int) {
+    take(x);
 }
 
 fn main() {
diff --git a/src/test/compile-fail/liveness-move-in-loop.rs b/src/test/compile-fail/liveness-move-in-loop.rs
index 0935d429966..cb9d028809e 100644
--- a/src/test/compile-fail/liveness-move-in-loop.rs
+++ b/src/test/compile-fail/liveness-move-in-loop.rs
@@ -9,19 +9,16 @@
 // except according to those terms.
 
 fn main() {
-
-    let y: int = 42;
-    let mut x: int;
+    let y: ~int = ~42;
+    let mut x: ~int;
     loop {
         log(debug, y);
         loop {
             loop {
                 loop {
 // tjc: Not sure why it prints the same error twice
-                    x = move y; //~ ERROR use of moved value
-                    //~^ NOTE move of value occurred here
-                    //~^^ ERROR use of moved value
-                    //~^^^ NOTE move of value occurred here
+                    x = y; //~ ERROR use of moved value
+                    //~^ ERROR use of moved value
 
                     copy x;
                 }
diff --git a/src/test/compile-fail/liveness-move-in-while.rs b/src/test/compile-fail/liveness-move-in-while.rs
index 9f261fdb2d1..fa8ce00fb08 100644
--- a/src/test/compile-fail/liveness-move-in-while.rs
+++ b/src/test/compile-fail/liveness-move-in-while.rs
@@ -10,15 +10,13 @@
 
 fn main() {
 
-    let y: int = 42;
-    let mut x: int;
+    let y: ~int = ~42;
+    let mut x: ~int;
     loop {
         log(debug, y);
 // tjc: not sure why it prints the same error twice
-        while true { while true { while true { x = move y; copy x; } } }
+        while true { while true { while true { x = y; copy x; } } }
         //~^ ERROR use of moved value: `y`
-        //~^^ NOTE move of value occurred here
-        //~^^^ ERROR use of moved value: `y`
-        //~^^^^ NOTE move of value occurred here
+        //~^^ ERROR use of moved value: `y`
     }
 }
diff --git a/src/test/compile-fail/liveness-use-after-move.rs b/src/test/compile-fail/liveness-use-after-move.rs
index d48cbc23e15..16518261009 100644
--- a/src/test/compile-fail/liveness-use-after-move.rs
+++ b/src/test/compile-fail/liveness-use-after-move.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 fn main() {
-    let x = @5;
-    let y = move x; //~ NOTE move of value occurred here
+    let x = ~5;
+    let y = x;
     log(debug, *x); //~ ERROR use of moved value: `x`
     copy y;
 }
diff --git a/src/test/compile-fail/liveness-use-after-send.rs b/src/test/compile-fail/liveness-use-after-send.rs
index 2a1e486d133..2746c5a304b 100644
--- a/src/test/compile-fail/liveness-use-after-send.rs
+++ b/src/test/compile-fail/liveness-use-after-send.rs
@@ -18,8 +18,8 @@ enum _chan<T> = int;
 
 // Tests that "log(debug, message);" is flagged as using
 // message after the send deinitializes it
-fn test00_start(ch: _chan<int>, message: int, _count: int) {
-    send(ch, move message); //~ NOTE move of value occurred here
+fn test00_start(ch: _chan<~int>, message: ~int, _count: ~int) {
+    send(ch, message);
     log(debug, message); //~ ERROR use of moved value: `message`
 }
 
diff --git a/src/test/compile-fail/moves-based-on-type-access-to-field.rs b/src/test/compile-fail/moves-based-on-type-access-to-field.rs
new file mode 100644
index 00000000000..663b615816d
--- /dev/null
+++ b/src/test/compile-fail/moves-based-on-type-access-to-field.rs
@@ -0,0 +1,20 @@
+// Tests that if you move from `x.f` or `x[0]`, `x` is inaccessible.
+// Also tests that we give a more specific error message.
+
+struct Foo { f: ~str, y: int }
+fn consume(_s: ~str) {}
+fn touch<A>(_a: &A) {}
+
+fn f10() {
+    let x = Foo { f: ~"hi", y: 3 };
+    consume(x.f); //~ NOTE field of `x` moved here
+    touch(&x.y); //~ ERROR use of partially moved value: `x`
+}
+
+fn f20() {
+    let x = ~[~"hi"];
+    consume(x[0]); //~ NOTE element of `x` moved here
+    touch(&x[0]); //~ ERROR use of partially moved value: `x`
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs
new file mode 100644
index 00000000000..db52a2bbe1e
--- /dev/null
+++ b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs
@@ -0,0 +1,43 @@
+// Tests that references to move-by-default values trigger moves when
+// they occur as part of various kinds of expressions.
+
+struct Foo<A> { f: A }
+fn touch<A>(_a: &A) {}
+
+fn f00() {
+    let x = ~"hi";
+    let _y = Foo { f:x }; //~ NOTE `x` moved here
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f05() {
+    let x = ~"hi";
+    let _y = Foo { f:(((x))) }; //~ NOTE `x` moved here
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f10() {
+    let x = ~"hi";
+    let _y = Foo { f:copy x };
+    touch(&x);
+}
+
+fn f20() {
+    let x = ~"hi";
+    let _y = Foo { f:copy (x) };
+    touch(&x);
+}
+
+fn f30() {
+    let x = ~"hi";
+    let _y = Foo { f:copy ((x)) };
+    touch(&x);
+}
+
+fn f40() {
+    let x = ~"hi";
+    let _y = Foo { f:(((((copy ((x))))))) };
+    touch(&x);
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/moves-based-on-type-exprs.rs b/src/test/compile-fail/moves-based-on-type-exprs.rs
new file mode 100644
index 00000000000..07fe8318836
--- /dev/null
+++ b/src/test/compile-fail/moves-based-on-type-exprs.rs
@@ -0,0 +1,95 @@
+// Tests that references to move-by-default values trigger moves when
+// they occur as part of various kinds of expressions.
+
+struct Foo<A> { f: A }
+fn guard(_s: ~str) -> bool {fail}
+fn touch<A>(_a: &A) {}
+
+fn f10() {
+    let x = ~"hi";
+    let _y = Foo { f:x };
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f20() {
+    let x = ~"hi";
+    let _y = (x, 3);
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f21() {
+    let x = ~[1, 2, 3];
+    let _y = (x[0], 3);
+    touch(&x);
+}
+
+fn f30(cond: bool) {
+    let x = ~"hi", y = ~"ho";
+    let _y = if cond {
+        x
+    } else {
+        y
+    };
+    touch(&x); //~ ERROR use of moved value: `x`
+    touch(&y); //~ ERROR use of moved value: `y`
+}
+
+fn f40(cond: bool) {
+    let x = ~"hi", y = ~"ho";
+    let _y = match cond {
+        true => x,
+        false => y
+    };
+    touch(&x); //~ ERROR use of moved value: `x`
+    touch(&y); //~ ERROR use of moved value: `y`
+}
+
+fn f50(cond: bool) {
+    let x = ~"hi", y = ~"ho";
+    let _y = match cond {
+        _ if guard(x) => 10,
+        true => 10,
+        false => 20,
+    };
+    touch(&x); //~ ERROR use of moved value: `x`
+    touch(&y);
+}
+
+fn f70() {
+    let x = ~"hi";
+    let _y = [x];
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f80() {
+    let x = ~"hi";
+    let _y = ~[x];
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f90() {
+    let x = ~"hi";
+    let _y = @[x];
+    touch(&x); //~ ERROR use of moved value: `x`
+}
+
+fn f100() {
+    let x = ~[~"hi"];
+    let _y = x[0];
+    touch(&x); //~ ERROR use of partially moved value: `x`
+}
+
+fn f110() {
+    let x = ~[~"hi"];
+    let _y = [x[0], ..1];
+    touch(&x); //~ ERROR use of partially moved value: `x`
+}
+
+fn f120() {
+    let x = ~[~"hi", ~"ho"];
+    x[0] <-> x[1];
+    touch(&x[0]);
+    touch(&x[1]);
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/liveness-move-from-mode.rs b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
index 52a59334d5c..3c15047a296 100644
--- a/src/test/compile-fail/liveness-move-from-mode.rs
+++ b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
@@ -8,13 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn take(-_x: int) {}
+fn test(_x: ~uint) {}
 
 fn main() {
-
-    let x: int = 25;
-    loop {
-        take(move x); //~ ERROR use of moved value: `x`
-        //~^ NOTE move of value occurred here
+    let i = ~3;
+    for uint::range(0, 10) |_x| {
+        test(i); //~ ERROR moving out of captured outer immutable variable in a stack closure
     }
 }
diff --git a/src/test/compile-fail/no-reuse-move-arc.rs b/src/test/compile-fail/no-reuse-move-arc.rs
index 1de8362e23a..8c33e026026 100644
--- a/src/test/compile-fail/no-reuse-move-arc.rs
+++ b/src/test/compile-fail/no-reuse-move-arc.rs
@@ -15,7 +15,7 @@ fn main() {
     let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     let arc_v = arc::ARC(v);
 
-    do task::spawn() |move arc_v| { //~ NOTE move of value occurred here
+    do task::spawn() { //~ NOTE `arc_v` moved into closure environment here
         let v = *arc::get(&arc_v);
         assert v[3] == 4;
     };
diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs
index 080f7fe3c6e..9a16ebda59d 100644
--- a/src/test/compile-fail/no-send-res-ports.rs
+++ b/src/test/compile-fail/no-send-res-ports.rs
@@ -24,12 +24,12 @@ fn main() {
             _x: x
         }
     }
-   
+
     let x = ~mut Some(foo(Port(@())));
 
-    do task::spawn |move x| { //~ ERROR not a sendable value
+    do task::spawn {
         let mut y = None;
-        *x <-> y;
+        *x <-> y; //~ ERROR not a sendable value
         log(error, y);
     }
 }
diff --git a/src/test/compile-fail/use-after-move-self.rs b/src/test/compile-fail/use-after-move-self.rs
index 8ba58cf6f66..7ad41b518a1 100644
--- a/src/test/compile-fail/use-after-move-self.rs
+++ b/src/test/compile-fail/use-after-move-self.rs
@@ -1,18 +1,18 @@
 struct S {
-    x: int
+    x: ~int
 }
 
 impl S {
     fn foo(self) -> int {
-        (move self).bar();
-        return self.x;  //~ ERROR use of moved value
+        self.bar();
+        return *self.x;  //~ ERROR use of moved value
     }
 
     fn bar(self) {}
 }
 
 fn main() {
-    let x = S { x: 1 };
+    let x = S { x: ~1 };
     io::println(x.foo().to_str());
 }
 
diff --git a/src/test/pretty/cap-clause.rs b/src/test/pretty/cap-clause.rs
deleted file mode 100644
index d8ade41257a..00000000000
--- a/src/test/pretty/cap-clause.rs
+++ /dev/null
@@ -1,27 +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.
-
-// pp-exact
-
-fn main() {
-    let x = 1;
-    let y = 2;
-    let z = 3;
-    let l1 = fn@(w: int, copy x) -> int { w + x + y };
-    let l2 = fn@(w: int, copy x, move y) -> int { w + x + y };
-    let l3 = fn@(w: int, move z) -> int { w + z };
-
-    let x = 1;
-    let y = 2;
-    let z = 3;
-    let s1 = fn~(copy x) -> int { x + y };
-    let s2 = fn~(copy x, move y) -> int { x + y };
-    let s3 = fn~(move z) -> int { z };
-}
diff --git a/src/test/run-fail/unwind-lambda.rs b/src/test/run-fail/unwind-lambda.rs
index aee6f4e480c..f2a95728237 100644
--- a/src/test/run-fail/unwind-lambda.rs
+++ b/src/test/run-fail/unwind-lambda.rs
@@ -18,6 +18,7 @@ fn main() {
         macerate(copy *tasties);
     } (carrots, |food| {
         let mush = food + cheese;
+        let cheese = copy cheese;
         let f = fn@() {
             let chew = mush + cheese;
             fail ~"so yummy"
diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs
index 28c97587898..2724684dea4 100644
--- a/src/test/run-pass/assignability-trait.rs
+++ b/src/test/run-pass/assignability-trait.rs
@@ -43,7 +43,7 @@ fn main() {
     // Call a method
     for x.iterate() |y| { assert x[*y] == *y; }
     // Call a parameterized function
-    assert length(x) == vec::len(x);
+    assert length(copy x) == vec::len(x);
     // Call a parameterized function, with type arguments that require
     // a borrow
     assert length::<int, &[int]>(x) == vec::len(x);
diff --git a/src/test/run-pass/borrowck-borrow-from-expr-block.rs b/src/test/run-pass/borrowck-borrow-from-expr-block.rs
index 93ab2ba2c41..f13d6eef136 100644
--- a/src/test/run-pass/borrowck-borrow-from-expr-block.rs
+++ b/src/test/run-pass/borrowck-borrow-from-expr-block.rs
@@ -13,8 +13,7 @@ fn borrow(x: &int, f: fn(x: &int)) {
 }
 
 fn test1(x: @~int) {
-    // Right now, at least, this induces a copy of the unique pointer:
-    do borrow({*x}) |p| {
+    do borrow(copy *x) |p| {
         let x_a = ptr::addr_of(&(**x));
         assert (x_a as uint) != ptr::to_uint(p);
         assert unsafe{*x_a} == *p;
diff --git a/src/test/run-pass/cap-clause-move.rs b/src/test/run-pass/cap-clause-move.rs
index 5ed27d92d79..a196593743f 100644
--- a/src/test/run-pass/cap-clause-move.rs
+++ b/src/test/run-pass/cap-clause-move.rs
@@ -11,29 +11,21 @@
 fn main() {
     let x = ~1;
     let y = ptr::addr_of(&(*x)) as uint;
-    let lam_copy = fn@(copy x) -> uint { ptr::addr_of(&(*x)) as uint };
     let lam_move = fn@(move x) -> uint { ptr::addr_of(&(*x)) as uint };
-    assert lam_copy() != y;
     assert lam_move() == y;
 
     let x = ~2;
     let y = ptr::addr_of(&(*x)) as uint;
-    let lam_copy: fn@() -> uint = |copy x| ptr::addr_of(&(*x)) as uint;
     let lam_move: fn@() -> uint = |move x| ptr::addr_of(&(*x)) as uint;
-    assert lam_copy() != y;
     assert lam_move() == y;
 
     let x = ~3;
     let y = ptr::addr_of(&(*x)) as uint;
-    let snd_copy = fn~(copy x) -> uint { ptr::addr_of(&(*x)) as uint };
     let snd_move = fn~(move x) -> uint { ptr::addr_of(&(*x)) as uint };
-    assert snd_copy() != y;
     assert snd_move() == y;
 
     let x = ~4;
     let y = ptr::addr_of(&(*x)) as uint;
-    let lam_copy: fn~() -> uint = |copy x| ptr::addr_of(&(*x)) as uint;
     let lam_move: fn~() -> uint = |move x| ptr::addr_of(&(*x)) as uint;
-    assert lam_copy() != y;
     assert lam_move() == y;
 }
diff --git a/src/test/run-pass/last-use-corner-cases.rs b/src/test/run-pass/last-use-corner-cases.rs
deleted file mode 100644
index 190177e53cb..00000000000
--- a/src/test/run-pass/last-use-corner-cases.rs
+++ /dev/null
@@ -1,44 +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.
-
-// xfail-fast
-#[legacy_modes];
-
-fn main() {
-    // Make sure closing over can be a last use
-    let q = ~10;
-    let addr = ptr::addr_of(&(*q));
-    let f = fn@(move q) -> *int { ptr::addr_of(&(*q)) };
-    assert addr == f();
-
-    // But only when it really is the last use
-    let q = ~20;
-    let f = fn@(copy q) -> *int { ptr::addr_of(&(*q)) };
-    assert ptr::addr_of(&(*q)) != f();
-
-    // Ensure function arguments and box arguments interact sanely.
-    fn call_me(x: fn() -> int, y: ~int) { assert x() == *y; }
-    let q = ~30;
-    call_me(|| *q, q);
-
-    // Check that no false positives are found in loops.
-    let mut q = ~40, p = 10;
-    loop {
-        let i = copy q;
-        p += *i;
-        if p > 100 { break; }
-    }
-
-    // Verify that blocks can't interfere with each other.
-    fn two_blocks(a: fn(), b: fn()) { a(); b(); a(); b(); }
-    let q = ~50;
-    two_blocks(|| { let a = copy q; assert *a == 50;},
-               || { let a = copy q; assert *a == 50;});
-}
diff --git a/src/test/run-pass/move-1-unique.rs b/src/test/run-pass/move-1-unique.rs
index e477442376e..c5d7e9783e4 100644
--- a/src/test/run-pass/move-1-unique.rs
+++ b/src/test/run-pass/move-1-unique.rs
@@ -19,8 +19,8 @@ fn test(x: bool, foo: ~Triple) -> int {
 
 fn main() {
     let x = ~Triple{x: 1, y: 2, z: 3};
-    assert (test(true, x) == 2);
-    assert (test(true, x) == 2);
-    assert (test(true, x) == 2);
+    assert (test(true, copy x) == 2);
+    assert (test(true, copy x) == 2);
+    assert (test(true, copy x) == 2);
     assert (test(false, x) == 5);
 }
diff --git a/src/test/run-pass/move-3-unique.rs b/src/test/run-pass/move-3-unique.rs
index e16955f31e8..5bf5654320a 100644
--- a/src/test/run-pass/move-3-unique.rs
+++ b/src/test/run-pass/move-3-unique.rs
@@ -22,7 +22,7 @@ fn test(x: bool, foo: ~Triple) -> int {
 fn main() {
     let x = ~Triple{x: 1, y: 2, z: 3};
     for uint::range(0u, 10000u) |_i| {
-        assert (test(true, x) == 2);
+        assert (test(true, copy x) == 2);
     }
     assert (test(false, x) == 5);
 }
diff --git a/src/test/run-pass/newtype-polymorphic.rs b/src/test/run-pass/newtype-polymorphic.rs
index eef241be3d2..6eb2fcdd520 100644
--- a/src/test/run-pass/newtype-polymorphic.rs
+++ b/src/test/run-pass/newtype-polymorphic.rs
@@ -16,7 +16,7 @@ fn myvec_elt<X: Copy>(mv: myvec<X>) -> X { return mv[0]; }
 
 fn main() {
     let mv = myvec(~[1, 2, 3]);
-    assert (myvec_deref(mv)[1] == 2);
-    assert (myvec_elt(mv) == 1);
+    assert (myvec_deref(copy mv)[1] == 2);
+    assert (myvec_elt(copy mv) == 1);
     assert (mv[2] == 3);
 }
diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs
index 62415ca438d..f49a095c334 100644
--- a/src/test/run-pass/task-comm-14.rs
+++ b/src/test/run-pass/task-comm-14.rs
@@ -20,7 +20,7 @@ fn main() {
         log(debug, i);
         let (p, ch) = pipes::stream();
         po.add(move p);
-        task::spawn(|move ch, copy i| child(i, ch) );
+        task::spawn({let i = i; |move ch| child(i, ch)});
         i = i - 1;
     }
 
diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs
index 237e5da0e9e..ebbac2d1a0a 100644
--- a/src/test/run-pass/task-comm-3.rs
+++ b/src/test/run-pass/task-comm-3.rs
@@ -43,11 +43,12 @@ fn test00() {
     let mut results = ~[];
     while i < number_of_tasks {
         let ch = po.chan();
-        do task::task().future_result(|+r| {
+        task::task().future_result(|+r| {
             results.push(move r);
-        }).spawn |move ch, copy i| {
-            test00_start(ch, i, number_of_messages)
-        }
+        }).spawn({
+            let i = i;
+            |move ch| test00_start(ch, i, number_of_messages)
+        });
         i = i + 1;
     }
 
diff --git a/src/test/run-pass/task-spawn-move-and-copy.rs b/src/test/run-pass/task-spawn-move-and-copy.rs
index ef54d3c8ddb..e68d6dd7483 100644
--- a/src/test/run-pass/task-spawn-move-and-copy.rs
+++ b/src/test/run-pass/task-spawn-move-and-copy.rs
@@ -16,22 +16,11 @@ fn main() {
     let x = ~1;
     let x_in_parent = ptr::addr_of(&(*x)) as uint;
 
-    let y = ~2;
-    let y_in_parent = ptr::addr_of(&(*y)) as uint;
-
-    task::spawn(fn~(copy y, move x) {
+    task::spawn(fn~() {
         let x_in_child = ptr::addr_of(&(*x)) as uint;
         ch.send(x_in_child);
-
-        let y_in_child = ptr::addr_of(&(*y)) as uint;
-        ch.send(y_in_child);
     });
-    // Ensure last-use analysis doesn't move y to child.
-    let _q = y;
 
     let x_in_child = p.recv();
     assert x_in_parent == x_in_child;
-
-    let y_in_child = p.recv();
-    assert y_in_parent != y_in_child;
 }
diff --git a/src/test/run-pass/threads.rs b/src/test/run-pass/threads.rs
index 66e14859079..02dcebb1132 100644
--- a/src/test/run-pass/threads.rs
+++ b/src/test/run-pass/threads.rs
@@ -14,7 +14,7 @@ extern mod std;
 
 fn main() {
     let mut i = 10;
-    while i > 0 { task::spawn(|copy i| child(i) ); i = i - 1; }
+    while i > 0 { task::spawn({let i = i; || child(i)}); i = i - 1; }
     debug!("main thread exiting");
 }