diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 4bb2b13998f7..6c99632341fb 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -13,13 +13,11 @@ use libc::{c_uint, c_ulonglong}; use llvm::{self, ValueRef, AttrHelper}; use middle::ty; use middle::infer; -use middle::traits::ProjectionMode; use session::config::NoDebugInfo; pub use syntax::attr::InlineAttr; use syntax::ast; use rustc_front::hir; use trans::abi::Abi; -use trans::base; use trans::common; use trans::context::CrateContext; use trans::machine; @@ -130,21 +128,12 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx -> llvm::AttrBuilder { use middle::ty::{BrAnon, ReLateBound}; - let function_type; - let (fn_sig, abi, env_ty) = match fn_type.sty { - ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None), - ty::TyClosure(closure_did, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), - &ccx.tcx().tables, - ProjectionMode::Any); - function_type = infcx.closure_type(closure_did, substs); - let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); - (&function_type.sig, Abi::RustCall, Some(self_type)) - } - _ => ccx.sess().bug("expected closure or function.") + let f = match fn_type.sty { + ty::TyFnDef(_, _, f) | ty::TyFnPtr(f) => f, + _ => unreachable!("expected fn type, found {:?}", fn_type) }; - let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); + let fn_sig = ccx.tcx().erase_late_bound_regions(&f.sig); let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig); let mut attrs = llvm::AttrBuilder::new(); @@ -153,30 +142,17 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // These have an odd calling convention, so we need to manually // unpack the input ty's let input_tys = match fn_type.sty { - ty::TyClosure(..) => { - assert!(abi == Abi::RustCall); - - match fn_sig.inputs[0].sty { - ty::TyTuple(ref inputs) => { - let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; - full_inputs.extend_from_slice(inputs); - full_inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - }, - ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; + ty::TyFnDef(..) | ty::TyFnPtr(_) if f.abi == Abi::RustCall => { + let first = Some(fn_sig.inputs[0]).into_iter(); match fn_sig.inputs[1].sty { ty::TyTuple(ref t_in) => { - inputs.extend_from_slice(&t_in[..]); - inputs + first.chain(t_in.iter().cloned()) } _ => ccx.sess().bug("expected tuple'd inputs") } } - _ => fn_sig.inputs.clone() + _ => None.into_iter().chain(fn_sig.inputs.iter().cloned()) }; // Index 0 is the return value of the llvm func, so we start at 1 @@ -228,7 +204,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx } } - for &t in input_tys.iter() { + for t in input_tys { match t.sty { _ if type_of::arg_is_indirect(ccx, t) => { let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t)); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 69b296edd306..905ccda198c5 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -192,22 +192,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - closure_id: DefId, - fn_ty: Ty<'tcx>) - -> Ty<'tcx> { - let closure_kind = ccx.tcx().closure_kind(closure_id); - match closure_kind { - ty::ClosureKind::Fn => { - ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) - } - ty::ClosureKind::FnMut => { - ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) - } - ty::ClosureKind::FnOnce => fn_ty, - } -} - pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKind { *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap() } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d4272e791850..df8dd1a09b7a 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -14,7 +14,7 @@ use llvm::{ValueRef, get_params}; use middle::def_id::DefId; use middle::infer; use middle::traits::ProjectionMode; -use trans::abi::Abi::RustCall; +use trans::abi::Abi; use trans::adt; use trans::attributes; use trans::base::*; @@ -30,7 +30,7 @@ use trans::monomorphize::{Instance}; use trans::type_of::*; use trans::value::Value; use trans::Disr; -use middle::ty; +use middle::ty::{self, Ty, TyCtxt}; use session::config::FullDebugInfo; use syntax::ast; @@ -49,7 +49,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Special case for small by-value selfs. let closure_ty = node_id_type(bcx, bcx.fcx.id); - let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty); + let self_type = get_self_type(bcx.tcx(), closure_def_id, closure_ty); let kind = kind_for_closure(bcx.ccx(), closure_def_id); let llenv = if kind == ty::ClosureKind::FnOnce && !arg_is_indirect(bcx.ccx(), self_type) { @@ -131,6 +131,21 @@ impl<'a> ClosureEnv<'a> { } } +pub fn get_self_type<'tcx>(tcx: &TyCtxt<'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::ReStatic), fn_ty) + } + ty::ClosureKind::FnMut => { + tcx.mk_mut_ref(tcx.mk_region(ty::ReStatic), 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. pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -139,22 +154,38 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> ValueRef { // Normalize type so differences in regions and typedefs don't cause // duplicate declarations - let substs = ccx.tcx().erase_regions(substs); - let mono_id = Instance { + let tcx = ccx.tcx(); + let substs = tcx.erase_regions(substs); + let instance = Instance { def: closure_id, params: &substs.func_substs.types }; - if let Some(&llfn) = ccx.closure_vals().borrow().get(&mono_id) { + if let Some(&llfn) = ccx.instances().borrow().get(&instance) { debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}", - mono_id, Value(llfn)); + instance, Value(llfn)); return llfn; } - let path = ccx.tcx().def_path(closure_id); + let path = tcx.def_path(closure_id); let symbol = mangle_internal_name_by_path_and_seq(path, "closure"); - let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs)); + // Compute the rust-call form of the closure call method. + let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any); + let sig = &infcx.closure_type(closure_id, &substs).sig; + let sig = tcx.erase_late_bound_regions(sig); + let sig = infer::normalize_associated_type(tcx, &sig); + let closure_type = tcx.mk_closure_from_closure_substs(closure_id, Box::new(substs)); + let function_type = tcx.mk_fn_ptr(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::define_internal_fn(ccx, &symbol, function_type); // set an inline hint for all closures @@ -162,8 +193,8 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?}: {:?}", - mono_id, Value(llfn)); - ccx.closure_vals().borrow_mut().insert(mono_id, llfn); + instance, Value(llfn)); + ccx.instances().borrow_mut().insert(instance, llfn); llfn } @@ -347,7 +378,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version of the closure type with the same arguments, but // with argument #0 being by value. - assert_eq!(abi, RustCall); + assert_eq!(abi, Abi::RustCall); sig.0.inputs[0] = closure_ty; let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: unsafety, diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 848ed2c1211f..7bee48039359 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -22,10 +22,8 @@ use llvm::{self, ValueRef}; use middle::ty; use middle::infer; -use middle::traits::ProjectionMode; use trans::abi::{Abi, FnType}; use trans::attributes; -use trans::base; use trans::context::CrateContext; use trans::type_::Type; use trans::type_of; @@ -94,37 +92,21 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { /// update the declaration and return existing ValueRef instead. 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); + debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let function_type; // placeholder so that the memory ownership works out ok - let (sig, abi, env) = match fn_type.sty { - ty::TyFnDef(_, _, f) | - ty::TyFnPtr(f) => { - (&f.sig, f.abi, None) - } - ty::TyClosure(closure_did, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), - &ccx.tcx().tables, - ProjectionMode::Any); - function_type = infcx.closure_type(closure_did, substs); - let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); - debug!("declare_rust_fn function_type={:?} self_type={:?}", - function_type, self_type); - (&function_type.sig, Abi::RustCall, Some(self_type)) - } - _ => ccx.sess().bug("expected closure or fn") + let f = match fn_type.sty { + ty::TyFnDef(_, _, f) | ty::TyFnPtr(f) => f, + _ => unreachable!("expected fn type for {:?}, found {:?}", name, fn_type) }; - - let sig = ccx.tcx().erase_late_bound_regions(sig); + let sig = ccx.tcx().erase_late_bound_regions(&f.sig); let sig = infer::normalize_associated_type(ccx.tcx(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - let (cconv, llfty) = if abi == Abi::Rust || abi == Abi::RustCall { - (llvm::CCallConv, type_of::type_of_rust_fn(ccx, env, &sig, abi)) + let (cconv, llfty) = if f.abi == Abi::Rust || f.abi == Abi::RustCall { + (llvm::CCallConv, type_of::type_of_rust_fn(ccx, &sig, f.abi)) } else { - let fty = FnType::new(ccx, abi, &sig, &[]); + let fty = FnType::new(ccx, f.abi, &sig, &[]); (fty.cconv, fty.to_llvm(ccx)) }; @@ -137,10 +119,10 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn); } - if abi == Abi::Rust || abi == Abi::RustCall { + if f.abi == Abi::Rust || f.abi == Abi::RustCall { attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); } else { - FnType::new(ccx, abi, &sig, &[]).add_attributes(llfn); + FnType::new(ccx, f.abi, &sig, &[]).add_attributes(llfn); } llfn diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index b3beecfb9b8d..b4f431f09e8c 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -88,14 +88,11 @@ pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - maybe_env: Option>, sig: &ty::FnSig<'tcx>, abi: Abi) -> Type { - debug!("type_of_rust_fn(sig={:?},abi={:?})", - sig, - abi); + debug!("type_of_rust_fn(sig={:?}, abi={:?})", sig, abi); assert!(!sig.variadic); // rust fns are never variadic @@ -129,11 +126,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::FnDiverging => Type::void(cx) }; - // Arg 1: Environment - if let Some(env_ty) = maybe_env { - atys.push(type_of_explicit_arg(cx, env_ty)); - } - // ... then explicit args. for input in inputs { let arg_ty = type_of_explicit_arg(cx, input); @@ -384,7 +376,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let sig = cx.tcx().erase_late_bound_regions(&f.sig); let sig = infer::normalize_associated_type(cx.tcx(), &sig); if f.abi == Abi::Rust || f.abi == Abi::RustCall { - type_of_rust_fn(cx, None, &sig, f.abi).ptr_to() + type_of_rust_fn(cx, &sig, f.abi).ptr_to() } else { FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to() }