diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a990a7c507fd..c7cad6455bc3 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) { - 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); - } - +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_closure(..., {})", instance); + info!("trans_instance({})", instance); - let fn_ty = FnType::new(ccx, abi, sig, &[]); + 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); + + if !ccx.sess().no_landing_pads() { + attributes::emit_uwtable(lldecl, true); + } + + 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 f49d63b83764..faf65f3f98b0 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 0cefc49cb425..000000000000 --- 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 or the MIT license -// , 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 a79719a4d227..2728a666556e 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 6f3a72621520..a0fac9cc6599 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 1ec5ca4a563a..662e3bec66db 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 8ef7f04d4ee1..0757343a8af5 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 b8d346b11c13..bca81fa36458 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 f25877b1de12..bf01db0ffd32 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 16bc7e212cf5..c5a7dbbcf548 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);