summaryrefslogtreecommitdiff
path: root/src/librustc_trans/trans/monomorphize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/monomorphize.rs')
-rw-r--r--src/librustc_trans/trans/monomorphize.rs275
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>,