summaryrefslogtreecommitdiff
path: root/src/librustc_trans/trans/callee.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/callee.rs')
-rw-r--r--src/librustc_trans/trans/callee.rs852
1 files changed, 448 insertions, 404 deletions
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 05e5ac808d0..17d08cd6c2f 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -25,15 +25,19 @@ 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::abi::{Abi, FnType};
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, CrateContext, FunctionContext};
+use trans::common::{C_uint, C_undef};
use trans::consts;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
@@ -41,37 +45,40 @@ use trans::declare;
use trans::expr;
use trans::glue;
use trans::inline;
-use trans::foreign;
use trans::intrinsic;
+use trans::machine::{llalign_of_min, llsize_of_store};
use trans::meth;
-use trans::monomorphize;
+use trans::monomorphize::{self, Instance};
use trans::type_::Type;
use trans::type_of;
+use trans::value::Value;
use trans::Disr;
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_front::hir;
-use syntax::abi::Abi;
-use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::errors;
use syntax::ptr::P;
-pub enum CalleeData<'tcx> {
+use std::cmp;
+
+#[derive(Debug)]
+pub enum CalleeData {
/// Constructor for enum variant/tuple-like-struct.
NamedTupleConstructor(Disr),
/// Function pointer.
Fn(ValueRef),
- Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>),
+ Intrinsic,
/// Trait object found in the vtable at that index.
Virtual(usize)
}
+#[derive(Debug)]
pub struct Callee<'tcx> {
- pub data: CalleeData<'tcx>,
+ pub data: CalleeData,
pub ty: Ty<'tcx>
}
@@ -96,26 +103,19 @@ impl<'tcx> Callee<'tcx> {
pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
- let ty = bcx.fcx.monomorphize(&method.ty);
- Callee::def(bcx.ccx(), method.def_id, substs, ty)
+ Callee::def(bcx.ccx(), method.def_id, substs)
}
/// Function or method definition.
pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
- substs: &'tcx subst::Substs<'tcx>,
- ty: Ty<'tcx>)
+ substs: &'tcx subst::Substs<'tcx>)
-> Callee<'tcx> {
let tcx = ccx.tcx();
if substs.self_ty().is_some() {
// Only trait methods can have a Self parameter.
- let method_item = tcx.impl_or_trait_item(def_id);
- let trait_id = method_item.container().id();
- let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
- let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref);
- return meth::callee_for_trait_impl(ccx, def_id, substs,
- trait_id, ty, vtbl);
+ return Callee::trait_method(ccx, def_id, substs);
}
let maybe_node_id = inline::get_local_instance(ccx, def_id)
@@ -123,34 +123,112 @@ impl<'tcx> Callee<'tcx> {
let maybe_ast_node = maybe_node_id.and_then(|node_id| {
tcx.map.find(node_id)
});
- match maybe_ast_node {
+
+ let data = match maybe_ast_node {
Some(hir_map::NodeStructCtor(_)) => {
- return Callee {
- data: NamedTupleConstructor(Disr(0)),
- ty: ty
- };
+ NamedTupleConstructor(Disr(0))
}
Some(hir_map::NodeVariant(_)) => {
let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
- assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
+ NamedTupleConstructor(Disr::from(vinfo.disr_val))
+ }
+ Some(hir_map::NodeForeignItem(fi)) if {
+ let abi = tcx.map.get_foreign_abi(fi.id);
+ abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
+ } => Intrinsic,
- return Callee {
- data: NamedTupleConstructor(Disr::from(vinfo.disr_val)),
- ty: ty
+ _ => return Callee::ptr(get_fn(ccx, def_id, substs))
+ };
+
+ Callee {
+ data: data,
+ ty: def_ty(tcx, def_id, substs)
+ }
+ }
+
+ /// Trait method, which has to be resolved to an impl method.
+ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx subst::Substs<'tcx>)
+ -> Callee<'tcx> {
+ let tcx = ccx.tcx();
+
+ let method_item = tcx.impl_or_trait_item(def_id);
+ let trait_id = method_item.container().id();
+ let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
+ match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
+ traits::VtableImpl(vtable_impl) => {
+ let impl_did = vtable_impl.impl_def_id;
+ let mname = tcx.item_name(def_id);
+ // create a concatenated set of substitutions which includes
+ // those from the impl and those from the method:
+ let impl_substs = vtable_impl.substs.with_method_from(&substs);
+ let substs = tcx.mk_substs(impl_substs);
+ let mth = meth::get_impl_method(tcx, impl_did, substs, mname);
+
+ // Translate the function, bypassing Callee::def.
+ // That is because default methods have the same ID as the
+ // trait method used to look up the impl method that ended
+ // up here, so calling Callee::def would infinitely recurse.
+ Callee::ptr(get_fn(ccx, mth.method.def_id, mth.substs))
+ }
+ traits::VtableClosure(vtable_closure) => {
+ // The substitutions should have no type parameters remaining
+ // after passing through fulfill_obligation
+ let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
+ let llfn = closure::trans_closure_method(ccx,
+ vtable_closure.closure_def_id,
+ vtable_closure.substs,
+ trait_closure_kind);
+
+ let method_ty = def_ty(tcx, def_id, substs);
+ let fn_ptr_ty = match method_ty.sty {
+ ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+ _ => unreachable!("expected fn item type, found {}",
+ method_ty)
};
+ Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
}
- Some(hir_map::NodeForeignItem(fi)) => {
- let abi = tcx.map.get_foreign_abi(fi.id);
- if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- return Callee {
- data: Intrinsic(fi.id, substs),
- ty: ty
- };
+ traits::VtableFnPointer(fn_ty) => {
+ let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
+ let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
+
+ let method_ty = def_ty(tcx, def_id, substs);
+ let fn_ptr_ty = match method_ty.sty {
+ ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+ _ => unreachable!("expected fn item type, found {}",
+ method_ty)
+ };
+ Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
+ }
+ traits::VtableObject(ref data) => {
+ Callee {
+ data: Virtual(traits::get_vtable_index_of_object_method(
+ tcx, data, def_id)),
+ ty: def_ty(tcx, def_id, substs)
}
}
- _ => {}
+ vtable => {
+ unreachable!("resolved vtable bad vtable {:?} in trans", vtable);
+ }
+ }
+ }
+
+ /// Get the abi::FnType for a direct call. Mainly deals with the fact
+ /// that a Virtual call doesn't take the vtable, like its shim does.
+ /// The extra argument types are for variadic (extern "C") functions.
+ pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
+ extra_args: &[Ty<'tcx>]) -> FnType {
+ let abi = self.ty.fn_abi();
+ let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
+ let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
+ let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
+ if let Virtual(_) = self.data {
+ // Don't pass the vtable, it's not an argument of the virtual fn.
+ fn_ty.args[1].ignore();
}
- Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs))
+ fn_ty.adjust_for_abi(ccx, abi, &sig);
+ fn_ty
}
/// This behemoth of a function translates function calls. Unfortunately, in
@@ -175,51 +253,36 @@ impl<'tcx> Callee<'tcx> {
/// Turn the callee into a function pointer.
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
-> Datum<'tcx, Rvalue> {
+ let fn_ptr_ty = match self.ty.sty {
+ ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
+ _ => self.ty
+ };
match self.data {
Fn(llfn) => {
- let fn_ptr_ty = match self.ty.sty {
- ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
- _ => self.ty
- };
immediate_rvalue(llfn, fn_ptr_ty)
}
- Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx),
+ Virtual(idx) => {
+ let llfn = meth::trans_object_shim(ccx, self.ty, idx);
+ immediate_rvalue(llfn, fn_ptr_ty)
+ }
NamedTupleConstructor(_) => match self.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
- return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs);
+ return get_fn(ccx, def_id, substs);
}
_ => unreachable!("expected fn item type, found {}", self.ty)
},
- Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty)
+ Intrinsic => unreachable!("intrinsic {} getting reified", self.ty)
}
}
}
-/// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
-/// pointer. This may require monomorphization or inlining.
-pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- def_id: DefId,
- node: ExprOrMethodCall,
- param_substs: &'tcx subst::Substs<'tcx>)
- -> Datum<'tcx, Rvalue> {
- let _icx = push_ctxt("trans_fn_ref");
-
- let substs = common::node_id_substs(ccx, node, param_substs);
- debug!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
- def_id,
- node,
- substs);
- let ref_ty = match node {
- ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs),
- ExprId(id) => ccx.tcx().node_id_to_type(id),
- MethodCallKey(method_call) => {
- ccx.tcx().tables.borrow().method_map[&method_call].ty
- }
- };
- let ref_ty = monomorphize::apply_param_substs(ccx.tcx(),
- param_substs,
- &ref_ty);
- trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs)
+/// Given a DefId and some Substs, produces the monomorphic item type.
+fn def_ty<'tcx>(tcx: &TyCtxt<'tcx>,
+ def_id: DefId,
+ substs: &'tcx subst::Substs<'tcx>)
+ -> Ty<'tcx> {
+ let ty = tcx.lookup_item_type(def_id).ty;
+ monomorphize::apply_param_substs(tcx, substs, &ty)
}
/// Translates an adapter that implements the `Fn` trait for a fn
@@ -251,6 +314,21 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
ty::ClosureKind::FnOnce => false,
};
+
+ let llfnpointer = match bare_fn_ty.sty {
+ ty::TyFnDef(def_id, substs, _) => {
+ // Function definitions have to be turned into a pointer.
+ let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val;
+ if !is_by_ref {
+ // A by-value fn item is ignored, so the shim has
+ // the same signature as the original function.
+ return llfn;
+ }
+ Some(llfn)
+ }
+ _ => None
+ };
+
let bare_fn_ty_maybe_ref = if is_by_ref {
tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
} else {
@@ -285,58 +363,48 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
let sig = tcx.erase_late_bound_regions(sig);
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
+ let sig = ty::FnSig {
+ inputs: vec![bare_fn_ty_maybe_ref,
+ tuple_input_ty],
+ output: sig.output,
+ variadic: false
+ };
+ let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: Abi::RustCall,
- sig: ty::Binder(ty::FnSig {
- inputs: vec![bare_fn_ty_maybe_ref,
- tuple_input_ty],
- output: sig.output,
- variadic: false
- })
+ sig: ty::Binder(sig)
});
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
"fn_pointer_shim");
- let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty);
+ let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
//
let empty_substs = tcx.mk_substs(Substs::trans_empty());
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
- fcx = new_fn_ctxt(ccx,
- llfn,
- ast::DUMMY_NODE_ID,
- false,
- sig.output,
- empty_substs,
- None,
- &block_arena);
- let mut bcx = init_function(&fcx, false, sig.output);
+ fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
+ let mut bcx = fcx.init(false, None);
let llargs = get_params(fcx.llfn);
- let self_idx = fcx.arg_offset();
- let llfnpointer = match bare_fn_ty.sty {
- ty::TyFnDef(def_id, substs, _) => {
- // Function definitions have to be turned into a pointer.
- Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val
- }
-
+ let self_idx = fcx.fn_ty.ret.is_indirect() as usize;
+ let llfnpointer = llfnpointer.unwrap_or_else(|| {
// the first argument (`self`) will be ptr to the fn pointer
- _ => if is_by_ref {
+ if is_by_ref {
Load(bcx, llargs[self_idx])
} else {
llargs[self_idx]
}
- };
+ });
assert!(!fcx.needs_ret_allocas);
let dest = fcx.llretslotptr.get().map(|_|
- expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
+ expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
);
let callee = Callee {
@@ -345,7 +413,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
};
bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
- finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
+ fcx.finish(bcx, DebugLoc::None);
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
@@ -359,25 +427,14 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
///
/// - `ccx`: the crate context
/// - `def_id`: def id of the fn or method item being referenced
-/// - `node`: node id of the reference to the fn/method, if applicable.
-/// This parameter may be zero; but, if so, the resulting value may not
-/// have the right type, so it must be cast before being used.
-/// - `ref_ty`: monotype of the reference to the fn/method, if applicable.
-/// This parameter may be None; but, if so, the resulting value may not
-/// have the right type, so it must be cast before being used.
/// - `substs`: values for each of the fn/method's parameters
-pub fn trans_fn_ref_with_substs<'a, 'tcx>(
- ccx: &CrateContext<'a, 'tcx>,
- def_id: DefId,
- ref_ty: Option<Ty<'tcx>>,
- substs: &'tcx subst::Substs<'tcx>)
- -> Datum<'tcx, Rvalue>
-{
- let _icx = push_ctxt("trans_fn_ref_with_substs");
+fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx subst::Substs<'tcx>)
+ -> Datum<'tcx, Rvalue> {
let tcx = ccx.tcx();
- debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})",
- def_id, ref_ty, substs);
+ debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
assert!(!substs.types.needs_infer());
assert!(!substs.types.has_escaping_regions());
@@ -407,7 +464,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
let must_monomorphise =
!substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
- debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
+ debug!("get_fn({:?}) must_monomorphise: {}",
def_id, must_monomorphise);
// Create a monomorphic version of generic functions
@@ -416,9 +473,7 @@ pub fn trans_fn_ref_with_substs<'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.
@@ -426,36 +481,72 @@ pub fn trans_fn_ref_with_substs<'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))
+ 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));
}
- _ => 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)
+ (sym, &attrs[..], Some(id))
+ }
+
+ Some(hir_map::NodeForeignItem(&hir::ForeignItem {
+ ref attrs, name, node: hir::ForeignItemFn(..), ..
+ })) => {
+ (imported_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
@@ -479,30 +570,23 @@ pub fn trans_fn_ref_with_substs<'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
+ };
+
+ ccx.instances().borrow_mut().insert(instance, llfn);
- datum
+ immediate_rvalue(llfn, fn_ptr_ty)
}
// ______________________________________________________________________
// Translating calls
-pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- did: DefId,
- args: &[ValueRef],
- dest: Option<expr::Dest>,
- debug_loc: DebugLoc)
- -> Result<'blk, 'tcx> {
- let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs);
- Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest)
-}
-
fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc,
callee: Callee<'tcx>,
@@ -519,33 +603,29 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let fcx = bcx.fcx;
let ccx = fcx.ccx;
- let (abi, ret_ty) = match callee.ty.sty {
- ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
- let sig = bcx.tcx().erase_late_bound_regions(&f.sig);
- let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
- (f.abi, sig.output)
+ let abi = callee.ty.fn_abi();
+ let sig = callee.ty.fn_sig();
+ let output = bcx.tcx().erase_late_bound_regions(&sig.output());
+ let output = infer::normalize_associated_type(bcx.tcx(), &output);
+
+ let extra_args = match args {
+ ArgExprs(args) if abi != Abi::RustCall => {
+ args[sig.0.inputs.len()..].iter().map(|expr| {
+ common::expr_ty_adjusted(bcx, expr)
+ }).collect()
}
- _ => panic!("expected fn item or ptr in Callee::call")
+ _ => vec![]
};
+ let fn_ty = callee.direct_fn_type(ccx, &extra_args);
- match callee.data {
- Intrinsic(node, substs) => {
+ let mut callee = match callee.data {
+ Intrinsic => {
assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
assert!(dest.is_some());
- let call_info = match debug_loc {
- DebugLoc::At(id, span) => NodeIdAndSpan { id: id, span: span },
- DebugLoc::None => {
- bcx.sess().bug("No call info for intrinsic call?")
- }
- };
-
- let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
- return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
- arg_cleanup_scope, args,
- dest.unwrap(),
- substs,
- call_info);
+ return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
+ args, dest.unwrap(),
+ debug_loc);
}
NamedTupleConstructor(disr) => {
assert!(dest.is_some());
@@ -557,34 +637,25 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
dest.unwrap(),
debug_loc);
}
- _ => {}
- }
-
- // Intrinsics should not become actual functions.
- // We trans them in place in `trans_intrinsic_call`
- assert!(abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic);
-
- let is_rust_fn = abi == Abi::Rust || abi == Abi::RustCall;
+ f => f
+ };
// Generate a location to store the result. If the user does
// not care about the result, just make a stack slot.
let opt_llretslot = dest.and_then(|dest| match dest {
expr::SaveIn(dst) => Some(dst),
expr::Ignore => {
- let ret_ty = match ret_ty {
- ty::FnConverging(ret_ty) => ret_ty,
- ty::FnDiverging => ccx.tcx().mk_nil()
+ let needs_drop = || match output {
+ ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
+ ty::FnDiverging => false
};
- if !is_rust_fn ||
- type_of::return_uses_outptr(ccx, ret_ty) ||
- bcx.fcx.type_needs_drop(ret_ty) {
+ if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
- if common::type_is_zero_size(ccx, ret_ty) {
- let llty = type_of::type_of(ccx, ret_ty);
- Some(common::C_undef(llty.ptr_to()))
+ if fn_ty.ret.is_ignore() {
+ Some(C_undef(fn_ty.ret.original_ty.ptr_to()))
} else {
- let llresult = alloc_ty(bcx, ret_ty, "__llret");
+ let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
call_lifetime_start(bcx, llresult);
Some(llresult)
}
@@ -594,128 +665,98 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
});
- let mut llresult = unsafe {
- llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
- };
+ // If there no destination, return must be direct, with no cast.
+ if opt_llretslot.is_none() {
+ assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
+ }
- let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
+ let mut llargs = Vec::new();
- // The code below invokes the function, using either the Rust
- // conventions (if it is a rust fn) or the native conventions
- // (otherwise). The important part is that, when all is said
- // and done, either the return value of the function will have been
- // written in opt_llretslot (if it is Some) or `llresult` will be
- // set appropriately (otherwise).
- if is_rust_fn {
- let mut llargs = Vec::new();
-
- if let (ty::FnConverging(ret_ty), Some(mut llretslot)) = (ret_ty, opt_llretslot) {
- if type_of::return_uses_outptr(ccx, ret_ty) {
- let llformal_ret_ty = type_of::type_of(ccx, ret_ty).ptr_to();
- let llret_ty = common::val_ty(llretslot);
- if llformal_ret_ty != llret_ty {
- // this could happen due to e.g. subtyping
- debug!("casting actual return type ({}) to match formal ({})",
- bcx.llty_str(llret_ty), bcx.llty_str(llformal_ret_ty));
- llretslot = PointerCast(bcx, llretslot, llformal_ret_ty);
- }
- llargs.push(llretslot);
- }
+ if fn_ty.ret.is_indirect() {
+ let mut llretslot = opt_llretslot.unwrap();
+ if let Some(ty) = fn_ty.ret.cast {
+ llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
}
+ llargs.push(llretslot);
+ }
- let arg_start = llargs.len();
-
- // Push the arguments.
- bcx = trans_args(bcx,
- args,
- callee.ty,
- &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope),
- abi);
+ let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
+ bcx = trans_args(bcx, abi, &fn_ty, &mut callee, args, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope));
+ fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
- fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
+ let llfn = match callee {
+ Fn(f) => f,
+ _ => unreachable!("expected fn pointer callee, found {:?}", callee)
+ };
- let datum = match callee.data {
- Fn(f) => immediate_rvalue(f, callee.ty),
- Virtual(idx) => {
- // The data and vtable pointers were split by trans_arg_datum.
- let vtable = llargs.remove(arg_start + 1);
- meth::get_virtual_method(bcx, vtable, idx, callee.ty)
- }
- _ => unreachable!()
- };
+ let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
+ if !bcx.unreachable.get() {
+ fn_ty.apply_attrs_callsite(llret);
+ }
- // Invoke the actual rust fn and update bcx/llresult.
- let (llret, b) = base::invoke(bcx,
- datum.val,
- &llargs[..],
- datum.ty,
- debug_loc);
- bcx = b;
- llresult = llret;
-
- // If the Rust convention for this type is return via
- // the return value, copy it into llretslot.
- match (opt_llretslot, ret_ty) {
- (Some(llretslot), ty::FnConverging(ret_ty)) => {
- if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
- !common::type_is_zero_size(bcx.ccx(), ret_ty)
- {
- store_ty(bcx, llret, llretslot, ret_ty)
- }
+ // If the function we just called does not use an outpointer,
+ // store the result into the rust outpointer. Cast the outpointer
+ // type to match because some ABIs will use a different type than
+ // the Rust type. e.g., a {u32,u32} struct could be returned as
+ // u64.
+ if !fn_ty.ret.is_ignore() && !fn_ty.ret.is_indirect() {
+ if let Some(llforeign_ret_ty) = fn_ty.ret.cast {
+ let llrust_ret_ty = fn_ty.ret.original_ty;
+ let llretslot = opt_llretslot.unwrap();
+
+ // The actual return type is a struct, but the ABI
+ // adaptation code has cast it into some scalar type. The
+ // code that follows is the only reliable way I have
+ // found to do a transform like i64 -> {i32,i32}.
+ // Basically we dump the data onto the stack then memcpy it.
+ //
+ // Other approaches I tried:
+ // - Casting rust ret pointer to the foreign type and using Store
+ // is (a) unsafe if size of foreign type > size of rust type and
+ // (b) runs afoul of strict aliasing rules, yielding invalid
+ // assembly under -O (specifically, the store gets removed).
+ // - Truncating foreign type to correct integral type and then
+ // bitcasting to the struct type yields invalid cast errors.
+ let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
+ base::call_lifetime_start(bcx, llscratch);
+ Store(bcx, llret, llscratch);
+ let llscratch_i8 = PointerCast(bcx, llscratch, Type::i8(ccx).ptr_to());
+ let llretptr_i8 = PointerCast(bcx, llretslot, Type::i8(ccx).ptr_to());
+ let llrust_size = llsize_of_store(ccx, llrust_ret_ty);
+ let llforeign_align = llalign_of_min(ccx, llforeign_ret_ty);
+ let llrust_align = llalign_of_min(ccx, llrust_ret_ty);
+ let llalign = cmp::min(llforeign_align, llrust_align);
+ debug!("llrust_size={}", llrust_size);
+
+ if !bcx.unreachable.get() {
+ base::call_memcpy(&B(bcx), llretptr_i8, llscratch_i8,
+ C_uint(ccx, llrust_size), llalign as u32);
}
- (_, _) => {}
+ base::call_lifetime_end(bcx, llscratch);
+ } else if let Some(llretslot) = opt_llretslot {
+ base::store_ty(bcx, llret, llretslot, output.unwrap());
}
- } else {
- // Lang items are the only case where dest is None, and
- // they are always Rust fns.
- assert!(dest.is_some());
-
- let mut llargs = Vec::new();
- let (llfn, arg_tys) = match (callee.data, &args) {
- (Fn(f), &ArgExprs(a)) => {
- (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect())
- }
- _ => panic!("expected fn ptr and arg exprs.")
- };
- bcx = trans_args(bcx,
- args,
- callee.ty,
- &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope),
- abi);
- fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
-
- bcx = foreign::trans_native_call(bcx,
- callee.ty,
- llfn,
- opt_llretslot.unwrap(),
- &llargs[..],
- arg_tys,
- debug_loc);
}
fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
// If the caller doesn't care about the result of this fn call,
// drop the temporary slot we made.
- match (dest, opt_llretslot, ret_ty) {
+ match (dest, opt_llretslot, output) {
(Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
// drop the value if it is not being saved.
- bcx = glue::drop_ty(bcx,
- llretslot,
- ret_ty,
- debug_loc);
+ bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc);
call_lifetime_end(bcx, llretslot);
}
_ => {}
}
- if ret_ty == ty::FnDiverging {
+ if output == ty::FnDiverging {
Unreachable(bcx);
}
- Result::new(bcx, llresult)
+ Result::new(bcx, llret)
}
pub enum CallArgs<'a, 'tcx> {
@@ -741,20 +782,19 @@ pub enum CallArgs<'a, 'tcx> {
fn trans_args_under_call_abi<'blk, 'tcx>(
mut bcx: Block<'blk, 'tcx>,
arg_exprs: &[P<hir::Expr>],
- fn_ty: Ty<'tcx>,
+ callee: &mut CalleeData,
+ fn_ty: &FnType,
llargs: &mut Vec<ValueRef>,
arg_cleanup_scope: cleanup::ScopeId)
-> Block<'blk, 'tcx>
{
- let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
- let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
- let args = sig.inputs;
+ let mut arg_idx = 0;
// Translate the `self` argument first.
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
bcx = trans_arg_datum(bcx,
- args[0],
arg_datum,
+ callee, fn_ty, &mut arg_idx,
arg_cleanup_scope,
llargs);
@@ -781,8 +821,8 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
}).to_expr_datum();
bcx = trans_arg_datum(bcx,
- field_type,
arg_datum,
+ callee, fn_ty, &mut arg_idx,
arg_cleanup_scope,
llargs);
}
@@ -796,64 +836,20 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
bcx
}
-fn trans_overloaded_call_args<'blk, 'tcx>(
- mut bcx: Block<'blk, 'tcx>,
- arg_exprs: Vec<&hir::Expr>,
- fn_ty: Ty<'tcx>,
- llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId)
- -> Block<'blk, 'tcx> {
- // Translate the `self` argument first.
- let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
- let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
- let arg_tys = sig.inputs;
-
- let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
- bcx = trans_arg_datum(bcx,
- arg_tys[0],
- arg_datum,
- arg_cleanup_scope,
- llargs);
-
- // Now untuple the rest of the arguments.
- let tuple_type = arg_tys[1];
- match tuple_type.sty {
- ty::TyTuple(ref field_types) => {
- for (i, &field_type) in field_types.iter().enumerate() {
- let arg_datum =
- unpack_datum!(bcx, expr::trans(bcx, arg_exprs[i + 1]));
- bcx = trans_arg_datum(bcx,
- field_type,
- arg_datum,
- arg_cleanup_scope,
- llargs);
- }
- }
- _ => {
- bcx.sess().span_bug(arg_exprs[0].span,
- "argument to `.call()` wasn't a tuple?!")
- }
- };
-
- bcx
-}
-
-pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
+pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ abi: Abi,
+ fn_ty: &FnType,
+ callee: &mut CalleeData,
args: CallArgs<'a, 'tcx>,
- fn_ty: Ty<'tcx>,
llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId,
- abi: Abi)
+ arg_cleanup_scope: cleanup::ScopeId)
-> Block<'blk, 'tcx> {
debug!("trans_args(abi={})", abi);
let _icx = push_ctxt("trans_args");
- let sig = cx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
- let sig = infer::normalize_associated_type(cx.tcx(), &sig);
- let arg_tys = sig.inputs;
- let variadic = sig.variadic;
- let mut bcx = cx;
+ let mut bcx = bcx;
+ let mut arg_idx = 0;
// First we figure out the caller's view of the types of the arguments.
// This will be needed if this is a generic call, because the callee has
@@ -863,79 +859,90 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
if abi == Abi::RustCall {
// This is only used for direct calls to the `call`,
// `call_mut` or `call_once` functions.
- return trans_args_under_call_abi(cx,
- arg_exprs,
- fn_ty,
+ return trans_args_under_call_abi(bcx,
+ arg_exprs, callee, fn_ty,
llargs,
arg_cleanup_scope)
}
- let num_formal_args = arg_tys.len();
- for (i, arg_expr) in arg_exprs.iter().enumerate() {
- let arg_ty = if i >= num_formal_args {
- assert!(variadic);
- common::expr_ty_adjusted(cx, &arg_expr)
- } else {
- arg_tys[i]
- };
-
+ for arg_expr in arg_exprs {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
- bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
+ bcx = trans_arg_datum(bcx,
+ arg_datum,
+ callee, fn_ty, &mut arg_idx,
arg_cleanup_scope,
llargs);
}
}
ArgOverloadedCall(arg_exprs) => {
- return trans_overloaded_call_args(cx,
- arg_exprs,
- fn_ty,
- llargs,
- arg_cleanup_scope)
+ for expr in arg_exprs {
+ let arg_datum =
+ unpack_datum!(bcx, expr::trans(bcx, expr));
+ bcx = trans_arg_datum(bcx,
+ arg_datum,
+ callee, fn_ty, &mut arg_idx,
+ arg_cleanup_scope,
+ llargs);
+ }
}
ArgOverloadedOp(lhs, rhs) => {
- assert!(!variadic);
-
- bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
+ bcx = trans_arg_datum(bcx, lhs,
+ callee, fn_ty, &mut arg_idx,
arg_cleanup_scope,
llargs);
if let Some(rhs) = rhs {
- assert_eq!(arg_tys.len(), 2);
- bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
+ bcx = trans_arg_datum(bcx, rhs,
+ callee, fn_ty, &mut arg_idx,
arg_cleanup_scope,
llargs);
- } else {
- assert_eq!(arg_tys.len(), 1);
}
}
ArgVals(vs) => {
- llargs.extend_from_slice(vs);
+ match *callee {
+ Virtual(idx) => {
+ llargs.push(vs[0]);
+
+ let fn_ptr = meth::get_virtual_method(bcx, vs[1], idx);
+ let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+ *callee = Fn(PointerCast(bcx, fn_ptr, llty));
+ llargs.extend_from_slice(&vs[2..]);
+ }
+ _ => llargs.extend_from_slice(vs)
+ }
}
}
bcx
}
-pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- formal_arg_ty: Ty<'tcx>,
- arg_datum: Datum<'tcx, Expr>,
- arg_cleanup_scope: cleanup::ScopeId,
- llargs: &mut Vec<ValueRef>)
- -> Block<'blk, 'tcx> {
+fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ arg_datum: Datum<'tcx, Expr>,
+ callee: &mut CalleeData,
+ fn_ty: &FnType,
+ next_idx: &mut usize,
+ arg_cleanup_scope: cleanup::ScopeId,
+ llargs: &mut Vec<ValueRef>)
+ -> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_arg_datum");
let mut bcx = bcx;
- let ccx = bcx.ccx();
- debug!("trans_arg_datum({:?})",
- formal_arg_ty);
+ debug!("trans_arg_datum({:?})", arg_datum);
- let arg_datum_ty = arg_datum.ty;
+ let arg = &fn_ty.args[*next_idx];
+ *next_idx += 1;
+
+ // Fill padding with undef value, where applicable.
+ if let Some(ty) = arg.pad {
+ llargs.push(C_undef(ty));
+ }
- debug!(" arg datum: {}", arg_datum.to_string(bcx.ccx()));
+ // Determine whether we want a by-ref datum even if not appropriate.
+ let want_by_ref = arg.is_indirect() || arg.cast.is_some();
- let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
- !bcx.fcx.type_needs_drop(arg_datum_ty) {
- arg_datum.val
+ let fat_ptr = common::type_is_fat_ptr(bcx.tcx(), arg_datum.ty);
+ let (by_ref, val) = if fat_ptr && !bcx.fcx.type_needs_drop(arg_datum.ty) {
+ (true, arg_datum.val)
} else {
// Make this an rvalue, since we are going to be
// passing ownership.
@@ -944,33 +951,70 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Now that arg_datum is owned, get it into the appropriate
// mode (ref vs value).
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_appropriate_datum(bcx));
+ let arg_datum = unpack_datum!(bcx, if want_by_ref {
+ arg_datum.to_ref_datum(bcx)
+ } else {
+ arg_datum.to_appropriate_datum(bcx)
+ });
// Technically, ownership of val passes to the callee.
// However, we must cleanup should we panic before the
// callee is actually invoked.
- arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)
+ (arg_datum.kind.is_by_ref(),
+ arg_datum.add_clean(bcx.fcx, arg_cleanup_scope))
};
- if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
- // this could happen due to e.g. subtyping
- let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
- debug!("casting actual type ({}) to match formal ({})",
- bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
- debug!("Rust types: {:?}; {:?}", arg_datum_ty,
- formal_arg_ty);
- val = PointerCast(bcx, val, llformal_arg_ty);
+ if arg.is_ignore() {
+ return bcx;
}
- debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
+ debug!("--- trans_arg_datum passing {:?}", Value(val));
- if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
+ if fat_ptr {
+ // Fat pointers should be passed without any transformations.
+ assert!(!arg.is_indirect() && arg.cast.is_none());
llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
- llargs.push(Load(bcx, expr::get_meta(bcx, val)));
- } else {
- llargs.push(val);
+
+ let info_arg = &fn_ty.args[*next_idx];
+ *next_idx += 1;
+ assert!(!info_arg.is_indirect() && info_arg.cast.is_none());
+ let info = Load(bcx, expr::get_meta(bcx, val));
+
+ if let Virtual(idx) = *callee {
+ // We have to grab the fn pointer from the vtable when
+ // handling the first argument, ensure that here.
+ assert_eq!(*next_idx, 2);
+ assert!(info_arg.is_ignore());
+ let fn_ptr = meth::get_virtual_method(bcx, info, idx);
+ let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+ *callee = Fn(PointerCast(bcx, fn_ptr, llty));
+ } else {
+ assert!(!info_arg.is_ignore());
+ llargs.push(info);
+ }
+ return bcx;
+ }
+
+ let mut val = val;
+ if by_ref && !arg.is_indirect() {
+ // Have to load the argument, maybe while casting it.
+ if arg.original_ty == Type::i1(bcx.ccx()) {
+ // We store bools as i8 so we need to truncate to i1.
+ val = LoadRangeAssert(bcx, val, 0, 2, llvm::False);
+ val = Trunc(bcx, val, arg.original_ty);
+ } else if let Some(ty) = arg.cast {
+ val = Load(bcx, PointerCast(bcx, val, ty.ptr_to()));
+ if !bcx.unreachable.get() {
+ let llalign = llalign_of_min(bcx.ccx(), arg.ty);
+ unsafe {
+ llvm::LLVMSetAlignment(val, llalign);
+ }
+ }
+ } else {
+ val = Load(bcx, val);
+ }
}
+ llargs.push(val);
bcx
}