about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-11-09 23:09:28 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-11-12 20:08:03 +0200
commit57950982b27c6ab45509c1f2db4a01fa1d2cfebb (patch)
tree31999422c25805650003d783c1b6d789829bb228
parentb6828fd1acf11272b05c32010f9071d3e8862e76 (diff)
downloadrust-57950982b27c6ab45509c1f2db4a01fa1d2cfebb.tar.gz
rust-57950982b27c6ab45509c1f2db4a01fa1d2cfebb.zip
rustc_trans: translate closures using the collector
Translate closures like normal functions, using the trans::collector
interface.
-rw-r--r--src/librustc_trans/base.rs63
-rw-r--r--src/librustc_trans/callee.rs177
-rw-r--r--src/librustc_trans/closure.rs318
-rw-r--r--src/librustc_trans/collector.rs28
-rw-r--r--src/librustc_trans/common.rs31
-rw-r--r--src/librustc_trans/declare.rs5
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/mir/constant.rs8
-rw-r--r--src/librustc_trans/mir/rvalue.rs9
-rw-r--r--src/librustc_trans/trans_item.rs5
10 files changed, 241 insertions, 404 deletions
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index a990a7c507f..c7cad6455bc 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1003,34 +1003,41 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
     }
 }
 
-/// Builds an LLVM function out of a source function.
-///
-/// If the function closes over its environment a closure will be returned.
-pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               llfndecl: ValueRef,
-                               instance: Instance<'tcx>,
-                               sig: &ty::FnSig<'tcx>,
-                               abi: Abi) {
+pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
+    let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
+    // this is an info! to allow collecting monomorphization statistics
+    // and to allow finding the last function before LLVM aborts from
+    // release builds.
+    info!("trans_instance({})", instance);
+
+    let _icx = push_ctxt("trans_instance");
+
+    let fn_ty = ccx.tcx().item_type(instance.def);
+    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
+    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
+
+    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+
+    let lldecl = match ccx.instances().borrow().get(&instance) {
+        Some(&val) => val,
+        None => bug!("Instance `{:?}` not already declared", instance)
+    };
+
     ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
 
-    let _icx = push_ctxt("trans_closure");
     if !ccx.sess().no_landing_pads() {
-        attributes::emit_uwtable(llfndecl, true);
+        attributes::emit_uwtable(lldecl, true);
     }
 
-    // this is an info! to allow collecting monomorphization statistics
-    // and to allow finding the last function before LLVM aborts from
-    // release builds.
-    info!("trans_closure(..., {})", instance);
-
-    let fn_ty = FnType::new(ccx, abi, sig, &[]);
+    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let (arena, fcx): (TypedArena<_>, FunctionContext);
     arena = TypedArena::new();
     fcx = FunctionContext::new(ccx,
-                               llfndecl,
+                               lldecl,
                                fn_ty,
-                               Some((instance, sig, abi)),
+                               Some((instance, &sig, abi)),
                                &arena);
 
     if fcx.mir.is_none() {
@@ -1040,26 +1047,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     mir::trans_mir(&fcx);
 }
 
-pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
-    let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
-    debug!("trans_instance(instance={:?})", instance);
-    let _icx = push_ctxt("trans_instance");
-
-    let fn_ty = ccx.tcx().item_type(instance.def);
-    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
-    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
-
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig());
-    let abi = fn_ty.fn_abi();
-
-    let lldecl = match ccx.instances().borrow().get(&instance) {
-        Some(&val) => val,
-        None => bug!("Instance `{:?}` not already declared", instance)
-    };
-
-    trans_closure(ccx, lldecl, instance, &sig, abi);
-}
-
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                  def_id: DefId,
                                  substs: &'tcx Substs<'tcx>,
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index f49d63b8376..faf65f3f98b 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -26,11 +26,11 @@ use attributes;
 use base;
 use base::*;
 use build::*;
-use closure;
 use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
 use consts;
 use debuginfo::DebugLoc;
 use declare;
+use value::Value;
 use meth;
 use monomorphize::{self, Instance};
 use trans_item::TransItem;
@@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> {
                 // after passing through fulfill_obligation
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
                 let instance = Instance::new(def_id, substs);
-                let llfn = closure::trans_closure_method(ccx,
-                                                         vtable_closure.closure_def_id,
-                                                         vtable_closure.substs,
-                                                         instance,
-                                                         trait_closure_kind);
+                let llfn = trans_closure_method(
+                    ccx,
+                    vtable_closure.closure_def_id,
+                    vtable_closure.substs,
+                    instance,
+                    trait_closure_kind);
 
                 let method_ty = def_ty(ccx.shared(), def_id, substs);
                 Callee::ptr(llfn, method_ty)
@@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
     monomorphize::apply_param_substs(shared, substs, &ty)
 }
 
+
+fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
+                                  def_id: DefId,
+                                  substs: ty::ClosureSubsts<'tcx>,
+                                  method_instance: Instance<'tcx>,
+                                  trait_closure_kind: ty::ClosureKind)
+                                  -> ValueRef
+{
+    // If this is a closure, redirect to it.
+    let (llfn, _) = get_fn(ccx, def_id, substs.substs);
+
+    // If the closure is a Fn closure, but a FnOnce is needed (etc),
+    // then adapt the self type
+    let llfn_closure_kind = ccx.tcx().closure_kind(def_id);
+
+    let _icx = push_ctxt("trans_closure_adapter_shim");
+
+    debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
+           trait_closure_kind={:?}, llfn={:?})",
+           llfn_closure_kind, trait_closure_kind, Value(llfn));
+
+    match (llfn_closure_kind, trait_closure_kind) {
+        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
+            // No adapter needed.
+            llfn
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
+            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
+            // `fn(&mut self, ...)`. In fact, at trans time, these are
+            // basically the same thing, so we can just return llfn.
+            llfn
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
+            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
+            // self, ...)`.  We want a `fn(self, ...)`. We can produce
+            // this by doing something like:
+            //
+            //     fn call_once(self, ...) { call_mut(&self, ...) }
+            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
+            //
+            // These are both the same at trans time.
+            trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn)
+        }
+        _ => {
+            bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
+                 llfn_closure_kind,
+                 trait_closure_kind);
+        }
+    }
+}
+
+fn trans_fn_once_adapter_shim<'a, 'tcx>(
+    ccx: &'a CrateContext<'a, 'tcx>,
+    def_id: DefId,
+    substs: ty::ClosureSubsts<'tcx>,
+    method_instance: Instance<'tcx>,
+    llreffn: ValueRef)
+    -> ValueRef
+{
+    if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
+        return llfn;
+    }
+
+    debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
+           def_id, substs, Value(llreffn));
+
+    let tcx = ccx.tcx();
+
+    // Find a version of the closure type. Substitute static for the
+    // region since it doesn't really matter.
+    let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs);
+    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
+
+    // Make a version with the type of by-ref closure.
+    let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
+    sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
+    let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: unsafety,
+        abi: abi,
+        sig: sig.clone()
+    }));
+    debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
+           llref_fn_ty);
+
+
+    // Make a version of the closure type with the same arguments, but
+    // with argument #0 being by value.
+    assert_eq!(abi, Abi::RustCall);
+    sig.0.inputs[0] = closure_ty;
+
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
+
+    let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: unsafety,
+        abi: abi,
+        sig: ty::Binder(sig)
+    }));
+
+    // Create the by-value helper.
+    let function_name = method_instance.symbol_name(ccx.shared());
+    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
+    attributes::set_frame_pointer_elimination(ccx, lloncefn);
+
+    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
+    block_arena = TypedArena::new();
+    fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
+    let mut bcx = fcx.init(false);
+
+
+    // the first argument (`self`) will be the (by value) closure env.
+
+    let mut llargs = get_params(fcx.llfn);
+    let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
+    let env_arg = &fcx.fn_ty.args[0];
+    let llenv = if env_arg.is_indirect() {
+        llargs[self_idx]
+    } else {
+        let scratch = alloc_ty(bcx, closure_ty, "self");
+        let mut llarg_idx = self_idx;
+        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
+        scratch
+    };
+
+    debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
+    // Adjust llargs such that llargs[self_idx..] has the call arguments.
+    // For zero-sized closures that means sneaking in a new argument.
+    if env_arg.is_ignore() {
+        if self_idx > 0 {
+            self_idx -= 1;
+            llargs[self_idx] = llenv;
+        } else {
+            llargs.insert(0, llenv);
+        }
+    } else {
+        llargs[self_idx] = llenv;
+    }
+
+    let dest = fcx.llretslotptr.get();
+
+    let callee = Callee {
+        data: Fn(llreffn),
+        ty: llref_fn_ty
+    };
+
+    // Call the by-ref closure body with `self` in a cleanup scope,
+    // to drop `self` when the body returns, or in case it unwinds.
+    let self_scope = fcx.push_custom_cleanup_scope();
+    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
+
+    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
+
+    fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
+
+    fcx.finish(bcx, DebugLoc::None);
+
+    ccx.instances().borrow_mut().insert(method_instance, lloncefn);
+
+    lloncefn
+}
+
 /// Translates an adapter that implements the `Fn` trait for a fn
 /// pointer. This is basically the equivalent of something like:
 ///
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
deleted file mode 100644
index 0cefc49cb42..00000000000
--- a/src/librustc_trans/closure.rs
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use arena::TypedArena;
-use llvm::{self, ValueRef, get_params};
-use rustc::hir::def_id::DefId;
-use abi::{Abi, FnType};
-use attributes;
-use base::*;
-use callee::{self, Callee};
-use common::*;
-use debuginfo::{DebugLoc};
-use declare;
-use monomorphize::{Instance};
-use value::Value;
-use rustc::ty::{self, Ty, TyCtxt};
-
-use rustc::hir;
-
-fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           closure_id: DefId,
-                           fn_ty: Ty<'tcx>)
-                           -> Ty<'tcx> {
-    match tcx.closure_kind(closure_id) {
-        ty::ClosureKind::Fn => {
-            tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty)
-        }
-        ty::ClosureKind::FnMut => {
-            tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty)
-        }
-        ty::ClosureKind::FnOnce => fn_ty,
-    }
-}
-
-/// Returns the LLVM function declaration for a closure, creating it if
-/// necessary. If the ID does not correspond to a closure ID, returns None.
-fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                               closure_id: DefId,
-                                               substs: ty::ClosureSubsts<'tcx>)
-                                               -> ValueRef {
-    // Normalize type so differences in regions and typedefs don't cause
-    // duplicate declarations
-    let tcx = ccx.tcx();
-    let substs = tcx.erase_regions(&substs);
-    let instance = Instance::new(closure_id, substs.substs);
-
-    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
-        debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
-               instance, Value(llfn));
-        return llfn;
-    }
-
-    let symbol = instance.symbol_name(ccx.shared());
-
-    // Compute the rust-call form of the closure call method.
-    let sig = &tcx.closure_type(closure_id, substs).sig;
-    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-    let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
-    let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Normal,
-        abi: Abi::RustCall,
-        sig: ty::Binder(ty::FnSig {
-            inputs: Some(get_self_type(tcx, closure_id, closure_type))
-                        .into_iter().chain(sig.inputs).collect(),
-            output: sig.output,
-            variadic: false
-        })
-    }));
-    let llfn = declare::declare_fn(ccx, &symbol, function_type);
-
-    attributes::set_frame_pointer_elimination(ccx, llfn);
-
-    debug!("get_or_create_declaration_if_closure(): inserting new \
-            closure {:?}: {:?}",
-           instance, Value(llfn));
-
-    // NOTE: We do *not* store llfn in the ccx.instances() map here,
-    //       that is only done, when the closures body is translated.
-
-    llfn
-}
-
-pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                            closure_def_id: DefId,
-                                            closure_substs: ty::ClosureSubsts<'tcx>) {
-    // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
-    // defid of the closure in its original crate, whereas `id` will be the id of the local
-    // inlined copy.
-    debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})",
-           closure_def_id, closure_substs);
-
-    let tcx = ccx.tcx();
-    let _icx = push_ctxt("closure::trans_closure_expr");
-
-    let instance = Instance::new(closure_def_id, closure_substs.substs);
-
-    // If we have not done so yet, translate this closure's body
-    if  !ccx.instances().borrow().contains_key(&instance) {
-        let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
-
-        unsafe {
-            if ccx.sess().target.target.options.allows_weak_linkage {
-                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage);
-                llvm::SetUniqueComdat(ccx.llmod(), llfn);
-            } else {
-                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage);
-            }
-        }
-
-        // set an inline hint for all closures
-        attributes::inline(llfn, attributes::InlineAttr::Hint);
-
-        // Get the type of this closure. Use the current `param_substs` as
-        // the closure substitutions. This makes sense because the closure
-        // takes the same set of type arguments as the enclosing fn, and
-        // this function (`trans_closure`) is invoked at the point
-        // of the closure expression.
-
-        let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
-        let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-
-        let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
-                                                              closure_substs);
-        let sig = ty::FnSig {
-            inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
-                        .into_iter().chain(sig.inputs).collect(),
-            output: sig.output,
-            variadic: false
-        };
-
-        trans_closure(ccx,
-                      llfn,
-                      instance,
-                      &sig,
-                      Abi::RustCall);
-
-        ccx.instances().borrow_mut().insert(instance, llfn);
-    }
-}
-
-pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
-                                      closure_def_id: DefId,
-                                      substs: ty::ClosureSubsts<'tcx>,
-                                      method_instance: Instance<'tcx>,
-                                      trait_closure_kind: ty::ClosureKind)
-                                      -> ValueRef
-{
-    // If this is a closure, redirect to it.
-    let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
-
-    // If weak linkage is not allowed, we have to make sure that a local,
-    // private copy of the closure is available in this codegen unit
-    if !ccx.sess().target.target.options.allows_weak_linkage &&
-       !ccx.sess().opts.single_codegen_unit() {
-
-        trans_closure_body_via_mir(ccx, closure_def_id, substs);
-    }
-
-    // If the closure is a Fn closure, but a FnOnce is needed (etc),
-    // then adapt the self type
-    let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
-
-    let _icx = push_ctxt("trans_closure_adapter_shim");
-
-    debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
-           trait_closure_kind={:?}, llfn={:?})",
-           llfn_closure_kind, trait_closure_kind, Value(llfn));
-
-    match (llfn_closure_kind, trait_closure_kind) {
-        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
-        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
-            // No adapter needed.
-            llfn
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
-            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
-            // `fn(&mut self, ...)`. In fact, at trans time, these are
-            // basically the same thing, so we can just return llfn.
-            llfn
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
-            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
-            // self, ...)`.  We want a `fn(self, ...)`. We can produce
-            // this by doing something like:
-            //
-            //     fn call_once(self, ...) { call_mut(&self, ...) }
-            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
-            //
-            // These are both the same at trans time.
-            trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
-        }
-        _ => {
-            bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
-                 llfn_closure_kind,
-                 trait_closure_kind);
-        }
-    }
-}
-
-fn trans_fn_once_adapter_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    closure_def_id: DefId,
-    substs: ty::ClosureSubsts<'tcx>,
-    method_instance: Instance<'tcx>,
-    llreffn: ValueRef)
-    -> ValueRef
-{
-    if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
-        return llfn;
-    }
-
-    debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
-           closure_def_id, substs, Value(llreffn));
-
-    let tcx = ccx.tcx();
-
-    // Find a version of the closure type. Substitute static for the
-    // region since it doesn't really matter.
-    let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs);
-    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
-
-    // Make a version with the type of by-ref closure.
-    let ty::ClosureTy { unsafety, abi, mut sig } =
-        tcx.closure_type(closure_def_id, substs);
-    sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
-    let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: sig.clone()
-    }));
-    debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
-           llref_fn_ty);
-
-
-    // Make a version of the closure type with the same arguments, but
-    // with argument #0 being by value.
-    assert_eq!(abi, Abi::RustCall);
-    sig.0.inputs[0] = closure_ty;
-
-    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
-    let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: ty::Binder(sig)
-    }));
-
-    // Create the by-value helper.
-    let function_name = method_instance.symbol_name(ccx.shared());
-    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
-    attributes::set_frame_pointer_elimination(ccx, lloncefn);
-
-    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false);
-
-
-    // the first argument (`self`) will be the (by value) closure env.
-
-    let mut llargs = get_params(fcx.llfn);
-    let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
-    let env_arg = &fcx.fn_ty.args[0];
-    let llenv = if env_arg.is_indirect() {
-        llargs[self_idx]
-    } else {
-        let scratch = alloc_ty(bcx, closure_ty, "self");
-        let mut llarg_idx = self_idx;
-        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
-        scratch
-    };
-
-    debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
-    // Adjust llargs such that llargs[self_idx..] has the call arguments.
-    // For zero-sized closures that means sneaking in a new argument.
-    if env_arg.is_ignore() {
-        if self_idx > 0 {
-            self_idx -= 1;
-            llargs[self_idx] = llenv;
-        } else {
-            llargs.insert(0, llenv);
-        }
-    } else {
-        llargs[self_idx] = llenv;
-    }
-
-    let dest = fcx.llretslotptr.get();
-
-    let callee = Callee {
-        data: callee::Fn(llreffn),
-        ty: llref_fn_ty
-    };
-
-    // Call the by-ref closure body with `self` in a cleanup scope,
-    // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = fcx.push_custom_cleanup_scope();
-    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
-
-    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
-
-    fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
-
-    fcx.finish(bcx, DebugLoc::None);
-
-    ccx.instances().borrow_mut().insert(method_instance, lloncefn);
-
-    lloncefn
-}
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index a79719a4d22..2728a666556 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -446,24 +446,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         debug!("visiting rvalue {:?}", *rvalue);
 
         match *rvalue {
-            mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id,
-                                                               ref substs), _) => {
-                let mir = self.scx.tcx().item_mir(def_id);
-
-                let concrete_substs = monomorphize::apply_param_substs(self.scx,
-                                                                       self.param_substs,
-                                                                       &substs.substs);
-                let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);
-
-                let visitor = MirNeighborCollector {
-                    scx: self.scx,
-                    mir: &mir,
-                    output: self.output,
-                    param_substs: concrete_substs
-                };
-
-                visit_mir_and_promoted(visitor, &mir);
-            }
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
@@ -888,10 +870,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         traits::VtableImpl(impl_data) => {
             Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
         }
-        // If we have a closure or a function pointer, we will also encounter
-        // the concrete closure/function somewhere else (during closure or fn
-        // pointer construction). That's where we track those things.
-        traits::VtableClosure(..) |
+        traits::VtableClosure(closure_data) => {
+            Some((closure_data.closure_def_id, closure_data.substs.substs))
+        }
+        // Trait object and function pointer shims are always
+        // instantiated in-place, and as they are just an ABI-adjusting
+        // indirect call they do not have any dependencies.
         traits::VtableFnPointer(..) |
         traits::VtableObject(..) => {
             None
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 6f3a7262152..a0fac9cc659 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -44,6 +44,8 @@ use rustc::hir;
 
 use arena::TypedArena;
 use libc::{c_uint, c_char};
+use std::borrow::Cow;
+use std::iter;
 use std::ops::Deref;
 use std::ffi::CString;
 use std::cell::{Cell, RefCell, Ref};
@@ -1069,3 +1071,32 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
 }
+
+pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                          ty: Ty<'tcx>)
+                          -> Cow<'tcx, ty::BareFnTy<'tcx>>
+{
+    match ty.sty {
+        ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty),
+        // Shims currently have type TyFnPtr. Not sure this should remain.
+        ty::TyFnPtr(fty) => Cow::Borrowed(fty),
+        ty::TyClosure(def_id, substs) => {
+            let tcx = ccx.tcx();
+            let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs);
+
+            let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
+            let env_ty = match tcx.closure_kind(def_id) {
+                ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty),
+                ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty),
+                ty::ClosureKind::FnOnce => ty,
+            };
+
+            let sig = sig.map_bound(|sig| ty::FnSig {
+                inputs: iter::once(env_ty).chain(sig.inputs).collect(),
+                ..sig
+            });
+            Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
+        }
+        _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
+    }
+}
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 1ec5ca4a563..662e3bec66d 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -25,6 +25,7 @@ use rustc::ty;
 use abi::{Abi, FnType};
 use attributes;
 use context::CrateContext;
+use common;
 use type_::Type;
 use value::Value;
 
@@ -103,8 +104,8 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef {
 pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let abi = fn_type.fn_abi();
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
+    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
     let fty = FnType::new(ccx, abi, &sig, &[]);
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 8ef7f04d4ee..0757343a8af 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -109,7 +109,6 @@ mod cabi_x86_64;
 mod cabi_x86_win64;
 mod callee;
 mod cleanup;
-mod closure;
 mod collector;
 mod common;
 mod consts;
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index b8d346b11c1..bca81fa3645 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 }
                 failure?;
 
-                // FIXME Shouldn't need to manually trigger closure instantiations.
-                if let mir::AggregateKind::Closure(def_id, substs) = *kind {
-                    use closure;
-                    closure::trans_closure_body_via_mir(self.ccx,
-                                                        def_id,
-                                                        self.monomorphize(&substs));
-                }
-
                 match *kind {
                     mir::AggregateKind::Array => {
                         self.const_array(dest_ty, &fields)
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index f25877b1de1..bf01db0ffd3 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -133,15 +133,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     },
                     _ => {
-                        // FIXME Shouldn't need to manually trigger closure instantiations.
-                        if let mir::AggregateKind::Closure(def_id, substs) = *kind {
-                            use closure;
-
-                            closure::trans_closure_body_via_mir(bcx.ccx(),
-                                                                def_id,
-                                                                bcx.monomorphize(&substs));
-                        }
-
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 16bc7e212cf..c5a7dbbcf54 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -166,6 +166,11 @@ impl<'a, 'tcx> TransItem<'tcx> {
             llvm::SetUniqueComdat(ccx.llmod(), lldecl);
         }
 
+        if let ty::TyClosure(..) = mono_ty.sty {
+            // set an inline hint for all closures
+            attributes::inline(lldecl, attributes::InlineAttr::Hint);
+        }
+
         attributes::from_fn_attrs(ccx, &attrs, lldecl);
 
         ccx.instances().borrow_mut().insert(instance, lldecl);