about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-05-28 22:26:56 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-07-18 09:01:37 -0700
commit02adaca4dc7eb4594d8bda9a7e04bc0247fc2a74 (patch)
tree2edb47de67e3c8a0d006f61217d7dffaab824b27
parent5ddc7b4a252fbebee5f2ac87ed755139816d6823 (diff)
downloadrust-02adaca4dc7eb4594d8bda9a7e04bc0247fc2a74.tar.gz
rust-02adaca4dc7eb4594d8bda9a7e04bc0247fc2a74.zip
librustc: Implement unboxed closures with mutable receivers
-rw-r--r--src/libcore/ops.rs4
-rw-r--r--src/libcore/prelude.rs1
-rw-r--r--src/librustc/front/feature_gate.rs7
-rw-r--r--src/librustc/lint/builtin.rs3
-rw-r--r--src/librustc/metadata/common.rs18
-rw-r--r--src/librustc/metadata/encoder.rs40
-rw-r--r--src/librustc/metadata/tydecode.rs18
-rw-r--r--src/librustc/metadata/tyencode.rs6
-rw-r--r--src/librustc/middle/astencode.rs71
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs1
-rw-r--r--src/librustc/middle/cfg/construct.rs1
-rw-r--r--src/librustc/middle/check_loop.rs4
-rw-r--r--src/librustc/middle/dead.rs1
-rw-r--r--src/librustc/middle/expr_use_visitor.rs6
-rw-r--r--src/librustc/middle/freevars.rs12
-rw-r--r--src/librustc/middle/kind.rs7
-rw-r--r--src/librustc/middle/liveness.rs13
-rw-r--r--src/librustc/middle/mem_categorization.rs17
-rw-r--r--src/librustc/middle/privacy.rs3
-rw-r--r--src/librustc/middle/resolve.rs3
-rw-r--r--src/librustc/middle/save/mod.rs3
-rw-r--r--src/librustc/middle/subst.rs3
-rw-r--r--src/librustc/middle/trans/adt.rs6
-rw-r--r--src/librustc/middle/trans/base.rs311
-rw-r--r--src/librustc/middle/trans/callee.rs224
-rw-r--r--src/librustc/middle/trans/closure.rs170
-rw-r--r--src/librustc/middle/trans/common.rs12
-rw-r--r--src/librustc/middle/trans/context.rs5
-rw-r--r--src/librustc/middle/trans/debuginfo.rs12
-rw-r--r--src/librustc/middle/trans/expr.rs53
-rw-r--r--src/librustc/middle/trans/foreign.rs13
-rw-r--r--src/librustc/middle/trans/glue.rs5
-rw-r--r--src/librustc/middle/trans/intrinsic.rs10
-rw-r--r--src/librustc/middle/trans/meth.rs89
-rw-r--r--src/librustc/middle/trans/monomorphize.rs7
-rw-r--r--src/librustc/middle/trans/reflect.rs16
-rw-r--r--src/librustc/middle/trans/type_of.rs93
-rw-r--r--src/librustc/middle/ty.rs113
-rw-r--r--src/librustc/middle/ty_fold.rs7
-rw-r--r--src/librustc/middle/typeck/astconv.rs15
-rw-r--r--src/librustc/middle/typeck/check/method.rs102
-rw-r--r--src/librustc/middle/typeck/check/mod.rs67
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs4
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs114
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs43
-rw-r--r--src/librustc/middle/typeck/coherence.rs14
-rw-r--r--src/librustc/middle/typeck/collect.rs56
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs9
-rw-r--r--src/librustc/middle/typeck/mod.rs13
-rw-r--r--src/librustc/middle/typeck/variance.rs2
-rw-r--r--src/librustc/util/ppaux.rs5
-rw-r--r--src/librustc_back/svh.rs2
-rw-r--r--src/librustc_llvm/lib.rs8
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/libsyntax/abi.rs2
-rw-r--r--src/libsyntax/ast.rs13
-rw-r--r--src/libsyntax/ast_map/mod.rs8
-rw-r--r--src/libsyntax/ast_util.rs29
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs27
-rw-r--r--src/libsyntax/ext/expand.rs10
-rw-r--r--src/libsyntax/fold.rs17
-rw-r--r--src/libsyntax/parse/parser.rs119
-rw-r--r--src/libsyntax/print/pprust.rs61
-rw-r--r--src/libsyntax/visit.rs12
-rw-r--r--src/test/compile-fail/borrowck-overloaded-call.rs6
-rw-r--r--src/test/compile-fail/overloaded-calls-bad.rs2
-rw-r--r--src/test/compile-fail/overloaded-calls-nontuple.rs2
-rw-r--r--src/test/compile-fail/unboxed-closures-type-mismatch.rs19
-rw-r--r--src/test/compile-fail/unboxed-closures-vtable-mismatch.rs25
-rw-r--r--src/test/run-pass/fn-trait-sugar.rs2
-rw-r--r--src/test/run-pass/issue-14958.rs2
-rw-r--r--src/test/run-pass/issue-14959.rs2
-rw-r--r--src/test/run-pass/overloaded-calls-simple.rs16
-rw-r--r--src/test/run-pass/overloaded-calls-zero-args.rs2
-rw-r--r--src/test/run-pass/unboxed-closures-boxed.rs25
-rw-r--r--src/test/run-pass/unboxed-closures-generic.rs25
-rw-r--r--src/test/run-pass/unboxed-closures-simple.rs19
77 files changed, 1905 insertions, 384 deletions
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 53179df4cb9..8a1962c2bbd 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -749,6 +749,7 @@ pub trait DerefMut<Result>: Deref<Result> {
 #[lang="fn"]
 pub trait Fn<Args,Result> {
     /// This is called when the call operator is used.
+    #[rust_call_abi_hack]
     fn call(&self, args: Args) -> Result;
 }
 
@@ -756,6 +757,7 @@ pub trait Fn<Args,Result> {
 #[lang="fn_mut"]
 pub trait FnMut<Args,Result> {
     /// This is called when the call operator is used.
+    #[rust_call_abi_hack]
     fn call_mut(&mut self, args: Args) -> Result;
 }
 
@@ -763,5 +765,7 @@ pub trait FnMut<Args,Result> {
 #[lang="fn_once"]
 pub trait FnOnce<Args,Result> {
     /// This is called when the call operator is used.
+    #[rust_call_abi_hack]
     fn call_once(self, args: Args) -> Result;
 }
+
diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs
index d8ab89fd504..d27689eeaf4 100644
--- a/src/libcore/prelude.rs
+++ b/src/libcore/prelude.rs
@@ -35,6 +35,7 @@ pub use ops::{BitAnd, BitOr, BitXor};
 pub use ops::{Drop, Deref, DerefMut};
 pub use ops::{Shl, Shr};
 pub use ops::{Index, IndexMut};
+pub use ops::{Fn, FnMut, FnOnce};
 pub use option::{Option, Some, None};
 pub use result::{Result, Ok, Err};
 
diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs
index 8b92166388d..9f15c9a9b3f 100644
--- a/src/librustc/front/feature_gate.rs
+++ b/src/librustc/front/feature_gate.rs
@@ -67,6 +67,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     ("quad_precision_float", Removed),
 
     ("rustc_diagnostic_macros", Active),
+    ("unboxed_closures", Active),
 
     // A temporary feature gate used to enable parser extensions needed
     // to bootstrap fix for #5723.
@@ -327,6 +328,12 @@ impl<'a> Visitor<()> for Context<'a> {
             ast::ExprUnary(ast::UnBox, _) => {
                 self.gate_box(e.span);
             }
+            ast::ExprUnboxedFn(..) => {
+                self.gate_feature("unboxed_closures",
+                                  e.span,
+                                  "unboxed closures are a work-in-progress \
+                                   feature with known bugs");
+            }
             _ => {}
         }
         visit::walk_expr(self, e, ());
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index fbe4b211f97..3f4f5123699 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1451,6 +1451,9 @@ impl LintPass for Stability {
                             typeck::MethodStatic(def_id) => {
                                 def_id
                             }
+                            typeck::MethodStaticUnboxedClosure(def_id) => {
+                                def_id
+                            }
                             typeck::MethodParam(typeck::MethodParam {
                                 trait_id: trait_id,
                                 method_num: index,
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index cdeecf3a080..216a575f2fb 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -138,10 +138,11 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
     tag_table_vtable_map = 0x50,
     tag_table_adjustments = 0x51,
     tag_table_moves_map = 0x52,
-    tag_table_capture_map = 0x53
+    tag_table_capture_map = 0x53,
+    tag_table_unboxed_closure_type = 0x54,
 }
 static first_astencode_tag: uint = tag_ast as uint;
-static last_astencode_tag: uint = tag_table_capture_map as uint;
+static last_astencode_tag: uint = tag_table_unboxed_closure_type as uint;
 impl astencode_tag {
     pub fn from_uint(value : uint) -> Option<astencode_tag> {
         let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
@@ -155,6 +156,10 @@ pub static tag_item_trait_method_sort: uint = 0x60;
 
 pub static tag_item_impl_type_basename: uint = 0x61;
 
+pub static tag_crate_triple: uint = 0x66;
+
+pub static tag_dylib_dependency_formats: uint = 0x67;
+
 // Language items are a top-level directory (for speed). Hierarchy:
 //
 // tag_lang_items
@@ -199,10 +204,6 @@ pub static tag_plugin_registrar_fn: uint = 0x8b;
 pub static tag_exported_macros: uint = 0x8c;
 pub static tag_macro_def: uint = 0x8d;
 
-pub static tag_crate_triple: uint = 0x66;
-
-pub static tag_dylib_dependency_formats: uint = 0x67;
-
 pub static tag_method_argument_names: uint = 0x8e;
 pub static tag_method_argument_name: uint = 0x8f;
 
@@ -211,7 +212,6 @@ pub static tag_reachable_extern_fn_id: uint = 0x91;
 
 pub static tag_items_data_item_stability: uint = 0x92;
 
-
 #[deriving(Clone, Show)]
 pub struct LinkMeta {
     pub crate_name: String,
@@ -223,3 +223,7 @@ pub static tag_region_param_def_ident: uint = 0x91;
 pub static tag_region_param_def_def_id: uint = 0x92;
 pub static tag_region_param_def_space: uint = 0x93;
 pub static tag_region_param_def_index: uint = 0x94;
+
+pub static tag_unboxed_closures: uint = 0x95;
+pub static tag_unboxed_closure: uint = 0x96;
+pub static tag_unboxed_closure_type: uint = 0x97;
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index a3389ef86e5..b86f5ee6cc2 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -209,6 +209,18 @@ fn encode_variant_id(ebml_w: &mut Encoder, vid: DefId) {
     ebml_w.end_tag();
 }
 
+pub fn write_closure_type(ecx: &EncodeContext,
+                          ebml_w: &mut Encoder,
+                          closure_type: &ty::ClosureTy) {
+    let ty_str_ctxt = &tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_string,
+        tcx: ecx.tcx,
+        abbrevs: &ecx.type_abbrevs
+    };
+    tyencode::enc_closure_ty(ebml_w.writer, ty_str_ctxt, closure_type);
+}
+
 pub fn write_type(ecx: &EncodeContext,
                   ebml_w: &mut Encoder,
                   typ: ty::t) {
@@ -1618,6 +1630,26 @@ fn encode_macro_defs(ecx: &EncodeContext,
     ebml_w.end_tag();
 }
 
+fn encode_unboxed_closures<'a>(
+                           ecx: &'a EncodeContext,
+                           ebml_w: &'a mut Encoder) {
+    ebml_w.start_tag(tag_unboxed_closures);
+    for (unboxed_closure_id, unboxed_closure_type) in
+            ecx.tcx.unboxed_closure_types.borrow().iter() {
+        if unboxed_closure_id.krate != LOCAL_CRATE {
+            continue
+        }
+
+        ebml_w.start_tag(tag_unboxed_closure);
+        encode_def_id(ebml_w, *unboxed_closure_id);
+        ebml_w.start_tag(tag_unboxed_closure_type);
+        write_closure_type(ecx, ebml_w, unboxed_closure_type);
+        ebml_w.end_tag();
+        ebml_w.end_tag();
+    }
+    ebml_w.end_tag();
+}
+
 struct ImplVisitor<'a,'b,'c> {
     ecx: &'a EncodeContext<'b>,
     ebml_w: &'a mut Encoder<'c>,
@@ -1787,6 +1819,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
         native_lib_bytes: u64,
         plugin_registrar_fn_bytes: u64,
         macro_defs_bytes: u64,
+        unboxed_closure_bytes: u64,
         impl_bytes: u64,
         misc_bytes: u64,
         item_bytes: u64,
@@ -1801,6 +1834,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
         native_lib_bytes: 0,
         plugin_registrar_fn_bytes: 0,
         macro_defs_bytes: 0,
+        unboxed_closure_bytes: 0,
         impl_bytes: 0,
         misc_bytes: 0,
         item_bytes: 0,
@@ -1873,6 +1907,11 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
     encode_macro_defs(&ecx, krate, &mut ebml_w);
     stats.macro_defs_bytes = ebml_w.writer.tell().unwrap() - i;
 
+    // Encode the types of all unboxed closures in this crate.
+    i = ebml_w.writer.tell().unwrap();
+    encode_unboxed_closures(&ecx, &mut ebml_w);
+    stats.unboxed_closure_bytes = ebml_w.writer.tell().unwrap() - i;
+
     // Encode the def IDs of impls, for coherence checking.
     i = ebml_w.writer.tell().unwrap();
     encode_impls(&ecx, krate, &mut ebml_w);
@@ -1911,6 +1950,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
         println!("          native bytes: {}", stats.native_lib_bytes);
         println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
         println!("       macro def bytes: {}", stats.macro_defs_bytes);
+        println!(" unboxed closure bytes: {}", stats.unboxed_closure_bytes);
         println!("            impl bytes: {}", stats.impl_bytes);
         println!("            misc bytes: {}", stats.misc_bytes);
         println!("            item bytes: {}", stats.item_bytes);
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 41563293314..ffa0cca7539 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -130,6 +130,16 @@ fn data_log_string(data: &[u8], pos: uint) -> String {
     buf
 }
 
+pub fn parse_ty_closure_data(data: &[u8],
+                             crate_num: ast::CrateNum,
+                             pos: uint,
+                             tcx: &ty::ctxt,
+                             conv: conv_did)
+                             -> ty::ClosureTy {
+    let mut st = parse_state_from_data(data, crate_num, pos, tcx);
+    parse_closure_ty(&mut st, conv)
+}
+
 pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
                      conv: conv_did) -> ty::t {
     debug!("parse_ty_data {}", data_log_string(data, pos));
@@ -420,6 +430,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
           assert_eq!(next(st), ']');
           return ty::mk_struct(st.tcx, did, substs);
       }
+      'k' => {
+          let did = parse_def(st, NominalType, |x,y| conv(x,y));
+          return ty::mk_unboxed_closure(st.tcx, did);
+      }
       'e' => {
           return ty::mk_err();
       }
@@ -502,12 +516,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
     let store = parse_trait_store(st, |x,y| conv(x,y));
     let bounds = parse_bounds(st, |x,y| conv(x,y));
     let sig = parse_sig(st, |x,y| conv(x,y));
+    let abi = parse_abi_set(st);
     ty::ClosureTy {
         fn_style: fn_style,
         onceness: onceness,
         store: store,
         bounds: bounds.builtin_bounds,
-        sig: sig
+        sig: sig,
+        abi: abi,
     }
 }
 
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index bcd6f3ac91a..15e4e85ddb7 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -284,6 +284,9 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
             enc_substs(w, cx, substs);
             mywrite!(w, "]");
         }
+        ty::ty_unboxed_closure(def) => {
+            mywrite!(w, "k{}", (cx.ds)(def));
+        }
         ty::ty_err => {
             mywrite!(w, "e");
         }
@@ -316,7 +319,7 @@ pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
     enc_fn_sig(w, cx, &ft.sig);
 }
 
-fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
+pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
     enc_fn_style(w, ft.fn_style);
     enc_onceness(w, ft.onceness);
     enc_trait_store(w, cx, ft.store);
@@ -324,6 +327,7 @@ fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
                                   trait_bounds: Vec::new()};
     enc_bounds(w, cx, &bounds);
     enc_fn_sig(w, cx, &ft.sig);
+    enc_abi(w, ft.abi);
 }
 
 fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index fd10fd3c35a..722715405bc 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -609,6 +609,9 @@ impl tr for MethodOrigin {
     fn tr(&self, xcx: &ExtendedDecodeContext) -> MethodOrigin {
         match *self {
             typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(xcx)),
+            typeck::MethodStaticUnboxedClosure(did) => {
+                typeck::MethodStaticUnboxedClosure(did.tr(xcx))
+            }
             typeck::MethodParam(ref mp) => {
                 typeck::MethodParam(
                     typeck::MethodParam {
@@ -696,8 +699,18 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext,
                 })
             })
           }
+          typeck::vtable_unboxed_closure(def_id) => {
+              ebml_w.emit_enum_variant("vtable_unboxed_closure",
+                                       2u,
+                                       1u,
+                                       |ebml_w| {
+                ebml_w.emit_enum_variant_arg(0u, |ebml_w| {
+                    Ok(ebml_w.emit_def_id(def_id))
+                })
+              })
+          }
           typeck::vtable_error => {
-            ebml_w.emit_enum_variant("vtable_error", 2u, 3u, |_ebml_w| {
+            ebml_w.emit_enum_variant("vtable_error", 3u, 3u, |_ebml_w| {
                 Ok(())
             })
           }
@@ -771,7 +784,8 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
         self.read_enum("vtable_origin", |this| {
             this.read_enum_variant(["vtable_static",
                                     "vtable_param",
-                                    "vtable_error"],
+                                    "vtable_error",
+                                    "vtable_unboxed_closure"],
                                    |this, i| {
                 Ok(match i {
                   0 => {
@@ -798,6 +812,13 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
                     )
                   }
                   2 => {
+                    typeck::vtable_unboxed_closure(
+                        this.read_enum_variant_arg(0u, |this| {
+                            Ok(this.read_def_id_noxcx(cdata))
+                        }).unwrap()
+                    )
+                  }
+                  3 => {
                     typeck::vtable_error
                   }
                   _ => fail!("bad enum variant")
@@ -838,6 +859,9 @@ impl<'a> get_ty_str_ctxt for e::EncodeContext<'a> {
 }
 
 trait ebml_writer_helpers {
+    fn emit_closure_type(&mut self,
+                         ecx: &e::EncodeContext,
+                         closure_type: &ty::ClosureTy);
     fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t);
     fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]);
     fn emit_type_param_def(&mut self,
@@ -851,6 +875,14 @@ trait ebml_writer_helpers {
 }
 
 impl<'a> ebml_writer_helpers for Encoder<'a> {
+    fn emit_closure_type(&mut self,
+                         ecx: &e::EncodeContext,
+                         closure_type: &ty::ClosureTy) {
+        self.emit_opaque(|this| {
+            Ok(e::write_closure_type(ecx, this, closure_type))
+        });
+    }
+
     fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) {
         self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
     }
@@ -1127,6 +1159,18 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
             })
         })
     }
+
+    for unboxed_closure_type in tcx.unboxed_closure_types
+                                   .borrow()
+                                   .find(&ast_util::local_def(id))
+                                   .iter() {
+        ebml_w.tag(c::tag_table_unboxed_closure_type, |ebml_w| {
+            ebml_w.id(id);
+            ebml_w.tag(c::tag_table_val, |ebml_w| {
+                ebml_w.emit_closure_type(ecx, *unboxed_closure_type)
+            })
+        })
+    }
 }
 
 trait doc_decoder_helpers {
@@ -1150,6 +1194,8 @@ trait ebml_decoder_decoder_helpers {
                      -> ty::Polytype;
     fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
     fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
+    fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
+                                 -> ty::ClosureTy;
     fn convert_def_id(&mut self,
                       xcx: &ExtendedDecodeContext,
                       source: DefIdSource,
@@ -1322,6 +1368,18 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
         }).unwrap()
     }
 
+    fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
+                                 -> ty::ClosureTy {
+        self.read_opaque(|this, doc| {
+            Ok(tydecode::parse_ty_closure_data(
+                doc.data,
+                xcx.dcx.cdata.cnum,
+                doc.start,
+                xcx.dcx.tcx,
+                |s, a| this.convert_def_id(xcx, s, a)))
+        }).unwrap()
+    }
+
     fn convert_def_id(&mut self,
                       xcx: &ExtendedDecodeContext,
                       source: tydecode::DefIdSource,
@@ -1442,6 +1500,15 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
                         let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
                         dcx.tcx.adjustments.borrow_mut().insert(id, adj);
                     }
+                    c::tag_table_unboxed_closure_type => {
+                        let unboxed_closure_type =
+                            val_dsr.read_unboxed_closure_type(xcx);
+                        dcx.tcx
+                           .unboxed_closure_types
+                           .borrow_mut()
+                           .insert(ast_util::local_def(id),
+                                   unboxed_closure_type);
+                    }
                     _ => {
                         xcx.dcx.tcx.sess.bug(
                             format!("unknown tag found in side tables: {:x}",
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index cfec67bf3a3..fecd40dae01 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -832,3 +832,4 @@ impl<'a> CheckLoanCtxt<'a> {
                     self.bccx.loan_path_to_string(loan_path)).as_slice());
     }
 }
+
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 0d8729071ef..208a9d05716 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -446,6 +446,7 @@ impl<'a> CFGBuilder<'a> {
             ast::ExprMac(..) |
             ast::ExprFnBlock(..) |
             ast::ExprProc(..) |
+            ast::ExprUnboxedFn(..) |
             ast::ExprLit(..) |
             ast::ExprPath(..) => {
                 self.straightline(expr, pred, [])
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index c855d59d508..ac8faaa6c6d 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -42,7 +42,9 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
             ast::ExprLoop(ref b, _) => {
                 self.visit_block(&**b, Loop);
             }
-            ast::ExprFnBlock(_, ref b) | ast::ExprProc(_, ref b) => {
+            ast::ExprFnBlock(_, ref b) |
+            ast::ExprProc(_, ref b) |
+            ast::ExprUnboxedFn(_, ref b) => {
                 self.visit_block(&**b, Closure);
             }
             ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 33e7554084a..9fc589ddf59 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -104,6 +104,7 @@ impl<'a> MarkSymbolVisitor<'a> {
                             None => self.check_def_id(def_id)
                         }
                     }
+                    typeck::MethodStaticUnboxedClosure(_) => {}
                     typeck::MethodParam(typeck::MethodParam {
                         trait_id: trait_id,
                         method_num: index,
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 1e06b3b1fd4..b911e636da0 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -20,7 +20,7 @@ use middle::freevars;
 use middle::pat_util;
 use middle::ty;
 use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam};
-use middle::typeck::{MethodStatic};
+use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure};
 use middle::typeck;
 use util::ppaux::Repr;
 
@@ -160,6 +160,9 @@ impl OverloadedCallType {
             MethodStatic(def_id) => {
                 OverloadedCallType::from_method_id(tcx, def_id)
             }
+            MethodStaticUnboxedClosure(def_id) => {
+                OverloadedCallType::from_method_id(tcx, def_id)
+            }
             MethodParam(ref method_param) => {
                 OverloadedCallType::from_trait_id(tcx, method_param.trait_id)
             }
@@ -439,6 +442,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
             }
 
             ast::ExprFnBlock(..) |
+            ast::ExprUnboxedFn(..) |
             ast::ExprProc(..) => {
                 self.walk_captures(expr)
             }
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index 614972f3d57..f6887718ec1 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -16,7 +16,7 @@
 use middle::def;
 use middle::resolve;
 use middle::ty;
-use util::nodemap::{NodeMap, NodeSet};
+use util::nodemap::{DefIdSet, NodeMap, NodeSet};
 
 use syntax::codemap::Span;
 use syntax::{ast};
@@ -39,8 +39,11 @@ pub struct freevar_entry {
     pub def: def::Def, //< The variable being accessed free.
     pub span: Span     //< First span where it is accessed (there can be multiple)
 }
+
 pub type freevar_map = NodeMap<Vec<freevar_entry>>;
 
+pub type UnboxedClosureList = DefIdSet;
+
 struct CollectFreevarsVisitor<'a> {
     seen: NodeSet,
     refs: Vec<freevar_entry>,
@@ -54,7 +57,8 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
 
     fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
         match expr.node {
-            ast::ExprFnBlock(..) | ast::ExprProc(..) => {
+            ast::ExprFnBlock(..) | ast::ExprProc(..) |
+            ast::ExprUnboxedFn(..) => {
                 visit::walk_expr(self, expr, depth + 1)
             }
             ast::ExprPath(..) => {
@@ -125,8 +129,8 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
 // efficient as it fully recomputes the free variables at every
 // node of interest rather than building up the free variables in
 // one pass. This could be improved upon if it turns out to matter.
-pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) ->
-   freevar_map {
+pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
+                         -> freevar_map {
     let mut visitor = AnnotateFreevarsVisitor {
         def_map: def_map,
         freevars: NodeMap::new(),
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 4f7cb742d8f..a45bb69a53e 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -216,6 +216,9 @@ fn with_appropriate_checker(cx: &Context,
         ty::ty_bare_fn(_) => {
             b(check_for_bare)
         }
+
+        ty::ty_unboxed_closure(_) => {}
+
         ref s => {
             cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
                                      {:?}",
@@ -321,7 +324,9 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
         Some(method) => {
             let is_object_call = match method.origin {
                 typeck::MethodObject(..) => true,
-                typeck::MethodStatic(..) | typeck::MethodParam(..) => false
+                typeck::MethodStatic(..) |
+                typeck::MethodStaticUnboxedClosure(..) |
+                typeck::MethodParam(..) => false
             };
             (&method.substs.types, is_object_call)
         }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 79742d31734..737b952151b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -448,7 +448,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         }
         visit::walk_expr(ir, expr, ());
       }
-      ExprFnBlock(..) | ExprProc(..) => {
+      ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) => {
         // Interesting control flow (for loops can contain labeled
         // breaks or continues)
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
@@ -941,8 +941,11 @@ impl<'a> Liveness<'a> {
               self.propagate_through_expr(&**e, succ)
           }
 
-          ExprFnBlock(_, ref blk) | ExprProc(_, ref blk) => {
-              debug!("{} is an ExprFnBlock or ExprProc", expr_to_string(expr));
+          ExprFnBlock(_, ref blk) |
+          ExprProc(_, ref blk) |
+          ExprUnboxedFn(_, ref blk) => {
+              debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
+                     expr_to_string(expr));
 
               /*
               The next-node for a break is the successor of the entire
@@ -1411,8 +1414,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
       ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
       ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
-      ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
-      ExprBox(..) => {
+      ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
+      ExprPath(..) | ExprBox(..) => {
         visit::walk_expr(this, expr, ());
       }
       ExprForLoop(..) => fail!("non-desugared expr_for_loop")
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index e928704b0cc..baf7f2dd776 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -473,7 +473,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
 
           ast::ExprAddrOf(..) | ast::ExprCall(..) |
           ast::ExprAssign(..) | ast::ExprAssignOp(..) |
-          ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) |
+          ast::ExprFnBlock(..) | ast::ExprProc(..) |
+          ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
           ast::ExprUnary(..) |
           ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
           ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
@@ -578,6 +579,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
                           }))
                       }
                   }
+                  ty::ty_unboxed_closure(_) => {
+                      // FIXME #2152 allow mutation of moved upvars
+                      Ok(Rc::new(cmt_ {
+                          id: id,
+                          span: span,
+                          cat: cat_copied_upvar(CopiedUpvar {
+                              upvar_id: var_id,
+                              onceness: ast::Many,
+                              capturing_proc: fn_node_id,
+                          }),
+                          mutbl: McImmutable,
+                          ty: expr_ty
+                      }))
+                  }
                   _ => {
                       self.tcx().sess.span_bug(
                           span,
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 74ca13a0821..cdb3f9dbb1d 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -21,7 +21,7 @@ use lint;
 use middle::resolve;
 use middle::ty;
 use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
-use middle::typeck::{MethodStatic, MethodObject};
+use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
 use util::nodemap::{NodeMap, NodeSet};
 
 use syntax::ast;
@@ -772,6 +772,7 @@ impl<'a> PrivacyVisitor<'a> {
             MethodStatic(method_id) => {
                 self.check_static_method(span, method_id, ident)
             }
+            MethodStaticUnboxedClosure(_) => {}
             // Trait methods are always all public. The only controlling factor
             // is whether the trait itself is accessible or not.
             MethodParam(MethodParam { trait_id: trait_id, .. }) |
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 3ff2ef77089..f1e6db1cab1 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5254,7 +5254,8 @@ impl<'a> Resolver<'a> {
             }
 
             ExprFnBlock(fn_decl, block) |
-            ExprProc(fn_decl, block) => {
+            ExprProc(fn_decl, block) |
+            ExprUnboxedFn(fn_decl, block) => {
                 self.resolve_function(FunctionRibKind(expr.id, block.id),
                                       Some(fn_decl), NoTypeParameters,
                                       block);
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index 2778764d6fa..9f1f4057be6 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -842,7 +842,8 @@ impl <'l> DxrVisitor<'l> {
         let method_map = self.analysis.ty_cx.method_map.borrow();
         let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id));
         let (def_id, decl_id) = match method_callee.origin {
-            typeck::MethodStatic(def_id) => {
+            typeck::MethodStatic(def_id) |
+            typeck::MethodStaticUnboxedClosure(def_id) => {
                 // method invoked on an object with a concrete type (not a static method)
                 let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
 
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 5c2a70a46fd..ef0709316f0 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -317,6 +317,9 @@ impl<T> VecPerParamSpace<T> {
         VecPerParamSpace::empty().with_vec(TypeSpace, types)
     }
 
+    /// `t` is the type space.
+    /// `s` is the self space.
+    /// `f` is the fn space.
     pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
         let type_limit = t.len();
         let self_limit = t.len() + s.len();
diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs
index 3ee61b1d675..1d0108fa3f7 100644
--- a/src/librustc/middle/trans/adt.rs
+++ b/src/librustc/middle/trans/adt.rs
@@ -163,6 +163,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
 
             return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
         }
+        ty::ty_unboxed_closure(def_id) => {
+            let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
+            let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
+            return Univariant(mk_struct(cx, upvar_types.as_slice(), false),
+                              false)
+        }
         ty::ty_enum(def_id, ref substs) => {
             let cases = get_cases(cx.tcx(), def_id, substs);
             let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 3ca188cf281..98342bfbcdc 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -29,17 +29,16 @@ use back::link::{mangle_exported_name};
 use back::{link, abi};
 use driver::config;
 use driver::config::{NoDebugInfo, FullDebugInfo};
-use driver::session::Session;
 use driver::driver::{CrateAnalysis, CrateTranslation};
+use driver::session::Session;
+use lint;
+use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param};
 use llvm;
-use llvm::{ModuleRef, ValueRef, BasicBlockRef};
-use llvm::{Vector};
 use metadata::{csearch, encoder, loader};
-use lint;
 use middle::astencode;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
-use middle::weak_lang_items;
 use middle::subst;
+use middle::weak_lang_items;
 use middle::subst::Subst;
 use middle::trans::_match;
 use middle::trans::adt;
@@ -82,7 +81,8 @@ use std::cell::{Cell, RefCell};
 use std::rc::Rc;
 use std::{i8, i16, i32, i64};
 use std::gc::Gc;
-use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustIntrinsic};
+use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
+use syntax::abi::{RustIntrinsic, Abi};
 use syntax::ast_util::{local_def, is_local};
 use syntax::attr::AttrMetaMethods;
 use syntax::attr;
@@ -254,13 +254,32 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
 }
 
 pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
-    let (inputs, output, has_env) = match ty::get(fn_ty).sty {
-        ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false),
-        ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true),
+    let (inputs, output, abi, env) = match ty::get(fn_ty).sty {
+        ty::ty_bare_fn(ref f) => {
+            (f.sig.inputs.clone(), f.sig.output, f.abi, None)
+        }
+        ty::ty_closure(ref f) => {
+            (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx)))
+        }
+        ty::ty_unboxed_closure(closure_did) => {
+            let unboxed_closure_types = ccx.tcx
+                                           .unboxed_closure_types
+                                           .borrow();
+            let function_type = unboxed_closure_types.get(&closure_did);
+            let llenvironment_type = type_of(ccx, fn_ty).ptr_to();
+            (function_type.sig.inputs.clone(),
+             function_type.sig.output,
+             RustCall,
+             Some(llenvironment_type))
+        }
         _ => fail!("expected closure or fn")
     };
 
-    let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output);
+    let llfty = type_of_rust_fn(ccx, env, inputs.as_slice(), output, abi);
+    debug!("decl_rust_fn(input count={},type={})",
+           inputs.len(),
+           ccx.tn.type_to_string(llfty));
+
     let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output);
     let attrs = get_fn_llvm_attributes(ccx, fn_ty);
     for &(idx, attr) in attrs.iter() {
@@ -674,6 +693,14 @@ pub fn iter_structural_ty<'r,
               }
           })
       }
+      ty::ty_unboxed_closure(def_id) => {
+          let repr = adt::represent_type(cx.ccx(), t);
+          let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
+          for (i, upvar) in upvars.iter().enumerate() {
+              let llupvar = adt::trans_field_ptr(cx, &*repr, av, 0, i);
+              cx = f(cx, llupvar, upvar.ty);
+          }
+      }
       ty::ty_vec(_, Some(n)) => {
         let unit_ty = ty::sequence_element_type(cx.tcx(), t);
         let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
@@ -870,7 +897,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
         ty::ty_bare_fn(ref fn_ty) => {
             match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
                                        ccx.sess().targ_cfg.arch) {
-                Some(Rust) => {
+                Some(Rust) | Some(RustCall) => {
                     get_extern_rust_fn(ccx, t, name.as_slice(), did)
                 }
                 Some(RustIntrinsic) => {
@@ -1150,13 +1177,11 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
 // slot where the return value of the function must go.
 pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
                            -> ValueRef {
-    unsafe {
-        if type_of::return_uses_outptr(fcx.ccx, output_type) {
-            llvm::LLVMGetParam(fcx.llfn, 0)
-        } else {
-            let lloutputtype = type_of::type_of(fcx.ccx, output_type);
-            AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
-        }
+    if type_of::return_uses_outptr(fcx.ccx, output_type) {
+        get_param(fcx.llfn, 0)
+    } else {
+        let lloutputtype = type_of::type_of(fcx.ccx, output_type);
+        AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
     }
 }
 
@@ -1213,9 +1238,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
     };
 
     if has_env {
-        fcx.llenv = Some(unsafe {
-            llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
-        });
+        fcx.llenv = Some(get_param(fcx.llfn, fcx.env_arg_pos() as c_uint))
     }
 
     fcx
@@ -1280,16 +1303,85 @@ pub fn create_datums_for_fn_args(fcx: &FunctionContext,
                                  -> Vec<RvalueDatum> {
     let _icx = push_ctxt("create_datums_for_fn_args");
 
-    // Return an array wrapping the ValueRefs that we get from
-    // llvm::LLVMGetParam for each argument into datums.
+    // Return an array wrapping the ValueRefs that we get from `get_param` for
+    // each argument into datums.
     arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
-        let llarg = unsafe {
-            llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
-        };
+        let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint);
         datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
     }).collect()
 }
 
+/// Creates rvalue datums for each of the incoming function arguments and
+/// tuples the arguments. These will later be stored into appropriate lvalue
+/// datums.
+fn create_datums_for_fn_args_under_call_abi<
+        'a>(
+        mut bcx: &'a Block<'a>,
+        arg_scope: cleanup::CustomScopeIndex,
+        arg_tys: &[ty::t])
+        -> Vec<RvalueDatum> {
+    let mut result = Vec::new();
+    for (i, &arg_ty) in arg_tys.iter().enumerate() {
+        if i < arg_tys.len() - 1 {
+            // Regular argument.
+            let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint);
+            result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx,
+                                                                  arg_ty)));
+            continue
+        }
+
+        // This is the last argument. Tuple it.
+        match ty::get(arg_ty).sty {
+            ty::ty_tup(ref tupled_arg_tys) => {
+                let tuple_args_scope_id = cleanup::CustomScope(arg_scope);
+                let tuple =
+                    unpack_datum!(bcx,
+                                  datum::lvalue_scratch_datum(bcx,
+                                                              arg_ty,
+                                                              "tupled_args",
+                                                              false,
+                                                              tuple_args_scope_id,
+                                                              (),
+                                                              |(),
+                                                               mut bcx,
+                                                               llval| {
+                        for (j, &tupled_arg_ty) in
+                                    tupled_arg_tys.iter().enumerate() {
+                            let llarg =
+                                get_param(bcx.fcx.llfn,
+                                          bcx.fcx.arg_pos(i + j) as c_uint);
+                            let lldest = GEPi(bcx, llval, [0, j]);
+                            let datum = datum::Datum::new(
+                                llarg,
+                                tupled_arg_ty,
+                                arg_kind(bcx.fcx, tupled_arg_ty));
+                            bcx = datum.store_to(bcx, lldest);
+                        }
+                        bcx
+                    }));
+                let tuple = unpack_datum!(bcx,
+                                          tuple.to_expr_datum()
+                                               .to_rvalue_datum(bcx,
+                                                                "argtuple"));
+                result.push(tuple);
+            }
+            ty::ty_nil => {
+                let mode = datum::Rvalue::new(datum::ByValue);
+                result.push(datum::Datum::new(C_nil(bcx.ccx()),
+                                              ty::mk_nil(),
+                                              mode))
+            }
+            _ => {
+                bcx.tcx().sess.bug("last argument of a function with \
+                                    `rust-call` ABI isn't a tuple?!")
+            }
+        };
+
+    }
+
+    result
+}
+
 fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
                             arg_scope: cleanup::CustomScopeIndex,
                             bcx: &'a Block<'a>,
@@ -1322,6 +1414,59 @@ fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
     bcx
 }
 
+fn copy_unboxed_closure_args_to_allocas<'a>(
+                                        mut bcx: &'a Block<'a>,
+                                        arg_scope: cleanup::CustomScopeIndex,
+                                        args: &[ast::Arg],
+                                        arg_datums: Vec<RvalueDatum>,
+                                        monomorphized_arg_types: &[ty::t])
+                                        -> &'a Block<'a> {
+    let _icx = push_ctxt("copy_unboxed_closure_args_to_allocas");
+    let arg_scope_id = cleanup::CustomScope(arg_scope);
+
+    assert_eq!(arg_datums.len(), 1);
+
+    let arg_datum = arg_datums.move_iter().next().unwrap();
+
+    // Untuple the rest of the arguments.
+    let tuple_datum =
+        unpack_datum!(bcx,
+                      arg_datum.to_lvalue_datum_in_scope(bcx,
+                                                         "argtuple",
+                                                         arg_scope_id));
+    let empty = Vec::new();
+    let untupled_arg_types = match ty::get(monomorphized_arg_types[0]).sty {
+        ty::ty_tup(ref types) => types.as_slice(),
+        ty::ty_nil => empty.as_slice(),
+        _ => {
+            bcx.tcx().sess.span_bug(args[0].pat.span,
+                                    "first arg to `rust-call` ABI function \
+                                     wasn't a tuple?!")
+        }
+    };
+    for j in range(0, args.len()) {
+        let tuple_element_type = untupled_arg_types[j];
+        let tuple_element_datum =
+            tuple_datum.get_element(tuple_element_type,
+                                    |llval| GEPi(bcx, llval, [0, j]));
+        let tuple_element_datum = tuple_element_datum.to_expr_datum();
+        let tuple_element_datum =
+            unpack_datum!(bcx,
+                          tuple_element_datum.to_rvalue_datum(bcx,
+                                                              "arg"));
+        bcx = _match::store_arg(bcx,
+                                args[j].pat,
+                                tuple_element_datum,
+                                arg_scope_id);
+
+        if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
+            debuginfo::create_argument_metadata(bcx, &args[j]);
+        }
+    }
+
+    bcx
+}
+
 // Ties up the llstaticallocas -> llloadenv -> lltop edges,
 // and builds the return block.
 pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
@@ -1379,6 +1524,12 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
     Ret(ret_cx, retval);
 }
 
+#[deriving(Clone, Eq, PartialEq)]
+pub enum IsUnboxedClosureFlag {
+    NotUnboxedClosure,
+    IsUnboxedClosure,
+}
+
 // trans_closure: Builds an LLVM function out of a source function.
 // If the function closes over its environment a closure will be
 // returned.
@@ -1389,7 +1540,11 @@ pub fn trans_closure(ccx: &CrateContext,
                      param_substs: &param_substs,
                      id: ast::NodeId,
                      _attributes: &[ast::Attribute],
+                     arg_types: Vec<ty::t>,
                      output_type: ty::t,
+                     abi: Abi,
+                     has_env: bool,
+                     is_unboxed_closure: IsUnboxedClosureFlag,
                      maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) {
     ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
 
@@ -1399,11 +1554,6 @@ pub fn trans_closure(ccx: &CrateContext,
     debug!("trans_closure(..., param_substs={})",
            param_substs.repr(ccx.tcx()));
 
-    let has_env = match ty::get(ty::node_id_to_type(ccx.tcx(), id)).sty {
-        ty::ty_closure(_) => true,
-        _ => false
-    };
-
     let arena = TypedArena::new();
     let fcx = new_fn_ctxt(ccx,
                           llfndecl,
@@ -1421,14 +1571,44 @@ pub fn trans_closure(ccx: &CrateContext,
     let block_ty = node_id_type(bcx, body.id);
 
     // Set up arguments to the function.
-    let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
-    let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
+    let monomorphized_arg_types =
+        arg_types.iter()
+                 .map(|at| monomorphize_type(bcx, *at))
+                 .collect::<Vec<_>>();
+    for monomorphized_arg_type in monomorphized_arg_types.iter() {
+        debug!("trans_closure: monomorphized_arg_type: {}",
+               ty_to_string(ccx.tcx(), *monomorphized_arg_type));
+    }
+    debug!("trans_closure: function lltype: {}",
+           bcx.fcx.ccx.tn.val_to_string(bcx.fcx.llfn));
+
+    let arg_datums = if abi != RustCall {
+        create_datums_for_fn_args(&fcx,
+                                  monomorphized_arg_types.as_slice())
+    } else {
+        create_datums_for_fn_args_under_call_abi(
+            bcx,
+            arg_scope,
+            monomorphized_arg_types.as_slice())
+    };
 
-    bcx = copy_args_to_allocas(&fcx,
-                               arg_scope,
-                               bcx,
-                               decl.inputs.as_slice(),
-                               arg_datums);
+    bcx = match is_unboxed_closure {
+        NotUnboxedClosure => {
+            copy_args_to_allocas(&fcx,
+                                 arg_scope,
+                                 bcx,
+                                 decl.inputs.as_slice(),
+                                 arg_datums)
+        }
+        IsUnboxedClosure => {
+            copy_unboxed_closure_args_to_allocas(
+                bcx,
+                arg_scope,
+                decl.inputs.as_slice(),
+                arg_datums,
+                monomorphized_arg_types.as_slice())
+        }
+    };
 
     bcx = maybe_load_env(bcx);
 
@@ -1488,9 +1668,23 @@ pub fn trans_fn(ccx: &CrateContext,
     let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string());
     debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
     let _icx = push_ctxt("trans_fn");
-    let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id));
-    trans_closure(ccx, decl, body, llfndecl,
-                  param_substs, id, attrs, output_type, |bcx| bcx);
+    let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
+    let arg_types = ty::ty_fn_args(fn_ty);
+    let output_type = ty::ty_fn_ret(fn_ty);
+    let abi = ty::ty_fn_abi(fn_ty);
+    trans_closure(ccx,
+                  decl,
+                  body,
+                  llfndecl,
+                  param_substs,
+                  id,
+                  attrs,
+                  arg_types,
+                  output_type,
+                  abi,
+                  false,
+                  NotUnboxedClosure,
+                  |bcx| bcx);
 }
 
 pub fn trans_enum_variant(ccx: &CrateContext,
@@ -1657,7 +1851,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
     let _icx = push_ctxt("trans_item");
     match item.node {
       ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => {
-        if abi != Rust  {
+        if abi != Rust {
             let llfndecl = get_item_val(ccx, item.id);
             foreign::trans_rust_fn_with_foreign_abi(
                 ccx, &**decl, &**body, item.attrs.as_slice(), llfndecl, item.id);
@@ -1792,7 +1986,7 @@ fn register_fn(ccx: &CrateContext,
                -> ValueRef {
     match ty::get(node_type).sty {
         ty::ty_bare_fn(ref f) => {
-            assert!(f.abi == Rust);
+            assert!(f.abi == Rust || f.abi == RustCall);
         }
         _ => fail!("expected bare rust fn")
     };
@@ -1802,15 +1996,30 @@ fn register_fn(ccx: &CrateContext,
     llfn
 }
 
-pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> {
+pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
+                              -> Vec<(uint, u64)> {
     use middle::ty::{BrAnon, ReLateBound};
 
-    let (fn_sig, has_env) = match ty::get(fn_ty).sty {
-        ty::ty_closure(ref f) => (f.sig.clone(), true),
-        ty::ty_bare_fn(ref f) => (f.sig.clone(), false),
+    let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
+        ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
+        ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
+        ty::ty_unboxed_closure(closure_did) => {
+            let unboxed_closure_types = ccx.tcx
+                                           .unboxed_closure_types
+                                           .borrow();
+            let function_type = unboxed_closure_types.get(&closure_did);
+            (function_type.sig.clone(), RustCall, true)
+        }
         _ => fail!("expected closure or function.")
     };
 
+    // These have an odd calling convention, so we skip them for now.
+    //
+    // FIXME(pcwalton): We don't have to skip them; just untuple the result.
+    if abi == RustCall {
+        return Vec::new()
+    }
+
     // Since index 0 is the return value of the llvm func, we start
     // at either 1 or 2 depending on whether there's an env slot or not
     let mut first_arg_offset = if has_env { 2 } else { 1 };
@@ -1986,16 +2195,16 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
 
                     vec!(
                         opaque_rust_main,
-                        llvm::LLVMGetParam(llfn, 0),
-                        llvm::LLVMGetParam(llfn, 1)
+                        get_param(llfn, 0),
+                        get_param(llfn, 1)
                      )
                 };
                 (start_fn, args)
             } else {
                 debug!("using user-defined start fn");
                 let args = vec!(
-                    llvm::LLVMGetParam(llfn, 0 as c_uint),
-                    llvm::LLVMGetParam(llfn, 1 as c_uint)
+                    get_param(llfn, 0 as c_uint),
+                    get_param(llfn, 1 as c_uint)
                 );
 
                 (rust_main, args)
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index db2d17c85db..8eab227ad16 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -19,18 +19,20 @@
 use arena::TypedArena;
 use back::abi;
 use back::link;
+use llvm::{ValueRef, get_param};
 use llvm;
-use llvm::ValueRef;
 use metadata::csearch;
 use middle::def;
 use middle::subst;
 use middle::subst::{Subst, VecPerParamSpace};
+use middle::trans::adt;
 use middle::trans::base;
 use middle::trans::base::*;
 use middle::trans::build::*;
 use middle::trans::callee;
 use middle::trans::cleanup;
 use middle::trans::cleanup::CleanupMethods;
+use middle::trans::closure;
 use middle::trans::common;
 use middle::trans::common::*;
 use middle::trans::datum::*;
@@ -74,7 +76,7 @@ pub enum CalleeData {
 
 pub struct Callee<'a> {
     pub bcx: &'a Block<'a>,
-    pub data: CalleeData
+    pub data: CalleeData,
 }
 
 fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
@@ -97,12 +99,18 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
         match ty::get(datum.ty).sty {
             ty::ty_bare_fn(..) => {
                 let llval = datum.to_llscalarish(bcx);
-                return Callee {bcx: bcx, data: Fn(llval)};
+                return Callee {
+                    bcx: bcx,
+                    data: Fn(llval),
+                };
             }
             ty::ty_closure(..) => {
                 let datum = unpack_datum!(
                     bcx, datum.to_lvalue_datum(bcx, "callee", expr.id));
-                return Callee {bcx: bcx, data: Closure(datum)};
+                return Callee {
+                    bcx: bcx,
+                    data: Closure(datum),
+                };
             }
             _ => {
                 bcx.tcx().sess.span_bug(
@@ -115,7 +123,10 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
     }
 
     fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> {
-        return Callee {bcx: bcx, data: Fn(llfn)};
+        return Callee {
+            bcx: bcx,
+            data: Fn(llfn),
+        };
     }
 
     fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
@@ -206,9 +217,14 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
                                            substs: subst::Substs,
                                            vtables: typeck::vtable_res)
                                            -> Callee<'a> {
-    Callee {bcx: bcx,
-            data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id),
-                                               substs, vtables))}
+    Callee {
+        bcx: bcx,
+        data: Fn(trans_fn_ref_with_vtables(bcx,
+                                           def_id,
+                                           ExprId(ref_id),
+                                           substs,
+                                           vtables)),
+    }
 }
 
 fn resolve_default_method_vtables(bcx: &Block,
@@ -304,9 +320,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
     let boxed_self_kind = arg_kind(&fcx, boxed_self_type);
 
     // Create a datum for self.
-    let llboxedself = unsafe {
-        llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(0) as u32)
-    };
+    let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
     let llboxedself = Datum::new(llboxedself,
                                  boxed_self_type,
                                  boxed_self_kind);
@@ -340,9 +354,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
     // Now call the function.
     let mut llshimmedargs = vec!(llself.val);
     for i in range(1, arg_types.len()) {
-        llshimmedargs.push(unsafe {
-            llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as u32)
-        });
+        llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
     }
     bcx = trans_call_inner(bcx,
                            None,
@@ -402,9 +414,6 @@ pub fn trans_fn_ref_with_vtables(
 
     assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
 
-    // Polytype of the function item (may have type params)
-    let fn_tpt = ty::lookup_item_type(tcx, def_id);
-
     // Load the info for the appropriate trait if necessary.
     match ty::trait_of_method(tcx, def_id) {
         None => {}
@@ -465,6 +474,12 @@ pub fn trans_fn_ref_with_vtables(
         }
     };
 
+    // If this is an unboxed closure, redirect to it.
+    match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) {
+        None => {}
+        Some(llfn) => return llfn,
+    }
+
     // Check whether this fn has an inlined copy and, if so, redirect
     // def_id to the local id of the inlined copy.
     let def_id = {
@@ -509,6 +524,9 @@ pub fn trans_fn_ref_with_vtables(
         return val;
     }
 
+    // Polytype of the function item (may have type params)
+    let fn_tpt = ty::lookup_item_type(tcx, def_id);
+
     // Find the actual function pointer.
     let mut val = {
         if def_id.krate == ast::LOCAL_CRATE {
@@ -546,7 +564,10 @@ pub fn trans_fn_ref_with_vtables(
     let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
     let llptrty = llty.ptr_to();
     if val_ty(val) != llptrty {
+        debug!("trans_fn_ref_with_vtables(): casting pointer!");
         val = BitCast(bcx, val, llptrty);
+    } else {
+        debug!("trans_fn_ref_with_vtables(): not casting pointer!");
     }
 
     val
@@ -660,7 +681,7 @@ pub fn trans_call_inner<'a>(
 
     let (abi, ret_ty) = match ty::get(callee_ty).sty {
         ty::ty_bare_fn(ref f) => (f.abi, f.sig.output),
-        ty::ty_closure(ref f) => (synabi::Rust, f.sig.output),
+        ty::ty_closure(ref f) => (f.abi, f.sig.output),
         _ => fail!("expected bare rust fn or closure in trans_call_inner")
     };
 
@@ -723,7 +744,7 @@ pub fn trans_call_inner<'a>(
     // and done, either the return value of the function will have been
     // written in opt_llretslot (if it is Some) or `llresult` will be
     // set appropriately (otherwise).
-    if abi == synabi::Rust {
+    if abi == synabi::Rust || abi == synabi::RustCall {
         let mut llargs = Vec::new();
 
         // Push the out-pointer if we use an out-pointer for this
@@ -742,9 +763,13 @@ pub fn trans_call_inner<'a>(
         }
 
         // Push the arguments.
-        bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+        bcx = trans_args(bcx,
+                         args,
+                         callee_ty,
+                         &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
-                         llself.is_some());
+                         llself.is_some(),
+                         abi);
 
         fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
@@ -779,8 +804,13 @@ pub fn trans_call_inner<'a>(
             ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(),
             _ => fail!("expected arg exprs.")
         };
-        bcx = trans_args(bcx, args, callee_ty, &mut llargs,
-                         cleanup::CustomScope(arg_cleanup_scope), false);
+        bcx = trans_args(bcx,
+                         args,
+                         callee_ty,
+                         &mut llargs,
+                         cleanup::CustomScope(arg_cleanup_scope),
+                         false,
+                         abi);
         fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
         bcx = foreign::trans_native_call(bcx, callee_ty,
                                          llfn, opt_llretslot.unwrap(),
@@ -821,15 +851,130 @@ pub enum CallArgs<'a> {
     // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
     // the right-hand-side (if any).
     ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
+
+    // Supply value of arguments as a list of expressions that must be
+    // translated, for overloaded call operators.
+    ArgOverloadedCall(&'a [Gc<ast::Expr>]),
 }
 
-pub fn trans_args<'a>(cx: &'a Block<'a>,
-                      args: CallArgs,
-                      fn_ty: ty::t,
-                      llargs: &mut Vec<ValueRef> ,
-                      arg_cleanup_scope: cleanup::ScopeId,
-                      ignore_self: bool)
-                      -> &'a Block<'a> {
+fn trans_args_under_call_abi<'a>(
+                             mut bcx: &'a Block<'a>,
+                             arg_exprs: &[Gc<ast::Expr>],
+                             fn_ty: ty::t,
+                             llargs: &mut Vec<ValueRef>,
+                             arg_cleanup_scope: cleanup::ScopeId,
+                             ignore_self: bool)
+                             -> &'a Block<'a> {
+    // Translate the `self` argument first.
+    let arg_tys = ty::ty_fn_args(fn_ty);
+    if !ignore_self {
+        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
+        llargs.push(unpack_result!(bcx, {
+            trans_arg_datum(bcx,
+                            *arg_tys.get(0),
+                            arg_datum,
+                            arg_cleanup_scope,
+                            DontAutorefArg)
+        }))
+    }
+
+    // Now untuple the rest of the arguments.
+    let tuple_expr = arg_exprs[1];
+    let tuple_type = node_id_type(bcx, tuple_expr.id);
+
+    match ty::get(tuple_type).sty {
+        ty::ty_tup(ref field_types) => {
+            let tuple_datum = unpack_datum!(bcx,
+                                            expr::trans(bcx, &*tuple_expr));
+            let tuple_lvalue_datum =
+                unpack_datum!(bcx,
+                              tuple_datum.to_lvalue_datum(bcx,
+                                                          "args",
+                                                          tuple_expr.id));
+            let repr = adt::represent_type(bcx.ccx(), tuple_type);
+            let repr_ptr = &*repr;
+            for i in range(0, field_types.len()) {
+                let arg_datum = tuple_lvalue_datum.get_element(
+                    *field_types.get(i),
+                    |srcval| {
+                        adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
+                    });
+                let arg_datum = arg_datum.to_expr_datum();
+                let arg_datum =
+                    unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+                let arg_datum =
+                    unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx));
+                llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope));
+            }
+        }
+        ty::ty_nil => {}
+        _ => {
+            bcx.sess().span_bug(tuple_expr.span,
+                                "argument to `.call()` wasn't a tuple?!")
+        }
+    };
+
+    bcx
+}
+
+fn trans_overloaded_call_args<'a>(
+                              mut bcx: &'a Block<'a>,
+                              arg_exprs: &[Gc<ast::Expr>],
+                              fn_ty: ty::t,
+                              llargs: &mut Vec<ValueRef>,
+                              arg_cleanup_scope: cleanup::ScopeId,
+                              ignore_self: bool)
+                              -> &'a Block<'a> {
+    // Translate the `self` argument first.
+    let arg_tys = ty::ty_fn_args(fn_ty);
+    if !ignore_self {
+        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
+        llargs.push(unpack_result!(bcx, {
+            trans_arg_datum(bcx,
+                            *arg_tys.get(0),
+                            arg_datum,
+                            arg_cleanup_scope,
+                            DontAutorefArg)
+        }))
+    }
+
+    // Now untuple the rest of the arguments.
+    let tuple_type = *arg_tys.get(1);
+    match ty::get(tuple_type).sty {
+        ty::ty_tup(ref field_types) => {
+            for (i, &field_type) in field_types.iter().enumerate() {
+                let arg_datum =
+                    unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[i + 1]));
+                llargs.push(unpack_result!(bcx, {
+                    trans_arg_datum(bcx,
+                                    field_type,
+                                    arg_datum,
+                                    arg_cleanup_scope,
+                                    DontAutorefArg)
+                }))
+            }
+        }
+        ty::ty_nil => {}
+        _ => {
+            bcx.sess().span_bug(arg_exprs[0].span,
+                                "argument to `.call()` wasn't a tuple?!")
+        }
+    };
+
+    bcx
+}
+
+pub fn trans_args<'a>(
+                  cx: &'a Block<'a>,
+                  args: CallArgs,
+                  fn_ty: ty::t,
+                  llargs: &mut Vec<ValueRef> ,
+                  arg_cleanup_scope: cleanup::ScopeId,
+                  ignore_self: bool,
+                  abi: synabi::Abi)
+                  -> &'a Block<'a> {
+    debug!("trans_args(abi={})", abi);
+
     let _icx = push_ctxt("trans_args");
     let arg_tys = ty::ty_fn_args(fn_ty);
     let variadic = ty::fn_is_variadic(fn_ty);
@@ -841,6 +986,17 @@ pub fn trans_args<'a>(cx: &'a Block<'a>,
     // to cast her view of the arguments to the caller's view.
     match args {
         ArgExprs(arg_exprs) => {
+            if abi == synabi::RustCall {
+                // This is only used for direct calls to the `call`,
+                // `call_mut` or `call_once` functions.
+                return trans_args_under_call_abi(cx,
+                                                 arg_exprs,
+                                                 fn_ty,
+                                                 llargs,
+                                                 arg_cleanup_scope,
+                                                 ignore_self)
+            }
+
             let num_formal_args = arg_tys.len();
             for (i, arg_expr) in arg_exprs.iter().enumerate() {
                 if i == 0 && ignore_self {
@@ -861,6 +1017,14 @@ pub fn trans_args<'a>(cx: &'a Block<'a>,
                 }));
             }
         }
+        ArgOverloadedCall(arg_exprs) => {
+            return trans_overloaded_call_args(cx,
+                                              arg_exprs,
+                                              fn_ty,
+                                              llargs,
+                                              arg_cleanup_scope,
+                                              ignore_self)
+        }
         ArgOverloadedOp(lhs, rhs) => {
             assert!(!variadic);
 
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index f2400f6bfef..a3d8ab1733f 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -16,6 +16,7 @@ use llvm::ValueRef;
 use middle::def;
 use middle::freevars;
 use middle::lang_items::ClosureExchangeMallocFnLangItem;
+use middle::trans::adt;
 use middle::trans::base::*;
 use middle::trans::build::*;
 use middle::trans::common::*;
@@ -31,6 +32,7 @@ use util::ppaux::ty_to_string;
 
 use arena::TypedArena;
 use syntax::ast;
+use syntax::ast_util;
 
 // ___Good to know (tm)__________________________________________________
 //
@@ -285,7 +287,6 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
         let def_id = freevar.def.def_id();
 
         bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
-
         for &env_pointer_alloca in env_pointer_alloca.iter() {
             debuginfo::create_captured_var_metadata(
                 bcx,
@@ -303,6 +304,26 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
     bcx
 }
 
+fn load_unboxed_closure_environment<'a>(
+                                    bcx: &'a Block<'a>,
+                                    freevars: &Vec<freevars::freevar_entry>)
+                                    -> &'a Block<'a> {
+    let _icx = push_ctxt("closure::load_environment");
+
+    if freevars.len() == 0 {
+        return bcx
+    }
+
+    let llenv = bcx.fcx.llenv.unwrap();
+    for (i, freevar) in freevars.iter().enumerate() {
+        let upvar_ptr = GEPi(bcx, llenv, [0, i]);
+        let def_id = freevar.def.def_id();
+        bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
+    }
+
+    bcx
+}
+
 fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
     Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
     let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx()));
@@ -352,20 +373,149 @@ pub fn trans_expr_fn<'a>(
 
     let freevar_mode = freevars::get_capture_mode(tcx, id);
     let freevars: Vec<freevars::freevar_entry> =
-        freevars::with_freevars(
-            tcx, id,
-            |fv| fv.iter().map(|&fv| fv).collect());
-
-    let ClosureResult {llbox, cdata_ty, bcx} =
-        build_closure(bcx, freevar_mode, &freevars, store);
-    trans_closure(ccx, decl, body, llfn,
-                  bcx.fcx.param_substs, id,
-                  [], ty::ty_fn_ret(fty),
+        freevars::with_freevars(tcx,
+                                id,
+                                |fv| fv.iter().map(|&fv| fv).collect());
+
+    let ClosureResult {
+        llbox,
+        cdata_ty,
+        bcx
+    } = build_closure(bcx, freevar_mode, &freevars, store);
+    trans_closure(ccx,
+                  decl,
+                  body,
+                  llfn,
+                  bcx.fcx.param_substs,
+                  id,
+                  [],
+                  ty::ty_fn_args(fty),
+                  ty::ty_fn_ret(fty),
+                  ty::ty_fn_abi(fty),
+                  true,
+                  NotUnboxedClosure,
                   |bcx| load_environment(bcx, cdata_ty, &freevars, store));
     fill_fn_pair(bcx, dest_addr, llfn, llbox);
     bcx
 }
 
+/// Returns the LLVM function declaration for an unboxed closure, creating it
+/// if necessary. If the ID does not correspond to a closure ID, returns None.
+pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
+                                                    closure_id: ast::DefId)
+                                                    -> Option<ValueRef> {
+    if !ccx.tcx.unboxed_closure_types.borrow().contains_key(&closure_id) {
+        // Not an unboxed closure.
+        return None
+    }
+
+    match ccx.unboxed_closure_vals.borrow().find(&closure_id) {
+        Some(llfn) => {
+            debug!("get_or_create_declaration_if_unboxed_closure(): found \
+                    closure");
+            return Some(*llfn)
+        }
+        None => {}
+    }
+
+    let function_type = ty::mk_unboxed_closure(&ccx.tcx, closure_id);
+    let symbol = ccx.tcx.map.with_path(closure_id.node, |path| {
+        mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
+    });
+
+    let llfn = decl_internal_rust_fn(ccx, function_type, symbol.as_slice());
+
+    // set an inline hint for all closures
+    set_inline_hint(llfn);
+
+    debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
+            closure {} (type {})",
+           closure_id,
+           ccx.tn.type_to_string(val_ty(llfn)));
+    ccx.unboxed_closure_vals.borrow_mut().insert(closure_id, llfn);
+
+    Some(llfn)
+}
+
+pub fn trans_unboxed_closure<'a>(
+                             mut bcx: &'a Block<'a>,
+                             decl: &ast::FnDecl,
+                             body: &ast::Block,
+                             id: ast::NodeId,
+                             dest: expr::Dest)
+                             -> &'a Block<'a> {
+    let _icx = push_ctxt("closure::trans_unboxed_closure");
+
+    debug!("trans_unboxed_closure()");
+
+    let closure_id = ast_util::local_def(id);
+    let llfn = get_or_create_declaration_if_unboxed_closure(
+        bcx.ccx(),
+        closure_id).unwrap();
+
+    // Untuple the arguments.
+    let unboxed_closure_types = bcx.tcx().unboxed_closure_types.borrow();
+    let /*mut*/ function_type = (*unboxed_closure_types.get(&closure_id)).clone();
+    /*function_type.sig.inputs =
+        match ty::get(*function_type.sig.inputs.get(0)).sty {
+            ty::ty_tup(ref tuple_types) => {
+                tuple_types.iter().map(|x| (*x).clone()).collect()
+            }
+            _ => {
+                bcx.tcx().sess.span_bug(body.span,
+                                        "unboxed closure wasn't a tuple?!")
+            }
+        };*/
+    let function_type = ty::mk_closure(bcx.tcx(), function_type);
+
+    let freevars: Vec<freevars::freevar_entry> =
+        freevars::with_freevars(bcx.tcx(),
+                                id,
+                                |fv| fv.iter().map(|&fv| fv).collect());
+    let freevars_ptr = &freevars;
+
+    trans_closure(bcx.ccx(),
+                  decl,
+                  body,
+                  llfn,
+                  bcx.fcx.param_substs,
+                  id,
+                  [],
+                  ty::ty_fn_args(function_type),
+                  ty::ty_fn_ret(function_type),
+                  ty::ty_fn_abi(function_type),
+                  true,
+                  IsUnboxedClosure,
+                  |bcx| load_unboxed_closure_environment(bcx, freevars_ptr));
+
+    // Don't hoist this to the top of the function. It's perfectly legitimate
+    // to have a zero-size unboxed closure (in which case dest will be
+    // `Ignore`) and we must still generate the closure body.
+    let dest_addr = match dest {
+        expr::SaveIn(p) => p,
+        expr::Ignore => {
+            debug!("trans_unboxed_closure() ignoring result");
+            return bcx
+        }
+    };
+
+    let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
+
+    // Create the closure.
+    adt::trans_start_init(bcx, &*repr, dest_addr, 0);
+    for freevar in freevars_ptr.iter() {
+        let datum = expr::trans_local_var(bcx, freevar.def);
+        let upvar_slot_dest = adt::trans_field_ptr(bcx,
+                                                   &*repr,
+                                                   dest_addr,
+                                                   0,
+                                                   0);
+        bcx = datum.store_to(bcx, upvar_slot_dest);
+    }
+
+    bcx
+}
+
 pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
                                closure_ty: ty::t,
                                def: def::Def,
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 945185f5953..320e291e928 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -71,7 +71,8 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
     }
     match ty::get(ty).sty {
         ty::ty_bot => true,
-        ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => {
+        ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) |
+        ty::ty_unboxed_closure(..) => {
             let llty = sizing_type_of(ccx, ty);
             llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
         }
@@ -632,12 +633,6 @@ pub fn C_bytes(ccx: &CrateContext, bytes: &[u8]) -> ValueRef {
     }
 }
 
-pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
-    unsafe {
-        llvm::LLVMGetParam(fndecl, param as c_uint)
-    }
-}
-
 pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
                   -> ValueRef {
     unsafe {
@@ -792,6 +787,9 @@ pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
         typeck::vtable_param(n_param, n_bound) => {
             find_vtable(tcx, param_substs, n_param, n_bound)
         }
+        typeck::vtable_unboxed_closure(def_id) => {
+            typeck::vtable_unboxed_closure(def_id)
+        }
         typeck::vtable_error => typeck::vtable_error
     }
 }
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 8c55f33a0d4..be39d435ee4 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -117,6 +117,10 @@ pub struct CrateContext {
     pub int_type: Type,
     pub opaque_vec_type: Type,
     pub builder: BuilderRef_res,
+
+    /// Holds the LLVM values for closure IDs.
+    pub unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
+
     /// Set when at least one function uses GC. Needed so that
     /// decl_gc_metadata knows whether to link to the module metadata, which
     /// is not emitted by LLVM's GC pass when no functions use GC.
@@ -225,6 +229,7 @@ impl CrateContext {
                 int_type: Type::from_ref(ptr::mut_null()),
                 opaque_vec_type: Type::from_ref(ptr::mut_null()),
                 builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
+                unboxed_closure_vals: RefCell::new(DefIdMap::new()),
                 uses_gc: false,
                 dbg_cx: dbg_cx,
                 eh_personality: RefCell::new(None),
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 8ecdf907fc4..47e94175546 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -452,7 +452,8 @@ impl TypeMap {
                                                onceness,
                                                store,
                                                ref bounds,
-                                               ref sig }) => {
+                                               ref sig,
+                                               abi: _ }) => {
                 if fn_style == ast::UnsafeFn {
                     unique_type_id.push_str("unsafe ");
                 }
@@ -1150,7 +1151,8 @@ pub fn create_function_debug_context(cx: &CrateContext,
         ast_map::NodeExpr(ref expr) => {
             match expr.node {
                 ast::ExprFnBlock(fn_decl, top_level_block) |
-                ast::ExprProc(fn_decl, top_level_block) => {
+                ast::ExprProc(fn_decl, top_level_block) |
+                ast::ExprUnboxedFn(fn_decl, top_level_block) => {
                     let name = format!("fn{}", token::gensym("fn"));
                     let name = token::str_to_ident(name.as_slice());
                     (name, fn_decl,
@@ -3602,7 +3604,8 @@ fn populate_scope_map(cx: &CrateContext,
             }
 
             ast::ExprFnBlock(ref decl, ref block) |
-            ast::ExprProc(ref decl, ref block) => {
+            ast::ExprProc(ref decl, ref block) |
+            ast::ExprUnboxedFn(ref decl, ref block) => {
                 with_new_scope(cx,
                                block.span,
                                scope_stack,
@@ -3877,6 +3880,9 @@ fn push_debuginfo_type_name(cx: &CrateContext,
                 push_debuginfo_type_name(cx, sig.output, true, output);
             }
         },
+        ty::ty_unboxed_closure(_) => {
+            output.push_str("closure");
+        }
         ty::ty_err      |
         ty::ty_infer(_) |
         ty::ty_param(_) => {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 60bf80191cb..e7bde00b3de 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -783,12 +783,14 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
                    expr_to_string(expr), expr_ty.repr(tcx));
             closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
         }
+        ast::ExprUnboxedFn(decl, body) => {
+            closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
+        }
         ast::ExprCall(ref f, ref args) => {
             if bcx.tcx().is_method_call(expr.id) {
-                let callee_datum = unpack_datum!(bcx, trans(bcx, &**f));
                 trans_overloaded_call(bcx,
                                       expr,
-                                      callee_datum,
+                                      *f,
                                       args.as_slice(),
                                       Some(dest))
             } else {
@@ -1502,54 +1504,18 @@ fn trans_overloaded_op<'a, 'b>(
 fn trans_overloaded_call<'a>(
                          mut bcx: &'a Block<'a>,
                          expr: &ast::Expr,
-                         callee: Datum<Expr>,
+                         callee: Gc<ast::Expr>,
                          args: &[Gc<ast::Expr>],
                          dest: Option<Dest>)
                          -> &'a Block<'a> {
-    // Evaluate and tuple the arguments.
-    let tuple_type = ty::mk_tup(bcx.tcx(),
-                                args.iter()
-                                    .map(|e| ty::expr_ty_adjusted(bcx.tcx(), &**e))
-                                    .collect());
-    let repr = adt::represent_type(bcx.ccx(), tuple_type);
-    let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
-        args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
-    let argument_scope = bcx.fcx.push_custom_cleanup_scope();
-    let tuple_datum =
-        unpack_datum!(bcx,
-                      lvalue_scratch_datum(bcx,
-                                           tuple_type,
-                                           "tupled_arguments",
-                                           false,
-                                           cleanup::CustomScope(
-                                               argument_scope),
-                                           (),
-                                           |(), bcx, addr| {
-            trans_adt(bcx,
-                      &*repr,
-                      0,
-                      numbered_fields.as_slice(),
-                      None,
-                      SaveIn(addr))
-        }));
-
     let method_call = MethodCall::expr(expr.id);
     let method_type = bcx.tcx()
                          .method_map
                          .borrow()
                          .get(&method_call)
                          .ty;
-    let callee_rvalue = unpack_datum!(bcx,
-                                      callee.to_rvalue_datum(bcx, "callee"));
-    let tuple_datum = tuple_datum.to_expr_datum();
-    let tuple_rvalue = unpack_datum!(bcx,
-                                     tuple_datum.to_rvalue_datum(bcx,
-                                                                 "tuple"));
-    let argument_values = [
-        callee_rvalue.add_clean(bcx.fcx,
-                                cleanup::CustomScope(argument_scope)),
-        tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope))
-    ];
+    let mut all_args = vec!(callee);
+    all_args.push_all(args);
     unpack_result!(bcx,
                    callee::trans_call_inner(bcx,
                                             Some(expr_info(expr)),
@@ -1562,10 +1528,9 @@ fn trans_overloaded_call<'a>(
                                                     None,
                                                     arg_cleanup_scope)
                                             },
-                                            callee::ArgVals(argument_values),
+                                            callee::ArgOverloadedCall(
+                                                all_args.as_slice()),
                                             dest));
-
-    bcx.fcx.pop_custom_cleanup_scope(argument_scope);
     bcx
 }
 
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 56fbccefede..d7630d7ec3a 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -10,8 +10,8 @@
 
 
 use back::{link};
+use llvm::{ValueRef, CallConv, Linkage, get_param};
 use llvm;
-use llvm::{ValueRef, CallConv, Linkage};
 use middle::weak_lang_items;
 use middle::trans::base::push_ctxt;
 use middle::trans::base;
@@ -27,7 +27,7 @@ use middle::ty;
 use std::cmp;
 use libc::c_uint;
 use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
-use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System};
+use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
 use syntax::codemap::Span;
 use syntax::parse::token::{InternedString, special_idents};
 use syntax::parse::token;
@@ -84,6 +84,11 @@ pub fn llvm_calling_convention(ccx: &CrateContext,
                 ccx.sess().unimpl("foreign functions with Rust ABI");
             }
 
+            RustCall => {
+                // FIXME(#3678) Implement linking to foreign fns with Rust ABI
+                ccx.sess().unimpl("foreign functions with RustCall ABI");
+            }
+
             // It's the ABI's job to select this, not us.
             System => ccx.sess().bug("system abi should be selected elsewhere"),
 
@@ -646,7 +651,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
         // If there is an out pointer on the foreign function
         let foreign_outptr = {
             if tys.fn_ty.ret_ty.is_indirect() {
-                Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false)))
+                Some(get_param(llwrapfn, next_foreign_arg(false)))
             } else {
                 None
             }
@@ -708,7 +713,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
 
             // skip padding
             let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
-            let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
+            let mut llforeign_arg = get_param(llwrapfn, foreign_index);
 
             debug!("llforeign_arg {}{}: {}", "#",
                    i, ccx.tn.val_to_string(llforeign_arg));
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 40065d0bc50..aad7ba95a73 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -15,8 +15,8 @@
 
 use back::abi;
 use back::link::*;
+use llvm::{ValueRef, True, get_param};
 use llvm;
-use llvm::{ValueRef, True};
 use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
 use middle::subst;
 use middle::trans::adt;
@@ -353,6 +353,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
                 }
             }
         }
+        ty::ty_unboxed_closure(..) => iter_structural_ty(bcx, v0, t, drop_ty),
         ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
             let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
             let env = Load(bcx, box_cell_v);
@@ -502,7 +503,7 @@ fn make_generic_glue(ccx: &CrateContext,
     // llfn is expected be declared to take a parameter of the appropriate
     // type, so we don't need to explicitly cast the function parameter.
 
-    let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) };
+    let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
     let bcx = helper(bcx, llrawptr0, t);
     finish_fn(&fcx, bcx, ty::mk_nil());
 
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index bb33a5e4f8d..2e3d7b291ea 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -29,6 +29,7 @@ use middle::trans::machine;
 use middle::trans::machine::llsize_of;
 use middle::trans::type_::Type;
 use middle::ty;
+use syntax::abi::RustIntrinsic;
 use syntax::ast;
 use syntax::parse::token;
 use util::ppaux::ty_to_string;
@@ -193,8 +194,13 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
 
     // Push the arguments.
     let mut llargs = Vec::new();
-    bcx = callee::trans_args(bcx, args, callee_ty, &mut llargs,
-                             cleanup::CustomScope(cleanup_scope), false);
+    bcx = callee::trans_args(bcx,
+                             args,
+                             callee_ty,
+                             &mut llargs,
+                             cleanup::CustomScope(cleanup_scope),
+                             false,
+                             RustIntrinsic);
 
     fcx.pop_custom_cleanup_scope(cleanup_scope);
 
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index ba44314d962..53f89c9d8b8 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -13,6 +13,7 @@ use back::abi;
 use llvm;
 use llvm::ValueRef;
 use metadata::csearch;
+use middle::subst::VecPerParamSpace;
 use middle::subst;
 use middle::trans::base::*;
 use middle::trans::build::*;
@@ -35,7 +36,7 @@ use util::ppaux::Repr;
 
 use std::c_str::ToCStr;
 use std::gc::Gc;
-use syntax::abi::Rust;
+use syntax::abi::{Rust, RustCall};
 use syntax::parse::token;
 use syntax::{ast, ast_map, visit};
 use syntax::ast_util::PostExpansionMethod;
@@ -104,10 +105,13 @@ pub fn trans_method_callee<'a>(
     };
 
     match origin {
-        typeck::MethodStatic(did) => {
+        typeck::MethodStatic(did) |
+        typeck::MethodStaticUnboxedClosure(did) => {
             Callee {
                 bcx: bcx,
-                data: Fn(callee::trans_fn_ref(bcx, did, MethodCall(method_call)))
+                data: Fn(callee::trans_fn_ref(bcx,
+                                              did,
+                                              MethodCall(method_call))),
             }
         }
         typeck::MethodParam(typeck::MethodParam {
@@ -200,6 +204,9 @@ pub fn trans_static_method_callee(bcx: &Block,
             let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
             PointerCast(bcx, llfn, llty)
         }
+        typeck::vtable_unboxed_closure(_) => {
+            bcx.tcx().sess.bug("can't call a closure vtable in a static way");
+        }
         _ => {
             fail!("vtable_param left in monomorphized \
                    function's vtable substs");
@@ -225,12 +232,13 @@ fn method_with_name(ccx: &CrateContext,
     *meth_did
 }
 
-fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
-                                  method_call: MethodCall,
-                                  trait_id: ast::DefId,
-                                  n_method: uint,
-                                  vtbl: typeck::vtable_origin)
-                                  -> Callee<'a> {
+fn trans_monomorphized_callee<'a>(
+                              bcx: &'a Block<'a>,
+                              method_call: MethodCall,
+                              trait_id: ast::DefId,
+                              n_method: uint,
+                              vtbl: typeck::vtable_origin)
+                              -> Callee<'a> {
     let _icx = push_ctxt("meth::trans_monomorphized_callee");
     match vtbl {
       typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
@@ -253,6 +261,26 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
 
           Callee { bcx: bcx, data: Fn(llfn) }
       }
+      typeck::vtable_unboxed_closure(closure_def_id) => {
+          // The static region and type parameters are lies, but we're in
+          // trans so it doesn't matter.
+          //
+          // FIXME(pcwalton): Is this true in the case of type parameters?
+          let callee_substs = get_callee_substitutions_for_unboxed_closure(
+                bcx,
+                closure_def_id);
+
+          let llfn = trans_fn_ref_with_vtables(bcx,
+                                               closure_def_id,
+                                               MethodCall(method_call),
+                                               callee_substs,
+                                               VecPerParamSpace::empty());
+
+          Callee {
+              bcx: bcx,
+              data: Fn(llfn),
+          }
+      }
       typeck::vtable_param(..) => {
           bcx.tcx().sess.bug(
               "vtable_param left in monomorphized function's vtable substs");
@@ -385,8 +413,12 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
     debug!("(translating trait callee) loading method");
     // Replace the self type (&Self or Box<Self>) with an opaque pointer.
     let llcallee_ty = match ty::get(callee_ty).sty {
-        ty::ty_bare_fn(ref f) if f.abi == Rust => {
-            type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
+        ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => {
+            type_of_rust_fn(ccx,
+                            Some(Type::i8p(ccx)),
+                            f.sig.inputs.slice_from(1),
+                            f.sig.output,
+                            f.abi)
         }
         _ => {
             ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
@@ -409,6 +441,26 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
     };
 }
 
+/// Creates the self type and (fake) callee substitutions for an unboxed
+/// closure with the given def ID. The static region and type parameters are
+/// lies, but we're in trans so it doesn't matter.
+fn get_callee_substitutions_for_unboxed_closure(bcx: &Block,
+                                                def_id: ast::DefId)
+                                                -> subst::Substs {
+    let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id);
+    subst::Substs::erased(
+        VecPerParamSpace::new(Vec::new(),
+                              vec![
+                                  ty::mk_rptr(bcx.tcx(),
+                                              ty::ReStatic,
+                                              ty::mt {
+                                                ty: self_ty,
+                                                mutbl: ast::MutMutable,
+                                              })
+                              ],
+                              Vec::new()))
+}
+
 /// Creates a returns a dynamic vtable for the given type and vtable origin.
 /// This is used only for objects.
 fn get_vtable(bcx: &Block,
@@ -436,6 +488,21 @@ fn get_vtable(bcx: &Block,
             typeck::vtable_static(id, substs, sub_vtables) => {
                 emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter()
             }
+            typeck::vtable_unboxed_closure(closure_def_id) => {
+                let callee_substs =
+                    get_callee_substitutions_for_unboxed_closure(
+                        bcx,
+                        closure_def_id);
+
+                let llfn = trans_fn_ref_with_vtables(
+                    bcx,
+                    closure_def_id,
+                    ExprId(0),
+                    callee_substs,
+                    VecPerParamSpace::empty());
+
+                (vec!(llfn)).move_iter()
+            }
             _ => ccx.sess().bug("get_vtable: expected a static origin"),
         }
     });
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 6ff6c4741c7..dac3b6bd8ee 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -254,6 +254,13 @@ pub fn make_vtable_id(_ccx: &CrateContext,
             }
         }
 
+        &typeck::vtable_unboxed_closure(def_id) => {
+            MonoId {
+                def: def_id,
+                params: subst::VecPerParamSpace::empty(),
+            }
+        }
+
         // can't this be checked at the callee?
         _ => fail!("make_vtable_id needs vtable_static")
     }
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index bc156fc3791..7d8700b9426 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use back::link::mangle_internal_name_by_path_and_seq;
-use llvm;
-use llvm::{ValueRef};
+use llvm::{ValueRef, get_param};
 use middle::trans::adt;
 use middle::trans::base::*;
 use middle::trans::build::*;
@@ -316,14 +315,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
                                       None, &arena);
                 let bcx = init_function(&fcx, false, ty::mk_u64());
 
-                let arg = unsafe {
-                    //
-                    // we know the return type of llfdecl is an int here, so
-                    // no need for a special check to see if the return type
-                    // is immediate.
-                    //
-                    llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
-                };
+                // we know the return type of llfdecl is an int here, so
+                // no need for a special check to see if the return type
+                // is immediate.
+                let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
                 let arg = BitCast(bcx, arg, llptrty);
                 let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
                 Store(bcx, ret, fcx.llretptr.get().unwrap());
@@ -366,6 +361,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
           // Miscellaneous extra types
           ty::ty_infer(_) => self.leaf("infer"),
           ty::ty_err => self.leaf("err"),
+          ty::ty_unboxed_closure(..) => self.leaf("err"),
           ty::ty_param(ref p) => {
               let extra = vec!(self.c_uint(p.idx));
               self.visit("param", extra.as_slice())
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index f54ab190d5e..94c376c09c8 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -39,10 +39,56 @@ pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
     }
 }
 
-pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
-                       inputs: &[ty::t], output: ty::t) -> Type {
+/// Yields the types of the "real" arguments for this function. For most
+/// functions, these are simply the types of the arguments. For functions with
+/// the `RustCall` ABI, however, this untuples the arguments of the function.
+fn untuple_arguments_if_necessary(ccx: &CrateContext,
+                                  inputs: &[ty::t],
+                                  abi: abi::Abi)
+                                  -> Vec<ty::t> {
+    if abi != abi::RustCall {
+        return inputs.iter().map(|x| (*x).clone()).collect()
+    }
+
+    if inputs.len() == 0 {
+        return Vec::new()
+    }
+
+    let mut result = Vec::new();
+    for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
+        if i < inputs.len() - 1 {
+            result.push(arg_prior_to_tuple);
+        }
+    }
+
+    match ty::get(inputs[inputs.len() - 1]).sty {
+        ty::ty_tup(ref tupled_arguments) => {
+            debug!("untuple_arguments_if_necessary(): untupling arguments");
+            for &tupled_argument in tupled_arguments.iter() {
+                result.push(tupled_argument);
+            }
+        }
+        ty::ty_nil => {}
+        _ => {
+            ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
+                                is neither a tuple nor unit")
+        }
+    }
+
+    result
+}
+
+pub fn type_of_rust_fn(cx: &CrateContext,
+                       llenvironment_type: Option<Type>,
+                       inputs: &[ty::t],
+                       output: ty::t,
+                       abi: abi::Abi)
+                       -> Type {
     let mut atys: Vec<Type> = Vec::new();
 
+    // First, munge the inputs, if this has the `rust-call` ABI.
+    let inputs = untuple_arguments_if_necessary(cx, inputs, abi);
+
     // Arg 0: Output pointer.
     // (if the output type is non-immediate)
     let use_out_pointer = return_uses_outptr(cx, output);
@@ -52,8 +98,9 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
     }
 
     // Arg 1: Environment
-    if has_env {
-        atys.push(Type::i8p(cx));
+    match llenvironment_type {
+        None => {}
+        Some(llenvironment_type) => atys.push(llenvironment_type),
     }
 
     // ... then explicit args.
@@ -72,16 +119,19 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
 pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
     match ty::get(fty).sty {
         ty::ty_closure(ref f) => {
-            type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output)
+            type_of_rust_fn(cx,
+                            Some(Type::i8p(cx)),
+                            f.sig.inputs.as_slice(),
+                            f.sig.output,
+                            f.abi)
         }
         ty::ty_bare_fn(ref f) => {
-            if f.abi == abi::Rust {
+            if f.abi == abi::Rust || f.abi == abi::RustCall {
                 type_of_rust_fn(cx,
-                                false,
+                                None,
                                 f.sig.inputs.as_slice(),
-                                f.sig.output)
-            } else if f.abi == abi::RustIntrinsic {
-                cx.sess().bug("type_of_fn_from_ty given intrinsic")
+                                f.sig.output,
+                                f.abi)
             } else {
                 foreign::lltype_for_foreign_fn(cx, fty)
             }
@@ -142,7 +192,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
             Type::array(&sizing_type_of(cx, mt.ty), size as u64)
         }
 
-        ty::ty_tup(..) | ty::ty_enum(..) => {
+        ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => {
             let repr = adt::represent_type(cx, t);
             adt::sizing_type_of(cx, &*repr)
         }
@@ -223,6 +273,13 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
         let name = llvm_type_name(cx, an_enum, did, tps);
         adt::incomplete_type_of(cx, &*repr, name.as_slice())
       }
+      ty::ty_unboxed_closure(did) => {
+        // Only create the named struct, but don't fill it in. We
+        // fill it in *after* placing it into the type cache.
+        let repr = adt::represent_type(cx, t);
+        let name = llvm_type_name(cx, an_unboxed_closure, did, []);
+        adt::incomplete_type_of(cx, &*repr, name.as_slice())
+      }
       ty::ty_box(typ) => {
           Type::at_box(cx, type_of(cx, typ)).ptr_to()
       }
@@ -299,7 +356,8 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
 
     // If this was an enum or struct, fill in the type now.
     match ty::get(t).sty {
-        ty::ty_enum(..) | ty::ty_struct(..) if !ty::type_is_simd(cx.tcx(), t) => {
+        ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_unboxed_closure(..)
+                if !ty::type_is_simd(cx.tcx(), t) => {
             let repr = adt::represent_type(cx, t);
             adt::finish_type_of(cx, &*repr, &mut llty);
         }
@@ -310,7 +368,11 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
 }
 
 // Want refinements! (Or case classes, I guess
-pub enum named_ty { a_struct, an_enum }
+pub enum named_ty {
+    a_struct,
+    an_enum,
+    an_unboxed_closure,
+}
 
 pub fn llvm_type_name(cx: &CrateContext,
                       what: named_ty,
@@ -319,8 +381,9 @@ pub fn llvm_type_name(cx: &CrateContext,
                       -> String
 {
     let name = match what {
-        a_struct => { "struct" }
-        an_enum => { "enum" }
+        a_struct => "struct",
+        an_enum => "enum",
+        an_unboxed_closure => return "closure".to_string(),
     };
 
     let base = ty::item_path_str(cx.tcx(), did);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 95ec4373830..50563d42e44 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -18,7 +18,7 @@ use lint;
 use middle::const_eval;
 use middle::def;
 use middle::dependency_format;
-use middle::lang_items::OpaqueStructLangItem;
+use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
 use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
 use middle::freevars;
 use middle::resolve;
@@ -370,6 +370,10 @@ pub struct ctxt {
 
     pub dependency_formats: RefCell<dependency_format::Dependencies>,
 
+    /// Records the type of each unboxed closure. The def ID is the ID of the
+    /// expression defining the unboxed closure.
+    pub unboxed_closure_types: RefCell<DefIdMap<ClosureTy>>,
+
     pub node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId),
                                           lint::LevelSource>>,
 
@@ -454,6 +458,7 @@ pub struct ClosureTy {
     pub store: TraitStore,
     pub bounds: BuiltinBounds,
     pub sig: FnSig,
+    pub abi: abi::Abi,
 }
 
 /**
@@ -736,6 +741,7 @@ pub enum sty {
     ty_closure(Box<ClosureTy>),
     ty_trait(Box<TyTrait>),
     ty_struct(DefId, Substs),
+    ty_unboxed_closure(DefId),
     ty_tup(Vec<t>),
 
     ty_param(ParamTy), // type parameter
@@ -1054,7 +1060,7 @@ pub fn mk_ctxt(s: Session,
                region_maps: middle::region::RegionMaps,
                lang_items: middle::lang_items::LanguageItems,
                stability: stability::Index)
-            -> ctxt {
+               -> ctxt {
     ctxt {
         named_region_map: named_region_map,
         item_variance_map: RefCell::new(DefIdMap::new()),
@@ -1106,6 +1112,7 @@ pub fn mk_ctxt(s: Session,
         method_map: RefCell::new(FnvHashMap::new()),
         vtable_map: RefCell::new(FnvHashMap::new()),
         dependency_formats: RefCell::new(HashMap::new()),
+        unboxed_closure_types: RefCell::new(DefIdMap::new()),
         node_lint_levels: RefCell::new(HashMap::new()),
         transmute_restrictions: RefCell::new(Vec::new()),
         stability: RefCell::new(stability)
@@ -1164,7 +1171,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
     }
     match &st {
       &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
-      &ty_str => {}
+      &ty_str | &ty_unboxed_closure(_) => {}
       // You might think that we could just return ty_err for
       // any type containing ty_err as a component, and get
       // rid of the has_ty_err flag -- likewise for ty_bot (with
@@ -1429,6 +1436,10 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t {
     mk_t(cx, ty_struct(struct_id, substs))
 }
 
+pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId) -> t {
+    mk_t(cx, ty_unboxed_closure(closure_id))
+}
+
 pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
 
 pub fn mk_int_var(cx: &ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
@@ -1459,7 +1470,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
     }
     match get(ty).sty {
         ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
-        ty_str | ty_infer(_) | ty_param(_) | ty_err => {
+        ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => {
         }
         ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
         ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => {
@@ -1567,7 +1578,7 @@ pub fn type_is_vec(ty: t) -> bool {
 pub fn type_is_structural(ty: t) -> bool {
     match get(ty).sty {
       ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
-      ty_vec(_, Some(_)) => true,
+      ty_vec(_, Some(_)) | ty_unboxed_closure(_) => true,
       _ => type_is_slice(ty) | type_is_trait(ty)
     }
 }
@@ -2082,6 +2093,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
                 apply_lang_items(cx, did, res)
             }
 
+            ty_unboxed_closure(did) => {
+                let upvars = unboxed_closure_upvars(cx, did);
+                TypeContents::union(upvars.as_slice(),
+                                    |f| tc_ty(cx, f.ty, cache))
+            }
+
             ty_tup(ref tys) => {
                 TypeContents::union(tys.as_slice(),
                                     |ty| tc_ty(cx, *ty, cache))
@@ -2323,6 +2340,11 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
                 r
             }
 
+            ty_unboxed_closure(did) => {
+                let upvars = unboxed_closure_upvars(cx, did);
+                upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
+            }
+
             ty_tup(ref ts) => {
                 ts.iter().any(|t| type_requires(cx, seen, r_ty, *t))
             }
@@ -2427,6 +2449,7 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
                 seen.pop();
                 r
             }
+
             ty_enum(did, ref substs) => {
                 seen.push(did);
                 let vs = enum_variants(cx, did);
@@ -2445,6 +2468,14 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
                 r
             }
 
+            ty_unboxed_closure(did) => {
+                let upvars = unboxed_closure_upvars(cx, did);
+                find_nonrepresentable(cx,
+                                      sp,
+                                      seen,
+                                      upvars.iter().map(|f| f.ty))
+            }
+
             _ => Representable,
         }
     }
@@ -2655,6 +2686,15 @@ pub fn ty_fn_sig(fty: t) -> FnSig {
     }
 }
 
+/// Returns the ABI of the given function.
+pub fn ty_fn_abi(fty: t) -> abi::Abi {
+    match get(fty).sty {
+        ty_bare_fn(ref f) => f.abi,
+        ty_closure(ref f) => f.abi,
+        _ => fail!("ty_fn_abi() called on non-fn type"),
+    }
+}
+
 // Type accessors for substructures of types
 pub fn ty_fn_args(fty: t) -> Vec<t> {
     match get(fty).sty {
@@ -2669,6 +2709,11 @@ pub fn ty_fn_args(fty: t) -> Vec<t> {
 pub fn ty_closure_store(fty: t) -> TraitStore {
     match get(fty).sty {
         ty_closure(ref f) => f.store,
+        ty_unboxed_closure(_) => {
+            // Close enough for the purposes of all the callers of this
+            // function (which is soon to be deprecated anyhow).
+            UniqTraitStore
+        }
         ref s => {
             fail!("ty_closure_store() called on non-closure type: {:?}", s)
         }
@@ -2816,11 +2861,14 @@ pub fn adjust_ty(cx: &ctxt,
                         ty::ty_bare_fn(ref b) => {
                             ty::mk_closure(
                                 cx,
-                                ty::ClosureTy {fn_style: b.fn_style,
-                                               onceness: ast::Many,
-                                               store: store,
-                                               bounds: ty::all_builtin_bounds(),
-                                               sig: b.sig.clone()})
+                                ty::ClosureTy {
+                                    fn_style: b.fn_style,
+                                    onceness: ast::Many,
+                                    store: store,
+                                    bounds: ty::all_builtin_bounds(),
+                                    sig: b.sig.clone(),
+                                    abi: b.abi,
+                                })
                         }
                         ref b => {
                             cx.sess.bug(
@@ -2990,6 +3038,14 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
         typeck::MethodStatic(did) => {
             ty::lookup_item_type(tcx, did).generics.types.clone()
         }
+        typeck::MethodStaticUnboxedClosure(_) => {
+            match tcx.lang_items.require(FnMutTraitLangItem) {
+                Ok(def_id) => {
+                    lookup_trait_def(tcx, def_id).generics.types.clone()
+                }
+                Err(s) => tcx.sess.fatal(s.as_slice()),
+            }
+        }
         typeck::MethodParam(typeck::MethodParam{trait_id: trt_id,
                                                 method_num: n_mth, ..}) |
         typeck::MethodObject(typeck::MethodObject{trait_id: trt_id,
@@ -3104,6 +3160,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
         ast::ExprMatch(..) |
         ast::ExprFnBlock(..) |
         ast::ExprProc(..) |
+        ast::ExprUnboxedFn(..) |
         ast::ExprBlock(..) |
         ast::ExprRepeat(..) |
         ast::ExprVstore(_, ast::ExprVstoreSlice) |
@@ -3250,6 +3307,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
         ty_struct(id, _) => {
             format!("struct {}", item_path_str(cx, id))
         }
+        ty_unboxed_closure(_) => "closure".to_string(),
         ty_tup(_) => "tuple".to_string(),
         ty_infer(TyVar(_)) => "inferred type".to_string(),
         ty_infer(IntVar(_)) => "integral variable".to_string(),
@@ -3617,7 +3675,8 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
     match get(ty).sty {
         ty_trait(box TyTrait { def_id: id, .. }) |
         ty_struct(id, _) |
-        ty_enum(id, _) => Some(id),
+        ty_enum(id, _) |
+        ty_unboxed_closure(id) => Some(id),
         _ => None
     }
 }
@@ -4046,6 +4105,34 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
     }).collect()
 }
 
+pub struct UnboxedClosureUpvar {
+    pub def: def::Def,
+    pub span: Span,
+    pub ty: t,
+}
+
+// Returns a list of `UnboxedClosureUpvar`s for each upvar.
+pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId)
+                              -> Vec<UnboxedClosureUpvar> {
+    if closure_id.krate == ast::LOCAL_CRATE {
+        match tcx.freevars.borrow().find(&closure_id.node) {
+            None => tcx.sess.bug("no freevars for unboxed closure?!"),
+            Some(ref freevars) => {
+                freevars.iter().map(|freevar| {
+                    let freevar_def_id = freevar.def.def_id();
+                    UnboxedClosureUpvar {
+                        def: freevar.def,
+                        span: freevar.span,
+                        ty: node_id_to_type(tcx, freevar_def_id.node),
+                    }
+                }).collect()
+            }
+        }
+    } else {
+        tcx.sess.bug("unimplemented cross-crate closure upvars")
+    }
+}
+
 pub fn is_binopable(cx: &ctxt, ty: t, op: ast::BinOp) -> bool {
     static tycat_other: int = 0;
     static tycat_bool: int = 1;
@@ -4623,6 +4710,10 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
             }
             ty_infer(_) => unreachable!(),
             ty_err => byte!(23),
+            ty_unboxed_closure(d) => {
+                byte!(24);
+                did(&mut state, d);
+            }
         }
     });
 
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index c90d9af9b78..e2b98495906 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -220,6 +220,9 @@ impl TypeFoldable for typeck::vtable_origin {
             typeck::vtable_param(n, b) => {
                 typeck::vtable_param(n, b)
             }
+            typeck::vtable_unboxed_closure(def_id) => {
+                typeck::vtable_unboxed_closure(def_id)
+            }
             typeck::vtable_error => {
                 typeck::vtable_error
             }
@@ -326,6 +329,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
         fn_style: fty.fn_style,
         onceness: fty.onceness,
         bounds: fty.bounds,
+        abi: fty.abi,
     }
 }
 
@@ -388,6 +392,9 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
         ty::ty_struct(did, ref substs) => {
             ty::ty_struct(did, substs.fold_with(this))
         }
+        ty::ty_unboxed_closure(did) => {
+            ty::ty_unboxed_closure(did)
+        }
         ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
         ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
         ty::ty_err | ty::ty_infer(_) |
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 6d215282cc4..56fda065796 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -762,6 +762,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                                             bounds,
                                             store,
                                             &*f.decl,
+                                            abi::Rust,
                                             None);
                 ty::mk_closure(tcx, fn_decl)
             }
@@ -780,6 +781,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                                             bounds,
                                             ty::UniqTraitStore,
                                             &*f.decl,
+                                            abi::Rust,
                                             None);
                 ty::mk_closure(tcx, fn_decl)
             }
@@ -879,9 +881,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
             }
             ast::TyInfer => {
                 // TyInfer also appears as the type of arguments or return
-                // values in a ExprFnBlock or ExprProc, or as the type of
-                // local variables. Both of these cases are handled specially
-                // and will not descend into this routine.
+                // values in a ExprFnBlock, ExprProc, or ExprUnboxedFn, or as
+                // the type of local variables. Both of these cases are
+                // handled specially and will not descend into this routine.
                 this.ty_infer(ast_ty.span)
             }
         }
@@ -911,7 +913,8 @@ pub fn ty_of_method<AC:AstConv>(
                     fn_style: ast::FnStyle,
                     untransformed_self_ty: ty::t,
                     explicit_self: ast::ExplicitSelf,
-                    decl: &ast::FnDecl)
+                    decl: &ast::FnDecl,
+                    abi: abi::Abi)
                     -> (ty::BareFnTy, ty::ExplicitSelfCategory) {
     let self_info = Some(SelfInfo {
         untransformed_self_ty: untransformed_self_ty,
@@ -921,7 +924,7 @@ pub fn ty_of_method<AC:AstConv>(
         ty_of_method_or_bare_fn(this,
                                 id,
                                 fn_style,
-                                abi::Rust,
+                                abi,
                                 self_info,
                                 decl);
     (bare_fn_ty, optional_explicit_self_category.unwrap())
@@ -1083,6 +1086,7 @@ pub fn ty_of_closure<AC:AstConv>(
     bounds: ty::BuiltinBounds,
     store: ty::TraitStore,
     decl: &ast::FnDecl,
+    abi: abi::Abi,
     expected_sig: Option<ty::FnSig>)
     -> ty::ClosureTy
 {
@@ -1117,6 +1121,7 @@ pub fn ty_of_closure<AC:AstConv>(
         onceness: onceness,
         store: store,
         bounds: bounds,
+        abi: abi,
         sig: ty::FnSig {binder_id: id,
                         inputs: input_tys,
                         output: output_ty,
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index e12fae4f950..1805c18eaf1 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -87,10 +87,11 @@ use middle::ty;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
 use middle::typeck::check;
+use middle::typeck::infer::MiscVariable;
 use middle::typeck::infer;
 use middle::typeck::MethodCallee;
 use middle::typeck::{MethodOrigin, MethodParam};
-use middle::typeck::{MethodStatic, MethodObject};
+use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
 use middle::typeck::{param_index};
 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
 use middle::typeck::TypeAndSubsts;
@@ -341,7 +342,7 @@ struct Candidate {
 #[deriving(Clone)]
 pub enum RcvrMatchCondition {
     RcvrMatchesIfObject(ast::DefId),
-    RcvrMatchesIfSubtype(ty::t)
+    RcvrMatchesIfSubtype(ty::t),
 }
 
 impl<'a> LookupContext<'a> {
@@ -441,7 +442,9 @@ impl<'a> LookupContext<'a> {
                     }
                     _ => {}
                 },
-                ty_enum(did, _) | ty_struct(did, _) => {
+                ty_enum(did, _) |
+                ty_struct(did, _) |
+                ty_unboxed_closure(did) => {
                     if self.check_traits == CheckTraitsAndInherentMethods {
                         self.push_inherent_impl_candidates_for_type(did);
                     }
@@ -465,6 +468,10 @@ impl<'a> LookupContext<'a> {
                 ty_param(p) => {
                     self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
                 }
+                ty_unboxed_closure(closure_did) => {
+                    self.push_unboxed_closure_call_candidates_if_applicable(
+                        closure_did);
+                }
                 _ => { /* No bound methods in these types */ }
             }
 
@@ -497,11 +504,89 @@ impl<'a> LookupContext<'a> {
         let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
         for applicable_traits in opt_applicable_traits.move_iter() {
             for trait_did in applicable_traits.iter() {
+                debug!("push_extension_candidates() found trait: {}",
+                       if trait_did.krate == ast::LOCAL_CRATE {
+                           self.fcx.ccx.tcx.map.node_to_string(trait_did.node)
+                       } else {
+                           "(external)".to_string()
+                       });
                 self.push_extension_candidate(*trait_did);
             }
         }
     }
 
+    fn push_unboxed_closure_call_candidate_if_applicable(
+            &mut self,
+            trait_did: DefId,
+            closure_did: DefId,
+            closure_function_type: &ClosureTy) {
+        let method =
+            ty::trait_methods(self.tcx(), trait_did).get(0).clone();
+
+        let vcx = self.fcx.vtable_context();
+        let region_params =
+            vec!(vcx.infcx.next_region_var(MiscVariable(self.span)));
+
+        // Get the tupled type of the arguments.
+        let arguments_type = *closure_function_type.sig.inputs.get(0);
+        let return_type = closure_function_type.sig.output;
+
+        let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
+                                                          closure_did);
+        self.extension_candidates.push(Candidate {
+            rcvr_match_condition:
+                RcvrMatchesIfSubtype(unboxed_closure_type),
+            rcvr_substs: subst::Substs::new_trait(
+                vec![arguments_type, return_type],
+                region_params,
+                *vcx.infcx.next_ty_vars(1).get(0)),
+            method_ty: method,
+            origin: MethodStaticUnboxedClosure(closure_did),
+        });
+    }
+
+    fn push_unboxed_closure_call_candidates_if_applicable(
+            &mut self,
+            closure_did: DefId) {
+        // FIXME(pcwalton): Try `Fn` and `FnOnce` too.
+        let trait_did = match self.tcx().lang_items.fn_mut_trait() {
+            Some(trait_did) => trait_did,
+            None => return,
+        };
+
+        match self.tcx()
+                  .unboxed_closure_types
+                  .borrow()
+                  .find(&closure_did) {
+            None => {}  // Fall through to try inherited.
+            Some(closure_function_type) => {
+                self.push_unboxed_closure_call_candidate_if_applicable(
+                    trait_did,
+                    closure_did,
+                    closure_function_type);
+                return
+            }
+        }
+
+        match self.fcx
+                  .inh
+                  .unboxed_closure_types
+                  .borrow()
+                  .find(&closure_did) {
+            Some(closure_function_type) => {
+                self.push_unboxed_closure_call_candidate_if_applicable(
+                    trait_did,
+                    closure_did,
+                    closure_function_type);
+                return
+            }
+            None => {}
+        }
+
+        self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \
+                             inherited map, so there")
+    }
+
     fn push_inherent_candidates_from_object(&mut self,
                                             did: DefId,
                                             substs: &subst::Substs) {
@@ -926,7 +1011,8 @@ impl<'a> LookupContext<'a> {
             ty_infer(FloatVar(_)) |
             ty_param(..) | ty_nil | ty_bot | ty_bool |
             ty_char | ty_int(..) | ty_uint(..) |
-            ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) |
+            ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) |
+            ty_unboxed_closure(..) | ty_tup(..) |
             ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => {
                 self.search_for_some_kind_of_autorefd_method(
                     AutoPtr, autoderefs, [MutImmutable, MutMutable],
@@ -1212,7 +1298,9 @@ impl<'a> LookupContext<'a> {
          */
 
         match candidate.origin {
-            MethodStatic(..) | MethodParam(..) => {
+            MethodStatic(..) |
+            MethodParam(..) |
+            MethodStaticUnboxedClosure(..) => {
                 return; // not a call to a trait instance
             }
             MethodObject(..) => {}
@@ -1268,6 +1356,7 @@ impl<'a> LookupContext<'a> {
             MethodStatic(method_id) => {
                 bad = self.tcx().destructors.borrow().contains(&method_id);
             }
+            MethodStaticUnboxedClosure(_) => bad = false,
             // FIXME: does this properly enforce this on everything now
             // that self has been merged in? -sully
             MethodParam(MethodParam { trait_id: trait_id, .. }) |
@@ -1409,6 +1498,9 @@ impl<'a> LookupContext<'a> {
                 };
                 self.report_static_candidate(idx, did)
             }
+            MethodStaticUnboxedClosure(did) => {
+                self.report_static_candidate(idx, did)
+            }
             MethodParam(ref mp) => {
                 self.report_param_candidate(idx, (*mp).trait_id)
             }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 3b860be0f01..557fd522fa9 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -114,7 +114,7 @@ use lint;
 use util::common::{block_query, indenter, loop_query};
 use util::ppaux;
 use util::ppaux::{UserString, Repr};
-use util::nodemap::{FnvHashMap, NodeMap};
+use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
 
 use std::cell::{Cell, RefCell};
 use std::collections::HashMap;
@@ -167,6 +167,7 @@ pub struct Inherited<'a> {
     method_map: MethodMap,
     vtable_map: vtable_map,
     upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
+    unboxed_closure_types: RefCell<DefIdMap<ty::ClosureTy>>,
 }
 
 /// When type-checking an expression, we propagate downward
@@ -273,6 +274,7 @@ impl<'a> Inherited<'a> {
             method_map: RefCell::new(FnvHashMap::new()),
             vtable_map: RefCell::new(FnvHashMap::new()),
             upvar_borrow_map: RefCell::new(HashMap::new()),
+            unboxed_closure_types: RefCell::new(DefIdMap::new()),
         }
     }
 }
@@ -1251,7 +1253,8 @@ impl<'a> FnCtxt<'a> {
     pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
         VtableContext {
             infcx: self.infcx(),
-            param_env: &self.inh.param_env
+            param_env: &self.inh.param_env,
+            unboxed_closure_types: &self.inh.unboxed_closure_types,
         }
     }
 }
@@ -1861,7 +1864,8 @@ fn check_argument_types(fcx: &FnCtxt,
         for (i, arg) in args.iter().take(t).enumerate() {
             let is_block = match arg.node {
                 ast::ExprFnBlock(..) |
-                ast::ExprProc(..) => true,
+                ast::ExprProc(..) |
+                ast::ExprUnboxedFn(..) => true,
                 _ => false
             };
 
@@ -2514,6 +2518,47 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
         })
     }
 
+    fn check_unboxed_closure(fcx: &FnCtxt,
+                             expr: &ast::Expr,
+                             decl: &ast::FnDecl,
+                             body: ast::P<ast::Block>) {
+        // The `RegionTraitStore` is a lie, but we ignore it so it doesn't
+        // matter.
+        //
+        // FIXME(pcwalton): Refactor this API.
+        let mut fn_ty = astconv::ty_of_closure(
+            fcx,
+            expr.id,
+            ast::NormalFn,
+            ast::Many,
+            ty::empty_builtin_bounds(),
+            ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
+            decl,
+            abi::RustCall,
+            None);
+
+        let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
+                                                  local_def(expr.id));
+        fcx.write_ty(expr.id, closure_type);
+
+        check_fn(fcx.ccx,
+                 ast::NormalFn,
+                 &fn_ty.sig,
+                 decl,
+                 expr.id,
+                 &*body,
+                 fcx.inh);
+
+        // Tuple up the arguments and insert the resulting function type into
+        // the `unboxed_closure_types` table.
+        fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
+
+        fcx.inh
+           .unboxed_closure_types
+           .borrow_mut()
+           .insert(local_def(expr.id), fn_ty);
+    }
+
     fn check_expr_fn(fcx: &FnCtxt,
                      expr: &ast::Expr,
                      store: ty::TraitStore,
@@ -2577,6 +2622,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                            expected_bounds,
                                            store,
                                            decl,
+                                           abi::Rust,
                                            expected_sig);
         let fty_sig = fn_ty.sig.clone();
         let fty = ty::mk_closure(tcx, fn_ty);
@@ -2593,8 +2639,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             ty::UniqTraitStore => (ast::NormalFn, expr.id)
         };
 
-        check_fn(fcx.ccx, inherited_style, &fty_sig,
-                 &*decl, id, &*body, fcx.inh);
+        check_fn(fcx.ccx,
+                 inherited_style,
+                 &fty_sig,
+                 decl,
+                 id,
+                 &*body,
+                 fcx.inh);
     }
 
 
@@ -3241,6 +3292,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                       body.clone(),
                       expected);
       }
+      ast::ExprUnboxedFn(ref decl, ref body) => {
+        check_unboxed_closure(fcx,
+                              expr,
+                              &**decl,
+                              *body);
+      }
       ast::ExprProc(ref decl, ref body) => {
         check_expr_fn(fcx,
                       expr,
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 180dac53828..22d52d0b7d2 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -587,7 +587,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             visit::walk_expr(rcx, expr, ());
         }
 
-        ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => {
+        ast::ExprFnBlock(_, ref body) |
+        ast::ExprProc(_, ref body) |
+        ast::ExprUnboxedFn(_, ref body) => {
             check_expr_fn_block(rcx, expr, &**body);
         }
 
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index d2a1ef786bd..ea82a62d6c6 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -15,21 +15,23 @@ use middle::ty_fold::TypeFolder;
 use middle::typeck::astconv::AstConv;
 use middle::typeck::check::{FnCtxt, impl_self_ty};
 use middle::typeck::check::{structurally_resolved_type};
+use middle::typeck::check::regionmanip;
 use middle::typeck::check::writeback;
 use middle::typeck::infer::fixup_err_to_string;
 use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
 use middle::typeck::infer;
-use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
-use middle::typeck::{vtable_static, vtable_param, vtable_error};
-use middle::typeck::{param_index};
-use middle::typeck::MethodCall;
-use middle::typeck::TypeAndSubsts;
+use middle::typeck::{MethodCall, TypeAndSubsts};
+use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param};
+use middle::typeck::{vtable_param_res, vtable_res, vtable_static};
+use middle::typeck::{vtable_unboxed_closure};
 use middle::subst;
 use middle::subst::{Subst, VecPerParamSpace};
 use util::common::indenter;
+use util::nodemap::DefIdMap;
 use util::ppaux;
 use util::ppaux::Repr;
 
+use std::cell::RefCell;
 use std::rc::Rc;
 use std::collections::HashSet;
 use syntax::ast;
@@ -69,6 +71,7 @@ use syntax::visit::Visitor;
 pub struct VtableContext<'a> {
     pub infcx: &'a infer::InferCtxt<'a>,
     pub param_env: &'a ty::ParameterEnvironment,
+    pub unboxed_closure_types: &'a RefCell<DefIdMap<ty::ClosureTy>>,
 }
 
 impl<'a> VtableContext<'a> {
@@ -248,10 +251,13 @@ fn lookup_vtable(vcx: &VtableContext,
         ty::ty_param(ParamTy {space, idx: n, ..}) => {
             let env_bounds = &vcx.param_env.bounds;
             let type_param_bounds = &env_bounds.get(space, n).trait_bounds;
-            lookup_vtable_from_bounds(vcx, span,
+            lookup_vtable_from_bounds(vcx,
+                                      span,
                                       type_param_bounds.as_slice(),
-                                      param_index { space: space,
-                                                    index: n },
+                                      param_index {
+                                          space: space,
+                                          index: n,
+                                      },
                                       trait_ref.clone())
         }
 
@@ -297,6 +303,75 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
     ret
 }
 
+fn search_for_unboxed_closure_vtable(vcx: &VtableContext,
+                                     span: Span,
+                                     ty: ty::t,
+                                     trait_ref: Rc<ty::TraitRef>)
+                                     -> Option<vtable_origin> {
+    let tcx = vcx.tcx();
+    let closure_def_id = match ty::get(ty).sty {
+        ty::ty_unboxed_closure(closure_def_id) => closure_def_id,
+        _ => return None,
+    };
+
+    let fn_traits = [
+        tcx.lang_items.fn_trait(),
+        tcx.lang_items.fn_mut_trait(),
+        tcx.lang_items.fn_once_trait()
+    ];
+    for fn_trait in fn_traits.iter() {
+        match *fn_trait {
+            Some(ref fn_trait) if *fn_trait == trait_ref.def_id => {}
+            _ => continue,
+        };
+
+        // Check to see whether the argument and return types match.
+        let unboxed_closure_types = tcx.unboxed_closure_types.borrow();
+        let closure_type = match unboxed_closure_types.find(&closure_def_id) {
+            Some(closure_type) => (*closure_type).clone(),
+            None => {
+                // Try the inherited unboxed closure type map.
+                let unboxed_closure_types = vcx.unboxed_closure_types
+                                               .borrow();
+                match unboxed_closure_types.find(&closure_def_id) {
+                    Some(closure_type) => (*closure_type).clone(),
+                    None => {
+                        tcx.sess.span_bug(span,
+                                          "didn't find unboxed closure type \
+                                           in tcx map or inh map")
+                    }
+                }
+            }
+        };
+
+        // FIXME(pcwalton): This is a bogus thing to do, but
+        // it'll do for now until we get the new trait-bound
+        // region skolemization working.
+        let (_, new_signature) =
+            regionmanip::replace_late_bound_regions_in_fn_sig(
+                tcx,
+                &closure_type.sig,
+                |br| {
+                    vcx.infcx.next_region_var(infer::LateBoundRegion(span,
+                                                                     br))
+                });
+
+        let arguments_tuple = *new_signature.inputs.get(0);
+        let corresponding_trait_ref = Rc::new(ty::TraitRef {
+            def_id: trait_ref.def_id,
+            substs: subst::Substs::new_trait(
+                vec![arguments_tuple, new_signature.output],
+                Vec::new(),
+                ty)
+        });
+
+        relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref);
+        return Some(vtable_unboxed_closure(closure_def_id))
+    }
+
+    None
+}
+
 fn search_for_vtable(vcx: &VtableContext,
                      span: Span,
                      ty: ty::t,
@@ -306,6 +381,18 @@ fn search_for_vtable(vcx: &VtableContext,
     debug!("nrc - search_for_vtable");
     let tcx = vcx.tcx();
 
+    // First, check to see whether this is a call to the `call` method of an
+    // unboxed closure. If so, and the arguments match, we're done.
+    match search_for_unboxed_closure_vtable(vcx,
+                                            span,
+                                            ty,
+                                            trait_ref.clone()) {
+        Some(vtable_origin) => return Some(vtable_origin),
+        None => {}
+    }
+
+    // Nope. Continue.
+
     let mut found = Vec::new();
     let mut impls_seen = HashSet::new();
 
@@ -799,7 +886,12 @@ pub fn resolve_impl(tcx: &ty::ctxt,
     debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
 
     let infcx = &infer::new_infer_ctxt(tcx);
-    let vcx = VtableContext { infcx: infcx, param_env: &param_env };
+    let unboxed_closure_types = RefCell::new(DefIdMap::new());
+    let vcx = VtableContext {
+        infcx: infcx,
+        param_env: &param_env,
+        unboxed_closure_types: &unboxed_closure_types,
+    };
 
     // Resolve the vtables for the trait reference on the impl.  This
     // serves many purposes, best explained by example. Imagine we have:
@@ -847,9 +939,11 @@ pub fn resolve_impl(tcx: &ty::ctxt,
 pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
                             substs: &subst::Substs) -> vtable_res {
     let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
+    let unboxed_closure_types = RefCell::new(DefIdMap::new());
     let vcx = VtableContext {
         infcx: &infer::new_infer_ctxt(tcx),
-        param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id)
+        param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id),
+        unboxed_closure_types: &unboxed_closure_types,
     };
 
     lookup_vtables(&vcx,
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 59b65fdbec7..d802e3d1443 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -30,7 +30,7 @@ use util::ppaux::Repr;
 use std::cell::Cell;
 
 use syntax::ast;
-use syntax::codemap::Span;
+use syntax::codemap::{DUMMY_SP, Span};
 use syntax::print::pprust::pat_to_string;
 use syntax::visit;
 use syntax::visit::Visitor;
@@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
     let mut wbcx = WritebackCx::new(fcx);
     wbcx.visit_expr(e, ());
     wbcx.visit_upvar_borrow_map();
+    wbcx.visit_unboxed_closure_types();
 }
 
 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@@ -61,6 +62,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
         }
     }
     wbcx.visit_upvar_borrow_map();
+    wbcx.visit_unboxed_closure_types();
 }
 
 pub fn resolve_impl_res(infcx: &infer::InferCtxt,
@@ -130,7 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
                                     MethodCall::expr(e.id));
 
         match e.node {
-            ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {
+            ast::ExprFnBlock(ref decl, _) |
+            ast::ExprProc(ref decl, _) |
+            ast::ExprUnboxedFn(ref decl, _) => {
                 for input in decl.inputs.iter() {
                     let _ = self.visit_node_id(ResolvingExpr(e.span),
                                                input.id);
@@ -201,6 +205,26 @@ impl<'cx> WritebackCx<'cx> {
         }
     }
 
+    fn visit_unboxed_closure_types(&self) {
+        if self.fcx.writeback_errors.get() {
+            return
+        }
+
+        for (def_id, closure_ty) in self.fcx
+                                        .inh
+                                        .unboxed_closure_types
+                                        .borrow()
+                                        .iter() {
+            let closure_ty = self.resolve(closure_ty,
+                                          ResolvingUnboxedClosure(*def_id));
+            self.fcx
+                .tcx()
+                .unboxed_closure_types
+                .borrow_mut()
+                .insert(*def_id, closure_ty);
+        }
+    }
+
     fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
         // Resolve any borrowings for the node with id `id`
         self.visit_adjustments(reason, id);
@@ -332,6 +356,7 @@ enum ResolveReason {
     ResolvingPattern(Span),
     ResolvingUpvar(ty::UpvarId),
     ResolvingImplRes(Span),
+    ResolvingUnboxedClosure(ast::DefId),
 }
 
 impl ResolveReason {
@@ -344,6 +369,13 @@ impl ResolveReason {
                 ty::expr_span(tcx, upvar_id.closure_expr_id)
             }
             ResolvingImplRes(s) => s,
+            ResolvingUnboxedClosure(did) => {
+                if did.krate == ast::LOCAL_CRATE {
+                    ty::expr_span(tcx, did.node)
+                } else {
+                    DUMMY_SP
+                }
+            }
         }
     }
 }
@@ -441,6 +473,13 @@ impl<'cx> Resolver<'cx> {
                                   "cannot determine a type for impl \
                                    supertrait");
                 }
+
+                ResolvingUnboxedClosure(_) => {
+                    let span = self.reason.span(self.tcx);
+                    self.tcx.sess.span_err(span,
+                                           "cannot determine a type for this \
+                                            unboxed closure")
+                }
             }
         }
     }
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index b9bf8e37dea..9e6d059650c 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -25,7 +25,8 @@ use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
 use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
 use middle::ty::{ty_param, Polytype, ty_ptr};
 use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
-use middle::ty::{ty_uint, ty_uniq, ty_bare_fn, ty_closure};
+use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
+use middle::ty::{ty_closure};
 use middle::ty::type_is_ty_var;
 use middle::subst::Subst;
 use middle::ty;
@@ -75,7 +76,7 @@ fn get_base_type(inference_context: &InferCtxt,
     }
 
     match get(resolved_type).sty {
-        ty_enum(..) | ty_struct(..) => {
+        ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
             debug!("(getting base type) found base type");
             Some(resolved_type)
         }
@@ -111,7 +112,8 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
     ty::walk_ty(original_type, |t| {
         match get(t).sty {
             ty_enum(def_id, _) |
-            ty_struct(def_id, _) => {
+            ty_struct(def_id, _) |
+            ty_unboxed_closure(def_id) => {
                 if def_id.krate == ast::LOCAL_CRATE {
                     found_nominal = true;
                 }
@@ -154,7 +156,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
         Some(base_type) => {
             match get(base_type).sty {
                 ty_enum(def_id, _) |
-                ty_struct(def_id, _) => {
+                ty_struct(def_id, _) |
+                ty_unboxed_closure(def_id) => {
                     Some(def_id)
                 }
                 ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty {
@@ -691,7 +694,8 @@ impl<'a> CoherenceChecker<'a> {
             let self_type = self.get_self_type_for_implementation(impl_did);
             match ty::get(self_type.ty).sty {
                 ty::ty_enum(type_def_id, _) |
-                ty::ty_struct(type_def_id, _) => {
+                ty::ty_struct(type_def_id, _) |
+                ty::ty_unboxed_closure(type_def_id) => {
                     tcx.destructor_for_type.borrow_mut().insert(type_def_id,
                                                                 method_def_id);
                     tcx.destructors.borrow_mut().insert(method_def_id);
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 906cc1e0255..5fd9b85d69a 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -208,9 +208,16 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
                         let ty_method = Rc::new(match m {
                             &ast::Required(ref m) => {
                                 ty_method_of_trait_method(
-                                    ccx, trait_id, &trait_def.generics,
-                                    &m.id, &m.ident, &m.explicit_self,
-                                    &m.generics, &m.fn_style, &*m.decl)
+                                    ccx,
+                                    trait_id,
+                                    &trait_def.generics,
+                                    &m.id,
+                                    &m.ident,
+                                    &m.explicit_self,
+                                    m.abi,
+                                    &m.generics,
+                                    &m.fn_style,
+                                    &*m.decl)
                             }
 
                             &ast::Provided(ref m) => {
@@ -221,6 +228,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
                                     &m.id,
                                     &m.pe_ident(),
                                     m.pe_explicit_self(),
+                                    m.pe_abi(),
                                     m.pe_generics(),
                                     &m.pe_fn_style(),
                                     &*m.pe_fn_decl())
@@ -272,25 +280,25 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
                                  m_id: &ast::NodeId,
                                  m_ident: &ast::Ident,
                                  m_explicit_self: &ast::ExplicitSelf,
+                                 m_abi: abi::Abi,
                                  m_generics: &ast::Generics,
                                  m_fn_style: &ast::FnStyle,
-                                 m_decl: &ast::FnDecl) -> ty::Method
-    {
-        let trait_self_ty = ty::mk_param(this.tcx,
-                                         subst::SelfSpace,
-                                         0,
-                                         local_def(trait_id));
-        let ty_generics = ty_generics_for_fn_or_method(
-            this,
-            m_generics,
-            (*trait_generics).clone());
+                                 m_decl: &ast::FnDecl)
+                                 -> ty::Method {
+        let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id));
+
         let (fty, explicit_self_category) =
             astconv::ty_of_method(this,
                                   *m_id,
                                   *m_fn_style,
                                   trait_self_ty,
                                   *m_explicit_self,
-                                  m_decl);
+                                  m_decl,
+                                  m_abi);
+        let ty_generics =
+            ty_generics_for_fn_or_method(this,
+                                         m_generics,
+                                         (*trait_generics).clone());
         ty::Method::new(
             *m_ident,
             ty_generics,
@@ -381,15 +389,29 @@ fn convert_methods(ccx: &CrateCtxt,
                     untransformed_rcvr_ty: ty::t,
                     rcvr_ty_generics: &ty::Generics,
                     rcvr_visibility: ast::Visibility)
-                    -> ty::Method
-    {
+                    -> ty::Method {
+        // FIXME(pcwalton): Hack until we have syntax in stage0 for snapshots.
+        let real_abi = match container {
+            ty::TraitContainer(trait_id) => {
+                if ccx.tcx.lang_items.fn_trait() == Some(trait_id) ||
+                        ccx.tcx.lang_items.fn_mut_trait() == Some(trait_id) ||
+                        ccx.tcx.lang_items.fn_once_trait() == Some(trait_id) {
+                    abi::RustCall
+                } else {
+                    m.pe_abi()
+                }
+            }
+            _ => m.pe_abi(),
+        };
+
         let (fty, explicit_self_category) =
             astconv::ty_of_method(ccx,
                                   m.id,
                                   m.pe_fn_style(),
                                   untransformed_rcvr_ty,
                                   *m.pe_explicit_self(),
-                                  &*m.pe_fn_decl());
+                                  &*m.pe_fn_decl(),
+                                  real_abi);
 
         // if the method specifies a visibility, use that, otherwise
         // inherit the visibility from the impl (so `foo` in `pub impl
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index d82e6e74778..1aae97d3d83 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -223,12 +223,14 @@ pub trait Combine {
         let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
         let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
         let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
+        let abi = if_ok!(self.abi(a.abi, b.abi));
         Ok(ty::ClosureTy {
             fn_style: fn_style,
             onceness: onceness,
             store: store,
             bounds: bounds,
-            sig: sig
+            sig: sig,
+            abi: abi,
         })
     }
 
@@ -490,6 +492,11 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
             Ok(ty::mk_struct(tcx, a_id, substs))
       }
 
+      (&ty::ty_unboxed_closure(a_id), &ty::ty_unboxed_closure(b_id))
+      if a_id == b_id => {
+          Ok(ty::mk_unboxed_closure(tcx, a_id))
+      }
+
       (&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => {
         this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ)))
       }
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index ad6864ba487..aebdb594382 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -97,6 +97,9 @@ pub enum MethodOrigin {
     // fully statically resolved method
     MethodStatic(ast::DefId),
 
+    // fully statically resolved unboxed closure invocation
+    MethodStaticUnboxedClosure(ast::DefId),
+
     // method invoked on a type parameter with a bounded trait
     MethodParam(MethodParam),
 
@@ -233,6 +236,12 @@ pub enum vtable_origin {
     vtable_param(param_index, uint),
 
     /*
+      Vtable automatically generated for an unboxed closure. The def ID is the
+      ID of the closure expression.
+     */
+    vtable_unboxed_closure(ast::DefId),
+
+    /*
       Asked to determine the vtable for ty_err. This is the value used
       for the vtables of `Self` in a virtual call like `foo.bar()`
       where `foo` is of object type. The same value is also used when
@@ -256,6 +265,10 @@ impl Repr for vtable_origin {
                 format!("vtable_param({:?}, {:?})", x, y)
             }
 
+            vtable_unboxed_closure(def_id) => {
+                format!("vtable_unboxed_closure({})", def_id)
+            }
+
             vtable_error => {
                 format!("vtable_error")
             }
diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs
index a65aa0423a6..d230b080966 100644
--- a/src/librustc/middle/typeck/variance.rs
+++ b/src/librustc/middle/typeck/variance.rs
@@ -715,7 +715,7 @@ impl<'a> ConstraintContext<'a> {
         match ty::get(ty).sty {
             ty::ty_nil | ty::ty_bot | ty::ty_bool |
             ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
-            ty::ty_float(_) | ty::ty_str => {
+            ty::ty_float(_) | ty::ty_str | ty::ty_unboxed_closure(..) => {
                 /* leaf type -- noop */
             }
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 8b8e37fe280..c3986d01d3d 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -21,6 +21,7 @@ use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
 use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
 use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup};
 use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
+use middle::ty::{ty_unboxed_closure};
 use middle::ty;
 use middle::typeck;
 use middle::typeck::infer;
@@ -414,6 +415,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
                   bound_str)
       }
       ty_str => "str".to_string(),
+      ty_unboxed_closure(..) => "closure".to_string(),
       ty_vec(ref mt, sz) => {
           match sz {
               Some(n) => {
@@ -878,6 +880,9 @@ impl Repr for typeck::MethodOrigin {
             &typeck::MethodStatic(def_id) => {
                 format!("MethodStatic({})", def_id.repr(tcx))
             }
+            &typeck::MethodStaticUnboxedClosure(def_id) => {
+                format!("MethodStaticUnboxedClosure({})", def_id.repr(tcx))
+            }
             &typeck::MethodParam(ref p) => {
                 p.repr(tcx)
             }
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index 66bc8c740c4..cb9519b1eb8 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -239,6 +239,7 @@ mod svh_visitor {
         SawExprWhile,
         SawExprMatch,
         SawExprFnBlock,
+        SawExprUnboxedFn,
         SawExprProc,
         SawExprBlock,
         SawExprAssign,
@@ -270,6 +271,7 @@ mod svh_visitor {
             ExprLoop(_, id)          => SawExprLoop(id.map(content)),
             ExprMatch(..)            => SawExprMatch,
             ExprFnBlock(..)          => SawExprFnBlock,
+            ExprUnboxedFn(..)        => SawExprUnboxedFn,
             ExprProc(..)             => SawExprProc,
             ExprBlock(..)            => SawExprBlock,
             ExprAssign(..)           => SawExprAssign,
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 9ee8fa98c74..4ea4958e544 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -1944,6 +1944,14 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter {
     }
 }
 
+/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
+pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
+    unsafe {
+        assert!(index < LLVMCountParams(llfn));
+        LLVMGetParam(llfn, index)
+    }
+}
+
 // FIXME #15460 - create a public function that actually calls our
 // static LLVM symbols. Otherwise the linker will just throw llvm
 // away.  We're just calling lots of stuff until we transitively get
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c94759d7d7e..9f5df205aa4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1301,6 +1301,8 @@ impl Clean<Type> for ty::t {
                 }
             }
 
+            ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton)
+
             ty::ty_infer(..) => fail!("ty_infer"),
             ty::ty_err => fail!("ty_err"),
         }
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index 8b01002831b..6f809383620 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -30,6 +30,7 @@ pub enum Abi {
     C,
     System,
     RustIntrinsic,
+    RustCall,
 }
 
 #[allow(non_camel_case_types)]
@@ -85,6 +86,7 @@ static AbiDatas: &'static [AbiData] = &[
     AbiData {abi: C, name: "C", abi_arch: AllArch},
     AbiData {abi: System, name: "system", abi_arch: AllArch},
     AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
+    AbiData {abi: RustCall, name: "rust-call", abi_arch: RustArch},
 ];
 
 /// Returns the ABI with the given name (if any).
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d9f14bfa156..394d4a82516 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -503,6 +503,7 @@ pub enum Expr_ {
     ExprMatch(Gc<Expr>, Vec<Arm>),
     ExprFnBlock(P<FnDecl>, P<Block>),
     ExprProc(P<FnDecl>, P<Block>),
+    ExprUnboxedFn(P<FnDecl>, P<Block>),
     ExprBlock(P<Block>),
 
     ExprAssign(Gc<Expr>, Gc<Expr>),
@@ -690,6 +691,7 @@ pub struct TypeMethod {
     pub ident: Ident,
     pub attrs: Vec<Attribute>,
     pub fn_style: FnStyle,
+    pub abi: Abi,
     pub decl: P<FnDecl>,
     pub generics: Generics,
     pub explicit_self: ExplicitSelf,
@@ -966,13 +968,20 @@ pub struct Method {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
     pub span: Span,
-    pub node: Method_
+    pub node: Method_,
 }
 
 #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum Method_ {
     /// Represents a method declaration
-    MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P<FnDecl>, P<Block>, Visibility),
+    MethDecl(Ident,
+             Generics,
+             Abi,
+             ExplicitSelf,
+             FnStyle,
+             P<FnDecl>,
+             P<Block>,
+             Visibility),
     /// Represents a macro in method position
     MethMac(Mac),
 }
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 50e487b63db..c77f7db1c6d 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -320,13 +320,15 @@ impl Map {
             }
             NodeForeignItem(i) => PathName(i.ident.name),
             NodeMethod(m) => match m.node {
-                MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+                MethDecl(ident, _, _, _, _, _, _, _) => PathName(ident.name),
                 MethMac(_) => fail!("no path elem for {:?}", node)
             },
             NodeTraitMethod(tm) => match *tm {
                 Required(ref m) => PathName(m.ident.name),
                 Provided(m) => match m.node {
-                    MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+                    MethDecl(ident, _, _, _, _, _, _, _) => {
+                        PathName(ident.name)
+                    }
                     MethMac(_) => fail!("no path elem for {:?}", node),
                 }
             },
@@ -709,7 +711,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
             format!("foreign item {} (id={})", path_str, id)
         }
         Some(NodeMethod(m)) => match m.node {
-            MethDecl(ident, _, _, _, _, _, _) =>
+            MethDecl(ident, _, _, _, _, _, _, _) =>
                 format!("method {} in {} (id={})",
                         token::get_ident(ident),
                         map.path_to_string(id), id),
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 5431a3db16e..2b98a3bdd28 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use abi::Abi;
 use ast::*;
 use ast;
 use ast_util;
@@ -249,7 +250,14 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
         Required(ref m) => (*m).clone(),
         Provided(m) => {
             match m.node {
-                MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => {
+                MethDecl(ident,
+                         ref generics,
+                         abi,
+                         explicit_self,
+                         fn_style,
+                         decl,
+                         _,
+                         vis) => {
                     TypeMethod {
                         ident: ident,
                         attrs: m.attrs.clone(),
@@ -260,6 +268,7 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
                         id: m.id,
                         span: m.span,
                         vis: vis,
+                        abi: abi,
                     }
                 },
                 MethMac(_) => fail!("expected non-macro method declaration")
@@ -749,6 +758,7 @@ pub fn static_has_significant_address(mutbl: ast::Mutability,
 pub trait PostExpansionMethod {
     fn pe_ident(&self) -> ast::Ident;
     fn pe_generics<'a>(&'a self) -> &'a ast::Generics;
+    fn pe_abi(&self) -> Abi;
     fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf;
     fn pe_fn_style(&self) -> ast::FnStyle;
     fn pe_fn_decl(&self) -> P<ast::FnDecl>;
@@ -797,25 +807,28 @@ macro_rules! mf_method{
 // PRE
 impl PostExpansionMethod for Method {
     fn pe_ident(&self) -> ast::Ident {
-        mf_method_body!(self,MethDecl(ident,_,_,_,_,_,_),ident)
+        mf_method_body!(self, MethDecl(ident,_,_,_,_,_,_,_),ident)
     }
     fn pe_generics<'a>(&'a self) -> &'a ast::Generics {
-        mf_method_body!(self,MethDecl(_,ref generics,_,_,_,_,_),generics)
+        mf_method_body!(self, MethDecl(_,ref generics,_,_,_,_,_,_),generics)
+    }
+    fn pe_abi(&self) -> Abi {
+        mf_method_body!(self, MethDecl(_,_,abi,_,_,_,_,_),abi)
     }
     fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf {
-        mf_method_body!(self,MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self)
+        mf_method_body!(self, MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self)
     }
     fn pe_fn_style(&self) -> ast::FnStyle{
-        mf_method_body!(self,MethDecl(_,_,_,fn_style,_,_,_),fn_style)
+        mf_method_body!(self, MethDecl(_,_,_,_,fn_style,_,_,_),fn_style)
     }
     fn pe_fn_decl(&self) -> P<ast::FnDecl> {
-        mf_method_body!(self,MethDecl(_,_,_,_,decl,_,_),decl)
+        mf_method_body!(self, MethDecl(_,_,_,_,_,decl,_,_),decl)
     }
     fn pe_body(&self) -> P<ast::Block> {
-        mf_method_body!(self,MethDecl(_,_,_,_,_,body,_),body)
+        mf_method_body!(self, MethDecl(_,_,_,_,_,_,body,_),body)
     }
     fn pe_vis(&self) -> ast::Visibility {
-        mf_method_body!(self,MethDecl(_,_,_,_,_,_,vis),vis)
+        mf_method_body!(self, MethDecl(_,_,_,_,_,_,_,vis),vis)
     }
 }
 
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index f1c1784146a..871f277a2da 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -183,6 +183,8 @@
 use std::cell::RefCell;
 use std::gc::{Gc, GC};
 
+use abi::Abi;
+use abi;
 use ast;
 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
 use ast_util;
@@ -477,9 +479,13 @@ impl<'a> TraitDef<'a> {
                                                      nonself_args.as_slice())
             };
 
-            method_def.create_method(cx, self,
-                                     type_ident, generics,
-                                     explicit_self, tys,
+            method_def.create_method(cx,
+                                     self,
+                                     type_ident,
+                                     generics,
+                                     abi::Rust,
+                                     explicit_self,
+                                     tys,
                                      body)
         }).collect();
 
@@ -513,9 +519,13 @@ impl<'a> TraitDef<'a> {
                                                    nonself_args.as_slice())
             };
 
-            method_def.create_method(cx, self,
-                                     type_ident, generics,
-                                     explicit_self, tys,
+            method_def.create_method(cx,
+                                     self,
+                                     type_ident,
+                                     generics,
+                                     abi::Rust,
+                                     explicit_self,
+                                     tys,
                                      body)
         }).collect();
 
@@ -622,9 +632,11 @@ impl<'a> MethodDef<'a> {
                      trait_: &TraitDef,
                      type_ident: Ident,
                      generics: &Generics,
+                     abi: Abi,
                      explicit_self: ast::ExplicitSelf,
                      arg_types: Vec<(Ident, P<ast::Ty>)> ,
-                     body: Gc<Expr>) -> Gc<ast::Method> {
+                     body: Gc<Expr>)
+                     -> Gc<ast::Method> {
         // create the generics that aren't for Self
         let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
 
@@ -653,6 +665,7 @@ impl<'a> MethodDef<'a> {
             span: trait_.span,
             node: ast::MethDecl(method_ident,
                                 fn_generics,
+                                abi,
                                 explicit_self,
                                 ast::NormalFn,
                                 fn_decl,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 1cbe863e4e4..fdb698441fc 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -910,7 +910,14 @@ impl<'a> Folder for PatIdentRenamer<'a> {
 fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
     let id = fld.new_id(m.id);
     match m.node {
-        ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+        ast::MethDecl(ident,
+                      ref generics,
+                      abi,
+                      ref explicit_self,
+                      fn_style,
+                      decl,
+                      body,
+                      vis) => {
             let (rewritten_fn_decl, rewritten_body)
                 = expand_and_rename_fn_decl_and_block(&*decl,body,fld);
             SmallVector::one(box(GC) ast::Method {
@@ -919,6 +926,7 @@ fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast
                     span: fld.new_span(m.span),
                     node: ast::MethDecl(fld.fold_ident(ident),
                                         fold_generics(generics, fld),
+                                        abi,
                                         fld.fold_explicit_self(explicit_self),
                                         fn_style,
                                         rewritten_fn_decl,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5467afab9f5..5417991c9df 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -727,6 +727,7 @@ pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMeth
         ident: fld.fold_ident(m.ident),
         attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
         fn_style: m.fn_style,
+        abi: m.abi,
         decl: fld.fold_fn_decl(&*m.decl),
         generics: fold_generics(&m.generics, fld),
         explicit_self: fld.fold_explicit_self(&m.explicit_self),
@@ -818,9 +819,17 @@ pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc
         id: id,
         span: folder.new_span(m.span),
         node: match m.node {
-            MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+            MethDecl(ident,
+                     ref generics,
+                     abi,
+                     ref explicit_self,
+                     fn_style,
+                     decl,
+                     body,
+                     vis) => {
                 MethDecl(folder.fold_ident(ident),
                          fold_generics(generics, folder),
+                         abi,
                          folder.fold_explicit_self(explicit_self),
                          fn_style,
                          folder.fold_fn_decl(&*decl),
@@ -948,7 +957,11 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
             ExprProc(folder.fold_fn_decl(&**decl),
                      folder.fold_block(body.clone()))
         }
-        ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk.clone())),
+        ExprUnboxedFn(ref decl, ref body) => {
+            ExprUnboxedFn(folder.fold_fn_decl(&**decl),
+                          folder.fold_block(*body))
+        }
+        ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
         ExprAssign(el, er) => {
             ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a77f24f98f8..394288bd9f2 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -25,7 +25,7 @@ use ast::{ExprBreak, ExprCall, ExprCast};
 use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
 use ast::{ExprLit, ExprLoop, ExprMac};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
-use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
+use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
 use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
 use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
 use ast::{ExprVstoreUniq, Once, Many};
@@ -59,6 +59,7 @@ use ast::Visibility;
 use ast;
 use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
 use ast_util;
+use attr;
 use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
 use codemap;
 use parse;
@@ -1217,6 +1218,16 @@ impl<'a> Parser<'a> {
             // NB: at the moment, trait methods are public by default; this
             // could change.
             let vis = p.parse_visibility();
+            let abi = if p.eat_keyword(keywords::Extern) {
+                p.parse_opt_abi().unwrap_or(abi::C)
+            } else if attr::contains_name(attrs.as_slice(),
+                                          "rust_call_abi_hack") {
+                // FIXME(stage0, pcwalton): Remove this awful hack after a
+                // snapshot, and change to `extern "rust-call" fn`.
+                abi::RustCall
+            } else {
+                abi::Rust
+            };
             let style = p.parse_fn_style();
             let ident = p.parse_ident();
 
@@ -1239,6 +1250,7 @@ impl<'a> Parser<'a> {
                     fn_style: style,
                     decl: d,
                     generics: generics,
+                    abi: abi,
                     explicit_self: explicit_self,
                     id: ast::DUMMY_NODE_ID,
                     span: mk_sp(lo, hi),
@@ -1254,7 +1266,14 @@ impl<'a> Parser<'a> {
                     attrs: attrs,
                     id: ast::DUMMY_NODE_ID,
                     span: mk_sp(lo, hi),
-                    node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis)
+                    node: ast::MethDecl(ident,
+                                        generics,
+                                        abi,
+                                        explicit_self,
+                                        style,
+                                        d,
+                                        body,
+                                        vis)
                 })
               }
 
@@ -2620,51 +2639,11 @@ impl<'a> Parser<'a> {
         self.mk_expr(lo, hi, ExprIf(cond, thn, els))
     }
 
-    /// `|args| { ... }` or `{ ...}` like in `do` expressions
-    pub fn parse_lambda_block_expr(&mut self) -> Gc<Expr> {
-        self.parse_lambda_expr_(
-            |p| {
-                match p.token {
-                    token::BINOP(token::OR) | token::OROR => {
-                        p.parse_fn_block_decl()
-                    }
-                    _ => {
-                        // No argument list - `do foo {`
-                        P(FnDecl {
-                            inputs: Vec::new(),
-                            output: P(Ty {
-                                id: ast::DUMMY_NODE_ID,
-                                node: TyInfer,
-                                span: p.span
-                            }),
-                            cf: Return,
-                            variadic: false
-                        })
-                    }
-                }
-            },
-            |p| {
-                let blk = p.parse_block();
-                p.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))
-            })
-    }
-
-    /// `|args| expr`
+    // `|args| expr`
     pub fn parse_lambda_expr(&mut self) -> Gc<Expr> {
-        self.parse_lambda_expr_(|p| p.parse_fn_block_decl(),
-                                |p| p.parse_expr())
-    }
-
-    /// parse something of the form |args| expr
-    /// this is used both in parsing a lambda expr
-    /// and in parsing a block expr as e.g. in for...
-    pub fn parse_lambda_expr_(&mut self,
-                              parse_decl: |&mut Parser| -> P<FnDecl>,
-                              parse_body: |&mut Parser| -> Gc<Expr>)
-                              -> Gc<Expr> {
         let lo = self.span.lo;
-        let decl = parse_decl(self);
-        let body = parse_body(self);
+        let (decl, is_unboxed) = self.parse_fn_block_decl();
+        let body = self.parse_expr();
         let fakeblock = P(ast::Block {
             view_items: Vec::new(),
             stmts: Vec::new(),
@@ -2674,7 +2653,11 @@ impl<'a> Parser<'a> {
             span: body.span,
         });
 
-        return self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock));
+        if is_unboxed {
+            self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock))
+        } else {
+            self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
+        }
     }
 
     pub fn parse_else_expr(&mut self) -> Gc<Expr> {
@@ -3955,18 +3938,30 @@ impl<'a> Parser<'a> {
         (spanned(lo, hi, explicit_self), fn_decl)
     }
 
-    /// Parse the |arg, arg| header on a lambda
-    fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
-        let inputs_captures = {
+    // parse the |arg, arg| header on a lambda
+    fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) {
+        let (is_unboxed, inputs_captures) = {
             if self.eat(&token::OROR) {
-                Vec::new()
+                (false, Vec::new())
             } else {
-                self.parse_unspanned_seq(
-                    &token::BINOP(token::OR),
+                self.expect(&token::BINOP(token::OR));
+                let is_unboxed = self.token == token::BINOP(token::AND) &&
+                    self.look_ahead(1, |t| {
+                        token::is_keyword(keywords::Mut, t)
+                    }) &&
+                    self.look_ahead(2, |t| *t == token::COLON);
+                if is_unboxed {
+                    self.bump();
+                    self.bump();
+                    self.bump();
+                }
+                let args = self.parse_seq_to_before_end(
                     &token::BINOP(token::OR),
                     seq_sep_trailing_disallowed(token::COMMA),
                     |p| p.parse_fn_block_arg()
-                )
+                );
+                self.bump();
+                (is_unboxed, args)
             }
         };
         let output = if self.eat(&token::RARROW) {
@@ -3979,12 +3974,12 @@ impl<'a> Parser<'a> {
             })
         };
 
-        P(FnDecl {
+        (P(FnDecl {
             inputs: inputs_captures,
             output: output,
             cf: Return,
             variadic: false
-        })
+        }), is_unboxed)
     }
 
     /// Parses the `(arg, arg) -> return_type` header on a procedure.
@@ -4079,6 +4074,11 @@ impl<'a> Parser<'a> {
                 (ast::MethMac(m), self.span.hi, attrs)
             } else {
                 let visa = self.parse_visibility();
+                let abi = if self.eat_keyword(keywords::Extern) {
+                    self.parse_opt_abi().unwrap_or(abi::C)
+                } else {
+                    abi::Rust
+                };
                 let fn_style = self.parse_fn_style();
                 let ident = self.parse_ident();
                 let generics = self.parse_generics();
@@ -4087,7 +4087,14 @@ impl<'a> Parser<'a> {
                     });
                 let (inner_attrs, body) = self.parse_inner_attrs_and_block();
                 let new_attrs = attrs.append(inner_attrs.as_slice());
-                (ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
+                (ast::MethDecl(ident,
+                               generics,
+                               abi,
+                               explicit_self,
+                               fn_style,
+                               decl,
+                               body,
+                               visa),
                  body.span.hi, new_attrs)
             }
         };
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 10caaea86cf..dd96118ea49 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -188,7 +188,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    to_string(|s| s.print_fn_block_args(p))
+    to_string(|s| s.print_fn_block_args(p, false))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
@@ -259,7 +259,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
     match expr.node {
         ast::ExprAssign(..) | ast::ExprBinary(..) |
         ast::ExprFnBlock(..) | ast::ExprProc(..) |
-        ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
+        ast::ExprUnboxedFn(..) | ast::ExprAssignOp(..) |
+        ast::ExprCast(..) => true,
         _ => false,
     }
 }
@@ -1004,9 +1005,20 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(meth.span.lo));
         try!(self.print_outer_attributes(meth.attrs.as_slice()));
         match meth.node {
-            ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
-                try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
-                                   ident, generics, Some(explicit_self.node),
+            ast::MethDecl(ident,
+                          ref generics,
+                          abi,
+                          ref explicit_self,
+                          fn_style,
+                          decl,
+                          body,
+                          vis) => {
+                try!(self.print_fn(&*decl,
+                                   Some(fn_style),
+                                   abi,
+                                   ident,
+                                   generics,
+                                   Some(explicit_self.node),
                                    vis));
                 try!(word(&mut self.s, " "));
                 self.print_block_with_attrs(&*body, meth.attrs.as_slice())
@@ -1446,7 +1458,37 @@ impl<'a> State<'a> {
                 // we are inside.
                 //
                 // if !decl.inputs.is_empty() {
-                try!(self.print_fn_block_args(&**decl));
+                try!(self.print_fn_block_args(&**decl, false));
+                try!(space(&mut self.s));
+                // }
+
+                if !body.stmts.is_empty() || !body.expr.is_some() {
+                    try!(self.print_block_unclosed(&**body));
+                } else {
+                    // we extract the block, so as not to create another set of boxes
+                    match body.expr.unwrap().node {
+                        ast::ExprBlock(blk) => {
+                            try!(self.print_block_unclosed(&*blk));
+                        }
+                        _ => {
+                            // this is a bare expression
+                            try!(self.print_expr(&*body.expr.unwrap()));
+                            try!(self.end()); // need to close a box
+                        }
+                    }
+                }
+                // a box will be closed by print_expr, but we didn't want an overall
+                // wrapper so we closed the corresponding opening. so create an
+                // empty box to satisfy the close.
+                try!(self.ibox(0));
+            }
+            ast::ExprUnboxedFn(ref 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() {
+                try!(self.print_fn_block_args(&**decl, true));
                 try!(space(&mut self.s));
                 // }
 
@@ -1939,8 +1981,13 @@ impl<'a> State<'a> {
     }
 
     pub fn print_fn_block_args(&mut self,
-                               decl: &ast::FnDecl) -> IoResult<()> {
+                               decl: &ast::FnDecl,
+                               is_unboxed: bool)
+                               -> IoResult<()> {
         try!(word(&mut self.s, "|"));
+        if is_unboxed {
+            try!(self.word_space("&mut:"));
+        }
         try!(self.print_fn_args(decl, None));
         try!(word(&mut self.s, "|"));
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index cd953607ea2..d5fb75a4d69 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -562,7 +562,7 @@ pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
                                                    method: &Method,
                                                    env: E) {
     match method.node {
-        MethDecl(ident, ref generics, _, _, decl, body, _) => {
+        MethDecl(ident, ref generics, _, _, _, decl, body, _) => {
             visitor.visit_ident(method.span, ident, env.clone());
             visitor.visit_fn(&FkMethod(ident, generics, method),
                              &*decl,
@@ -594,7 +594,7 @@ pub fn walk_fn<E: Clone, V: Visitor<E>>(visitor: &mut V,
         FkMethod(_, generics, method) => {
             visitor.visit_generics(generics, env.clone());
             match method.node {
-                MethDecl(_, _, ref explicit_self, _, _, _, _) =>
+                MethDecl(_, _, _, ref explicit_self, _, _, _, _) =>
                     visitor.visit_explicit_self(explicit_self, env.clone()),
                 MethMac(ref mac) =>
                     visitor.visit_mac(mac, env.clone())
@@ -790,6 +790,14 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
                              expression.id,
                              env.clone())
         }
+        ExprUnboxedFn(ref function_declaration, ref body) => {
+            visitor.visit_fn(&FkFnBlock,
+                             &**function_declaration,
+                             &**body,
+                             expression.span,
+                             expression.id,
+                             env.clone())
+        }
         ExprProc(ref function_declaration, ref body) => {
             visitor.visit_fn(&FkFnBlock,
                              &**function_declaration,
diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs
index 349a20313fa..f134c2aa09b 100644
--- a/src/test/compile-fail/borrowck-overloaded-call.rs
+++ b/src/test/compile-fail/borrowck-overloaded-call.rs
@@ -18,7 +18,7 @@ struct SFn {
 }
 
 impl Fn<(int,),int> for SFn {
-    fn call(&self, (z,): (int,)) -> int {
+    extern "rust-call" fn call(&self, (z,): (int,)) -> int {
         self.x * self.y * z
     }
 }
@@ -29,7 +29,7 @@ struct SFnMut {
 }
 
 impl FnMut<(int,),int> for SFnMut {
-    fn call_mut(&mut self, (z,): (int,)) -> int {
+    extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
         self.x * self.y * z
     }
 }
@@ -39,7 +39,7 @@ struct SFnOnce {
 }
 
 impl FnOnce<(String,),uint> for SFnOnce {
-    fn call_once(self, (z,): (String,)) -> uint {
+    extern "rust-call" fn call_once(self, (z,): (String,)) -> uint {
         self.x.len() + z.len()
     }
 }
diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs
index 3c03c874757..cc01c0b3c9f 100644
--- a/src/test/compile-fail/overloaded-calls-bad.rs
+++ b/src/test/compile-fail/overloaded-calls-bad.rs
@@ -18,7 +18,7 @@ struct S {
 }
 
 impl FnMut<(int,),int> for S {
-    fn call_mut(&mut self, (z,): (int,)) -> int {
+    extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
         self.x * self.y * z
     }
 }
diff --git a/src/test/compile-fail/overloaded-calls-nontuple.rs b/src/test/compile-fail/overloaded-calls-nontuple.rs
index 9bbc4ab3ba3..ee2fe352247 100644
--- a/src/test/compile-fail/overloaded-calls-nontuple.rs
+++ b/src/test/compile-fail/overloaded-calls-nontuple.rs
@@ -18,7 +18,7 @@ struct S {
 }
 
 impl FnMut<int,int> for S {
-    fn call_mut(&mut self, z: int) -> int {
+    extern "rust-call" fn call_mut(&mut self, z: int) -> int {
         self.x + self.y + z
     }
 }
diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs
new file mode 100644
index 00000000000..09f13b77386
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs
@@ -0,0 +1,19 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+pub fn main() {
+    let mut f = |&mut: x: int, y: int| -> int { x + y };
+    let z = f.call_mut((1u, 2));    //~ ERROR mismatched types
+    println!("{}", z);
+}
diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
new file mode 100644
index 00000000000..2ee632b9093
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
+    f.call_mut((2, y))
+}
+
+pub fn main() {
+    let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
+    let z = call_it(3, f);  //~ ERROR expected core::ops::FnMut
+    //~^ ERROR expected core::ops::FnMut
+    println!("{}", z);
+}
+
diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs
index b0c8d84b664..ccb5634f7a2 100644
--- a/src/test/run-pass/fn-trait-sugar.rs
+++ b/src/test/run-pass/fn-trait-sugar.rs
@@ -16,7 +16,7 @@ use std::ops::FnMut;
 struct S;
 
 impl FnMut<(int,),int> for S {
-    fn call_mut(&mut self, (x,): (int,)) -> int {
+    extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int {
         x * x
     }
 }
diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs
index 045d3cc0458..b53c2258736 100644
--- a/src/test/run-pass/issue-14958.rs
+++ b/src/test/run-pass/issue-14958.rs
@@ -15,7 +15,7 @@ trait Foo {}
 struct Bar;
 
 impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar {
-    fn call(&self, _: (&'a Foo,)) {}
+    extern "rust-call" fn call(&self, _: (&'a Foo,)) {}
 }
 
 struct Baz;
diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs
index 7fbb0657c70..af0bc78094e 100644
--- a/src/test/run-pass/issue-14959.rs
+++ b/src/test/run-pass/issue-14959.rs
@@ -34,7 +34,7 @@ impl Alloy {
 }
 
 impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> {
-    fn call(&self, (_res,): (&'b mut Response,)) {}
+    extern "rust-call" fn call(&self, (_res,): (&'b mut Response,)) {}
 }
 
 impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld {
diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs
index 33120defedd..76c7e60116f 100644
--- a/src/test/run-pass/overloaded-calls-simple.rs
+++ b/src/test/run-pass/overloaded-calls-simple.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(overloaded_calls)]
+#![feature(lang_items, overloaded_calls)]
 
 use std::ops::{Fn, FnMut, FnOnce};
 
@@ -18,7 +18,7 @@ struct S1 {
 }
 
 impl FnMut<(int,),int> for S1 {
-    fn call_mut(&mut self, (z,): (int,)) -> int {
+    extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
         self.x * self.y * z
     }
 }
@@ -29,7 +29,7 @@ struct S2 {
 }
 
 impl Fn<(int,),int> for S2 {
-    fn call(&self, (z,): (int,)) -> int {
+    extern "rust-call" fn call(&self, (z,): (int,)) -> int {
         self.x * self.y * z
     }
 }
@@ -40,7 +40,7 @@ struct S3 {
 }
 
 impl FnOnce<(int,int),int> for S3 {
-    fn call_once(self, (z,zz): (int,int)) -> int {
+    extern "rust-call" fn call_once(self, (z,zz): (int,int)) -> int {
         self.x * self.y * z * zz
     }
 }
@@ -50,21 +50,21 @@ fn main() {
         x: 3,
         y: 3,
     };
-    let ans = s(3);
-    assert_eq!(ans, 27);
+    let ans = s.call_mut((3,));
 
+    assert_eq!(ans, 27);
     let s = S2 {
         x: 3,
         y: 3,
     };
-    let ans = s(3);
+    let ans = s.call((3,));
     assert_eq!(ans, 27);
 
     let s = S3 {
         x: 3,
         y: 3,
     };
-    let ans = s(3, 1);
+    let ans = s.call_once((3, 1));
     assert_eq!(ans, 27);
 }
 
diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs
index f8f7df6b49b..b868c8c96b5 100644
--- a/src/test/run-pass/overloaded-calls-zero-args.rs
+++ b/src/test/run-pass/overloaded-calls-zero-args.rs
@@ -18,7 +18,7 @@ struct S {
 }
 
 impl FnMut<(),int> for S {
-    fn call_mut(&mut self, (): ()) -> int {
+    extern "rust-call" fn call_mut(&mut self, (): ()) -> int {
         self.x * self.y
     }
 }
diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs
new file mode 100644
index 00000000000..c4b990abf7e
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-boxed.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn make_adder(x: int) -> Box<FnMut<(int,),int>> {
+    (box |&mut: y: int| -> int { x + y }) as Box<FnMut<(int,),int>>
+}
+
+pub fn main() {
+    let mut adder = make_adder(3);
+    let z = adder.call_mut((2,));
+    println!("{}", z);
+    assert_eq!(z, 5);
+}
+
diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs
new file mode 100644
index 00000000000..9d1d81fe259
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-generic.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
+    f.call_mut((2, y))
+}
+
+pub fn main() {
+    let f = |&mut: x: int, y: int| -> int { x + y };
+    let z = call_it(3, f);
+    println!("{}", z);
+    assert_eq!(z, 5);
+}
+
diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs
new file mode 100644
index 00000000000..f11096ba5ff
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-simple.rs
@@ -0,0 +1,19 @@
+// 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.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+pub fn main() {
+    let mut f = |&mut: x: int, y: int| -> int { x + y };
+    let z = f.call_mut((1, 2));
+    assert_eq!(z, 3);
+}