diff options
Diffstat (limited to 'src/librustc_trans/trans/monomorphize.rs')
-rw-r--r-- | src/librustc_trans/trans/monomorphize.rs | 275 |
1 files changed, 95 insertions, 180 deletions
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index c6119416e47..2e75439ffc3 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,38 +17,35 @@ use middle::subst; use middle::subst::{Subst, Substs}; use middle::ty::fold::{TypeFolder, TypeFoldable}; use trans::attributes; -use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; +use trans::base::{push_ctxt}; use trans::base::trans_fn; use trans::base; use trans::common::*; use trans::declare; -use trans::foreign; use middle::ty::{self, Ty, TyCtxt}; use trans::Disr; use rustc::front::map as hir_map; +use rustc::util::ppaux; use rustc_front::hir; -use syntax::abi::Abi; -use syntax::ast; use syntax::attr; use syntax::errors; + +use std::fmt; use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, psubsts: &'tcx subst::Substs<'tcx>) - -> (ValueRef, Ty<'tcx>, bool) { + -> (ValueRef, Ty<'tcx>) { debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts); assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); - // we can only monomorphize things in this crate (or inlined into it) - let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap(); - let _icx = push_ctxt("monomorphic_fn"); - let hash_id = MonoId { + let instance = Instance { def: fn_id, params: &psubsts.types }; @@ -59,41 +56,15 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty); debug!("mono_ty = {:?} (post-substitution)", mono_ty); - match ccx.monomorphized().borrow().get(&hash_id) { + match ccx.instances().borrow().get(&instance) { Some(&val) => { - debug!("leaving monomorphic fn {}", - ccx.tcx().item_path_str(fn_id)); - return (val, mono_ty, false); + debug!("leaving monomorphic fn {:?}", instance); + return (val, mono_ty); } None => () } - debug!("monomorphic_fn(\ - fn_id={:?}, \ - psubsts={:?}, \ - hash_id={:?})", - fn_id, - psubsts, - hash_id); - - - let map_node = errors::expect( - ccx.sess().diagnostic(), - ccx.tcx().map.find(fn_node_id), - || { - format!("while monomorphizing {:?}, couldn't find it in \ - the item map (may have attempted to monomorphize \ - an item defined in a different crate?)", - fn_id) - }); - - if let hir_map::NodeForeignItem(_) = map_node { - let abi = ccx.tcx().map.get_foreign_abi(fn_node_id); - if abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic { - // Foreign externs don't have to be monomorphized. - return (get_item_val(ccx, fn_node_id), mono_ty, true); - } - } + debug!("monomorphic_fn({:?})", instance); ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1); @@ -110,8 +81,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // recursively more than thirty times can probably safely be assumed // to be causing an infinite expansion. if depth > ccx.sess().recursion_limit.get() { - ccx.sess().span_fatal(ccx.tcx().map.span(fn_node_id), - "reached the recursion limit during monomorphization"); + let error = format!("reached the recursion limit while instantiating `{}`", + instance); + if let Some(id) = ccx.tcx().map.as_local_node_id(fn_id) { + ccx.sess().span_fatal(ccx.tcx().map.span(id), &error); + } else { + ccx.sess().fatal(&error); + } } monomorphizing.insert(fn_id, depth + 1); @@ -120,173 +96,112 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let hash; let s = { let mut state = SipHasher::new(); - hash_id.hash(&mut state); + instance.hash(&mut state); mono_ty.hash(&mut state); hash = format!("h{}", state.finish()); - let path = ccx.tcx().map.def_path_from_id(fn_node_id); + let path = ccx.tcx().map.def_path(fn_id); exported_name(path, &hash[..]) }; debug!("monomorphize_fn mangled to {}", s); + assert!(declare::get_defined_value(ccx, &s).is_none()); - // This shouldn't need to option dance. - let mut hash_id = Some(hash_id); - let mut mk_lldecl = |abi: Abi| { - let lldecl = if abi != Abi::Rust { - foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s) - } else { - // FIXME(nagisa): perhaps needs a more fine grained selection? See - // setup_lldecl below. - declare::define_internal_rust_fn(ccx, &s, mono_ty) - }; + // FIXME(nagisa): perhaps needs a more fine grained selection? + let lldecl = declare::define_internal_fn(ccx, &s, mono_ty); + // FIXME(eddyb) Doubt all extern fn should allow unwinding. + attributes::unwind(lldecl, true); - ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); - lldecl - }; - let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { - base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - attributes::from_fn_attrs(ccx, attrs, lldecl); - - let is_first = !ccx.available_monomorphizations().borrow().contains(&s); - if is_first { - ccx.available_monomorphizations().borrow_mut().insert(s.clone()); - } + ccx.instances().borrow_mut().insert(instance, lldecl); - let trans_everywhere = attr::requests_inline(attrs); - if trans_everywhere && !is_first { - llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage); - } - - // If `true`, then `lldecl` should be given a function body. - // Otherwise, it should be left as a declaration of an external - // function, with no definition in the current compilation unit. - trans_everywhere || is_first - }; + // we can only monomorphize things in this crate (or inlined into it) + let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap(); + let map_node = errors::expect( + ccx.sess().diagnostic(), + ccx.tcx().map.find(fn_node_id), + || { + format!("while instantiating `{}`, couldn't find it in \ + the item map (may have attempted to monomorphize \ + an item defined in a different crate?)", + instance) + }); + match map_node { + hir_map::NodeItem(&hir::Item { + ref attrs, node: hir::ItemFn(ref decl, _, _, _, _, ref body), .. + }) | + hir_map::NodeTraitItem(&hir::TraitItem { + ref attrs, node: hir::MethodTraitItem( + hir::MethodSig { ref decl, .. }, Some(ref body)), .. + }) | + hir_map::NodeImplItem(&hir::ImplItem { + ref attrs, node: hir::ImplItemKind::Method( + hir::MethodSig { ref decl, .. }, ref body), .. + }) => { + base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); + attributes::from_fn_attrs(ccx, attrs, lldecl); + + let is_first = !ccx.available_monomorphizations().borrow().contains(&s); + if is_first { + ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + } - let lldecl = match map_node { - hir_map::NodeItem(i) => { - match *i { - hir::Item { - node: hir::ItemFn(ref decl, _, _, abi, _, ref body), - .. - } => { - let d = mk_lldecl(abi); - let needs_body = setup_lldecl(d, &i.attrs); - if needs_body { - if abi != Abi::Rust { - foreign::trans_rust_fn_with_foreign_abi( - ccx, &decl, &body, &[], d, psubsts, fn_node_id, - Some(&hash[..])); - } else { - trans_fn(ccx, - &decl, - &body, - d, - psubsts, - fn_node_id, - &i.attrs); - } - } - - d - } - _ => { - ccx.sess().bug("Can't monomorphize this kind of item") - } + let trans_everywhere = attr::requests_inline(attrs); + if trans_everywhere && !is_first { + llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage); } - } - hir_map::NodeVariant(v) => { - let variant = inlined_variant_def(ccx, fn_node_id); - assert_eq!(v.node.name, variant.name); - let d = mk_lldecl(Abi::Rust); - attributes::inline(d, attributes::InlineAttr::Hint); - trans_enum_variant(ccx, fn_node_id, Disr::from(variant.disr_val), psubsts, d); - d - } - hir_map::NodeImplItem(impl_item) => { - match impl_item.node { - hir::ImplItemKind::Method(ref sig, ref body) => { - let d = mk_lldecl(Abi::Rust); - let needs_body = setup_lldecl(d, &impl_item.attrs); - if needs_body { - trans_fn(ccx, - &sig.decl, - body, - d, - psubsts, - impl_item.id, - &impl_item.attrs); - } - d - } - _ => { - ccx.sess().bug(&format!("can't monomorphize a {:?}", - map_node)) - } + + if trans_everywhere || is_first { + trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id); } } - hir_map::NodeTraitItem(trait_item) => { - match trait_item.node { - hir::MethodTraitItem(ref sig, Some(ref body)) => { - let d = mk_lldecl(Abi::Rust); - let needs_body = setup_lldecl(d, &trait_item.attrs); - if needs_body { - trans_fn(ccx, - &sig.decl, - body, - d, - psubsts, - trait_item.id, - &trait_item.attrs); - } - d - } - _ => { - ccx.sess().bug(&format!("can't monomorphize a {:?}", - map_node)) + + hir_map::NodeVariant(_) | hir_map::NodeStructCtor(_) => { + let disr = match map_node { + hir_map::NodeVariant(_) => { + Disr::from(inlined_variant_def(ccx, fn_node_id).disr_val) } - } - } - hir_map::NodeStructCtor(struct_def) => { - let d = mk_lldecl(Abi::Rust); - attributes::inline(d, attributes::InlineAttr::Hint); - if struct_def.is_struct() { - panic!("ast-mapped struct didn't have a ctor id") - } - base::trans_tuple_struct(ccx, - struct_def.id(), - psubsts, - d); - d + hir_map::NodeStructCtor(_) => Disr(0), + _ => unreachable!() + }; + attributes::inline(lldecl, attributes::InlineAttr::Hint); + base::trans_ctor_shim(ccx, fn_node_id, disr, psubsts, lldecl); } - // Ugh -- but this ensures any new variants won't be forgotten - hir_map::NodeForeignItem(..) | - hir_map::NodeLifetime(..) | - hir_map::NodeTyParam(..) | - hir_map::NodeExpr(..) | - hir_map::NodeStmt(..) | - hir_map::NodeBlock(..) | - hir_map::NodePat(..) | - hir_map::NodeLocal(..) => { - ccx.sess().bug(&format!("can't monomorphize a {:?}", - map_node)) - } + _ => unreachable!("can't monomorphize a {:?}", map_node) }; ccx.monomorphizing().borrow_mut().insert(fn_id, depth); debug!("leaving monomorphic fn {}", ccx.tcx().item_path_str(fn_id)); - (lldecl, mono_ty, true) + (lldecl, mono_ty) } -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct MonoId<'tcx> { +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Instance<'tcx> { pub def: DefId, pub params: &'tcx subst::VecPerParamSpace<Ty<'tcx>> } +impl<'tcx> fmt::Display for Instance<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let substs = Substs { + types: self.params.clone(), + regions: subst::ErasedRegions + }; + ppaux::parameterized(f, &substs, self.def, ppaux::Ns::Value, &[], + |tcx| tcx.lookup_item_type(self.def).generics) + } +} + +impl<'tcx> Instance<'tcx> { + pub fn mono(tcx: &TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { + Instance { + def: def_id, + params: &tcx.mk_substs(Substs::trans_empty()).types + } + } +} + /// Monomorphizes a type from the AST by first applying the in-scope /// substitutions and then normalizing any associated types. pub fn apply_param_substs<'tcx,T>(tcx: &TyCtxt<'tcx>, |