trans: Condense the fn instantiation logic into callee.

This commit is contained in:
Eduard Burtescu 2016-02-23 22:04:51 +02:00
parent b05556e06d
commit cdfad40735
5 changed files with 143 additions and 524 deletions

View File

@ -192,22 +192,6 @@ fn drop(&mut self) {
}
}
fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>,
name: &str,
attrs: &[ast::Attribute])
-> ValueRef {
if let Some(n) = ccx.externs().borrow().get(name) {
return *n;
}
let f = declare::declare_rust_fn(ccx, name, fn_ty);
attributes::from_fn_attrs(ccx, &attrs, f);
ccx.externs().borrow_mut().insert(name.to_string(), f);
f
}
pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
closure_id: DefId,
fn_ty: Ty<'tcx>)
@ -865,34 +849,6 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
}
}
pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId)
-> datum::Datum<'tcx, datum::Rvalue> {
let name = ccx.sess().cstore.item_symbol(def_id);
let attrs = ccx.sess().cstore.item_attrs(def_id);
let ty = ccx.tcx().lookup_item_type(def_id).ty;
match ty.sty {
ty::TyFnDef(_, _, fty) => {
let abi = fty.abi;
let fty = infer::normalize_associated_type(ccx.tcx(), fty);
let ty = ccx.tcx().mk_fn_ptr(fty);
let llfn = match ccx.sess().target.target.adjust_abi(abi) {
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
ccx.sess().bug("unexpected intrinsic in get_extern_fn")
}
Abi::Rust | Abi::RustCall => {
get_extern_rust_fn(ccx, ty, &name, &attrs)
}
_ => {
foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs)
}
};
datum::immediate_rvalue(llfn, ty)
}
_ => unreachable!("get_extern_fn: expected fn item type, found {}", ty)
}
}
pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llfn: ValueRef,
llargs: &[ValueRef],
@ -2186,20 +2142,11 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
Result::new(bcx, llresult)
}
pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ctor_id: ast::NodeId,
param_substs: &'tcx Substs<'tcx>,
llfndecl: ValueRef) {
let _icx = push_ctxt("trans_tuple_struct");
trans_enum_variant_or_tuple_like_struct(ccx, ctor_id, Disr(0), param_substs, llfndecl);
}
fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ctor_id: ast::NodeId,
disr: Disr,
param_substs: &'tcx Substs<'tcx>,
llfndecl: ValueRef) {
pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ctor_id: ast::NodeId,
disr: Disr,
param_substs: &'tcx Substs<'tcx>,
llfndecl: ValueRef) {
let ctor_ty = ccx.tcx().node_id_to_type(ctor_id);
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
@ -2557,54 +2504,6 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
}
}
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId,
cc: llvm::CallConv,
llfty: Type)
-> ValueRef {
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
let llfn = declare::define_fn(ccx, &sym[..], cc, llfty,
ty::FnConverging(ccx.tcx().mk_nil())).unwrap_or_else(||{
ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
});
finish_register_fn(ccx, sym, node_id);
llfn
}
fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId) {
ccx.item_symbols().borrow_mut().insert(node_id, sym);
}
fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
sp: Span,
sym: String,
node_id: ast::NodeId,
node_type: Ty<'tcx>)
-> ValueRef {
if let ty::TyFnDef(_, _, ref f) = node_type.sty {
if f.abi != Abi::Rust && f.abi != Abi::RustCall {
ccx.sess().span_bug(sp,
&format!("only the `{}` or `{}` calling conventions are valid \
for this function; `{}` was specified",
Abi::Rust.name(),
Abi::RustCall.name(),
f.abi.name()));
}
} else {
ccx.sess().span_bug(sp, "expected bare rust function")
}
let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(|| {
ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
});
finish_register_fn(ccx, sym, node_id);
llfn
}
pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool {
match *sess.entry_fn.borrow() {
Some((entry_id, _)) => node_id == entry_id,
@ -2724,119 +2623,6 @@ fn contains_null(s: &str) -> bool {
s.bytes().any(|b| b == 0)
}
pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
debug!("get_item_val(id=`{}`)", id);
if let Some(v) = ccx.item_vals().borrow().get(&id).cloned() {
return v;
}
let item = ccx.tcx().map.get(id);
debug!("get_item_val: id={} item={:?}", id, item);
let val = match item {
hir_map::NodeItem(i) => {
let ty = ccx.tcx().node_id_to_type(i.id);
let sym = || exported_name(ccx, id, ty, &i.attrs);
let v = match i.node {
hir::ItemFn(_, _, _, abi, _, _) => {
let sym = sym();
let llfn = if abi == Abi::Rust {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id)
};
attributes::from_fn_attrs(ccx, &i.attrs, llfn);
llfn
}
_ => ccx.sess().bug("get_item_val: weird result in table"),
};
v
}
hir_map::NodeTraitItem(trait_item) => {
debug!("get_item_val(): processing a NodeTraitItem");
match trait_item.node {
hir::MethodTraitItem(_, Some(_)) => {
register_method(ccx, id, &trait_item.attrs, trait_item.span)
}
_ => {
ccx.sess().span_bug(trait_item.span,
"unexpected variant: trait item other than a provided \
method in get_item_val()");
}
}
}
hir_map::NodeImplItem(impl_item) => {
match impl_item.node {
hir::ImplItemKind::Method(..) => {
register_method(ccx, id, &impl_item.attrs, impl_item.span)
}
_ => {
ccx.sess().span_bug(impl_item.span,
"unexpected variant: non-method impl item in \
get_item_val()");
}
}
}
hir_map::NodeForeignItem(ni) => {
match ni.node {
hir::ForeignItemFn(..) => {
let abi = ccx.tcx().map.get_foreign_abi(id);
let ty = ccx.tcx().node_id_to_type(ni.id);
let name = foreign::link_name(&ni);
foreign::register_foreign_item_fn(ccx, abi, ty, &name, &ni.attrs)
}
hir::ForeignItemStatic(..) => {
foreign::register_static(ccx, &ni)
}
}
}
ref variant => {
ccx.sess().bug(&format!("get_item_val(): unexpected variant: {:?}", variant))
}
};
// All LLVM globals and functions are initially created as external-linkage
// declarations. If `trans_item`/`trans_fn` later turns the declaration
// into a definition, it adjusts the linkage then (using `update_linkage`).
//
// The exception is foreign items, which have their linkage set inside the
// call to `foreign::register_*` above. We don't touch the linkage after
// that (`foreign::trans_foreign_mod` doesn't adjust the linkage like the
// other item translation functions do).
ccx.item_vals().borrow_mut().insert(id, val);
val
}
fn register_method(ccx: &CrateContext,
id: ast::NodeId,
attrs: &[ast::Attribute],
span: Span)
-> ValueRef {
let mty = ccx.tcx().node_id_to_type(id);
let sym = exported_name(ccx, id, mty, &attrs);
if let ty::TyFnDef(_, _, ref f) = mty.sty {
let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
register_fn(ccx, span, sym, id, mty)
} else {
foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id)
};
attributes::from_fn_attrs(ccx, &attrs, llfn);
return llfn;
} else {
ccx.sess().span_bug(span, "expected bare rust function");
}
}
pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
krate: &hir::Crate,
reachable: &NodeSet,

View File

@ -25,15 +25,17 @@
use middle::infer;
use middle::subst;
use middle::subst::{Substs};
use middle::traits;
use rustc::front::map as hir_map;
use trans::adt;
use trans::attributes;
use trans::base;
use trans::base::*;
use trans::build::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
ExprOrMethodCall, FunctionContext, MethodCallKey};
use trans::closure;
use trans::common::{self, Block, Result, NodeIdAndSpan, CrateContext, FunctionContext};
use trans::consts;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
@ -44,7 +46,7 @@
use trans::foreign;
use trans::intrinsic;
use trans::meth;
use trans::monomorphize;
use trans::monomorphize::{self, Instance};
use trans::type_::Type;
use trans::type_of;
use trans::value::Value;
@ -442,9 +444,7 @@ fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
assert_eq!(def_id.krate, LOCAL_CRATE);
let substs = tcx.mk_substs(substs.clone().erase_regions());
let (mut val, fn_ty, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, substs);
let fn_ty = ref_ty.unwrap_or(fn_ty);
let (val, fn_ty) = monomorphize::monomorphic_fn(ccx, def_id, substs);
let fn_ptr_ty = match fn_ty.sty {
ty::TyFnDef(_, _, fty) => {
// Create a fn pointer with the substituted signature.
@ -452,36 +452,72 @@ fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
}
_ => unreachable!("expected fn item type, found {}", fn_ty)
};
if must_cast && ref_ty.is_some() {
let llptrty = type_of::type_of(ccx, fn_ptr_ty);
if llptrty != common::val_ty(val) {
val = consts::ptrcast(val, llptrty);
}
}
assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val));
return immediate_rvalue(val, fn_ptr_ty);
}
// Find the actual function pointer.
let local_node = ccx.tcx().map.as_local_node_id(def_id);
let mut datum = if let Some(node_id) = local_node {
// Type scheme of the function item (may have type params)
let fn_type_scheme = tcx.lookup_item_type(def_id);
let fn_type = match fn_type_scheme.ty.sty {
ty::TyFnDef(_, _, fty) => {
// Create a fn pointer with the normalized signature.
tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
}
_ => unreachable!("expected fn item type, found {}",
fn_type_scheme.ty)
};
// Internal reference.
immediate_rvalue(get_item_val(ccx, node_id), fn_type)
} else {
// External reference.
get_extern_fn(ccx, def_id)
let ty = ccx.tcx().lookup_item_type(def_id).ty;
let fn_ptr_ty = match ty.sty {
ty::TyFnDef(_, _, fty) => {
// Create a fn pointer with the normalized signature.
tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
}
_ => unreachable!("expected fn item type, found {}", ty)
};
let instance = Instance::mono(ccx.tcx(), def_id);
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
return immediate_rvalue(llfn, fn_ptr_ty);
}
let attrs;
let local_id = ccx.tcx().map.as_local_node_id(def_id);
let maybe_node = local_id.and_then(|id| tcx.map.find(id));
let (sym, attrs, local_item) = match maybe_node {
Some(hir_map::NodeItem(&hir::Item {
ref attrs, id, span, node: hir::ItemFn(..), ..
})) |
Some(hir_map::NodeTraitItem(&hir::TraitItem {
ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), ..
})) |
Some(hir_map::NodeImplItem(&hir::ImplItem {
ref attrs, id, span, node: hir::ImplItemKind::Method(..), ..
})) => {
let sym = exported_name(ccx, id, ty, attrs);
if declare::get_defined_value(ccx, &sym).is_some() {
ccx.sess().span_fatal(span,
&format!("symbol `{}` is already defined", sym));
}
(sym, &attrs[..], Some(id))
}
Some(hir_map::NodeForeignItem(&hir::ForeignItem {
ref attrs, name, node: hir::ForeignItemFn(..), ..
})) => {
(foreign::link_name(name, attrs).to_string(), &attrs[..], None)
}
None => {
attrs = ccx.sess().cstore.item_attrs(def_id);
(ccx.sess().cstore.item_symbol(def_id), &attrs[..], None)
}
ref variant => {
ccx.sess().bug(&format!("get_fn: unexpected variant: {:?}", variant))
}
};
let llfn = declare::declare_fn(ccx, &sym, ty);
attributes::from_fn_attrs(ccx, attrs, llfn);
if let Some(id) = local_item {
// FIXME(eddyb) Doubt all extern fn should allow unwinding.
attributes::unwind(llfn, true);
ccx.item_symbols().borrow_mut().insert(id, sym);
}
// This is subtle and surprising, but sometimes we have to bitcast
// the resulting fn pointer. The reason has to do with external
// functions. If you have two crates that both bind the same C
@ -505,15 +541,18 @@ fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
// This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
let llptrty = type_of::type_of(ccx, datum.ty);
if common::val_ty(datum.val) != llptrty {
debug!("trans_fn_ref_with_substs(): casting pointer!");
datum.val = consts::ptrcast(datum.val, llptrty);
let llptrty = type_of::type_of(ccx, fn_ptr_ty);
let llfn = if common::val_ty(llfn) != llptrty {
debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
consts::ptrcast(llfn, llptrty)
} else {
debug!("trans_fn_ref_with_substs(): not casting pointer!");
}
debug!("get_fn: not casting pointer!");
llfn
};
datum
ccx.instances().borrow_mut().insert(instance, llfn);
immediate_rvalue(llfn, fn_ptr_ty)
}
// ______________________________________________________________________

View File

@ -19,7 +19,7 @@
use trans::adt;
use trans::base;
use trans::builder::Builder;
use trans::common::{ExternMap,BuilderRef_res};
use trans::common::BuilderRef_res;
use trans::debuginfo;
use trans::declare;
use trans::glue::DropGlueKind;
@ -90,8 +90,6 @@ pub struct LocalCrateContext<'tcx> {
llmod: ModuleRef,
llcx: ContextRef,
tn: TypeNames,
externs: RefCell<ExternMap>,
item_vals: RefCell<NodeMap<ValueRef>>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
@ -464,8 +462,6 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
llmod: llmod,
llcx: llcx,
tn: TypeNames::new(),
externs: RefCell::new(FnvHashMap()),
item_vals: RefCell::new(NodeMap()),
needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()),
fn_pointer_shims: RefCell::new(FnvHashMap()),
drop_glues: RefCell::new(FnvHashMap()),
@ -616,14 +612,6 @@ pub fn tn<'a>(&'a self) -> &'a TypeNames {
&self.local.tn
}
pub fn externs<'a>(&'a self) -> &'a RefCell<ExternMap> {
&self.local.externs
}
pub fn item_vals<'a>(&'a self) -> &'a RefCell<NodeMap<ValueRef>> {
&self.local.item_vals
}
pub fn export_map<'a>(&'a self) -> &'a ExportMap {
&self.shared.export_map
}

View File

@ -10,7 +10,7 @@
use back::{abi, link};
use llvm::{ValueRef, CallConv, get_param};
use llvm::{ValueRef, get_param};
use llvm;
use middle::weak_lang_items;
use trans::attributes;
@ -37,12 +37,10 @@
use libc::c_uint;
use syntax::abi::Abi;
use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token::{InternedString, special_idents};
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use rustc_front::print::pprust;
use rustc_front::hir;
///////////////////////////////////////////////////////////////////////////
@ -112,56 +110,6 @@ pub fn register_static(ccx: &CrateContext,
return c;
}
// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
pub fn get_extern_fn(ccx: &CrateContext,
externs: &mut ExternMap,
name: &str,
cc: llvm::CallConv,
ty: Type,
output: Ty)
-> ValueRef {
match externs.get(name) {
Some(n) => return *n,
None => {}
}
let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output));
externs.insert(name.to_string(), f);
f
}
/// Registers a foreign function found in a library. Just adds a LLVM global.
pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
abi: Abi, fty: Ty<'tcx>,
name: &str,
attrs: &[ast::Attribute])-> ValueRef {
debug!("register_foreign_item_fn(abi={:?}, \
ty={:?}, \
name={})",
abi,
fty,
name);
let cc = llvm_calling_convention(ccx, abi);
// Register the function as a C extern fn
let tys = foreign_types_for_fn_ty(ccx, fty);
// Make sure the calling convention is right for variadic functions
// (should've been caught if not in typeck)
if tys.fn_sig.variadic {
assert!(cc == llvm::CCallConv);
}
// Create the LLVM value for the C extern fn
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty);
attributes::unwind(llfn, false);
add_argument_attributes(&tys, llfn);
attributes::from_fn_attrs(ccx, attrs, llfn);
llfn
}
/// Prepares a call to a native function. This requires adapting
/// from the Rust argument passing rules to the native rules.
///
@ -414,49 +362,6 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// inline the one into the other. Of course we could just generate the
// correct code in the first place, but this is much simpler.
pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>,
name: &str)
-> ValueRef {
let tys = foreign_types_for_fn_ty(ccx, t);
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let cconv = match t.sty {
ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => {
llvm_calling_convention(ccx, fn_ty.abi)
}
_ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
};
let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty,
ty::FnConverging(ccx.tcx().mk_nil()));
add_argument_attributes(&tys, llfn);
debug!("decl_rust_fn_with_foreign_abi(llfn_ty={:?}, llfn={:?})",
llfn_ty, Value(llfn));
llfn
}
pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId)
-> ValueRef {
let _icx = push_ctxt("foreign::register_foreign_fn");
let t = ccx.tcx().node_id_to_type(node_id);
let cconv = match t.sty {
ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => {
llvm_calling_convention(ccx, fn_ty.abi)
}
_ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
};
let tys = foreign_types_for_fn_ty(ccx, t);
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
add_argument_attributes(&tys, llfn);
debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={:?}, llfn={:?})",
node_id, llfn_ty, Value(llfn));
llfn
}
pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
decl: &hir::FnDecl,
body: &hir::Block,

View File

@ -17,7 +17,7 @@
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::*;
@ -31,7 +31,6 @@
use rustc_front::hir;
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr;
use syntax::errors;
@ -41,14 +40,11 @@
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 instance = Instance {
@ -72,25 +68,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("monomorphic_fn({:?})", instance);
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)
});
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);
}
}
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
let depth;
@ -132,155 +109,79 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
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);
ccx.instances().borrow_mut().insert(instance, lldecl);
let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
if is_first {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
}
// 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, _, _, abi, _, ref body), ..
}) |
hir_map::NodeTraitItem(&hir::TraitItem {
ref attrs, node: hir::MethodTraitItem(
hir::MethodSig { abi, ref decl, .. }, Some(ref body)), ..
}) |
hir_map::NodeImplItem(&hir::ImplItem {
ref attrs, node: hir::ImplItemKind::Method(
hir::MethodSig { abi, ref decl, .. }, ref body), ..
}) => {
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
attributes::from_fn_attrs(ccx, attrs, 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
};
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 is_first = !ccx.available_monomorphizations().borrow().contains(&s);
if is_first {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
}
}
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))
let trans_everywhere = attr::requests_inline(attrs);
if trans_everywhere && !is_first {
llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage);
}
if trans_everywhere || is_first {
if abi != Abi::Rust && abi != Abi::RustCall {
foreign::trans_rust_fn_with_foreign_abi(
ccx, decl, body, attrs, lldecl, psubsts, fn_node_id,
Some(&hash));
} else {
trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id, attrs);
}
}
}
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
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)
}
_ => {
ccx.sess().bug(&format!("can't monomorphize a {:?}",
map_node))
}
}
}
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(Copy, Clone, PartialEq, Eq, Hash, Debug)]