trans: Condense the fn instantiation logic into callee.
This commit is contained in:
parent
b05556e06d
commit
cdfad40735
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
|
@ -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<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 @@ 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<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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user