diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 53bbff50ecf..d177bb396c9 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> { } } -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, diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 06e3cba6be1..65724405db1 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -25,15 +25,17 @@ use middle::def_id::DefId; 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::inline; 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 get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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 get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } _ => 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 get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // 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) } // ______________________________________________________________________ diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index b558dd70ab8..b38050d2467 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -19,7 +19,7 @@ use rustc::mir::mir_map::MirMap; 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, - item_vals: RefCell>, needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, ValueRef>>, @@ -464,8 +462,6 @@ impl<'tcx> LocalCrateContext<'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 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.tn } - pub fn externs<'a>(&'a self) -> &'a RefCell { - &self.local.externs - } - - pub fn item_vals<'a>(&'a self) -> &'a RefCell> { - &self.local.item_vals - } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { &self.shared.export_map } diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 27d2c07893b..0c8ac32ecc1 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -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 std::iter::once; 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, diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index b3be7c858b5..fcbf0bdf790 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,7 +17,7 @@ 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::*; @@ -31,7 +31,6 @@ use rustc::util::ppaux; use rustc_front::hir; use syntax::abi::Abi; -use syntax::ast; use syntax::attr; use syntax::errors; @@ -41,14 +40,11 @@ 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 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)]