//! closure.
pub use self::CalleeData::*;
-pub use self::CallArgs::*;
use arena::TypedArena;
use back::symbol_names;
use llvm::{self, ValueRef, get_params};
-use middle::cstore::LOCAL_CRATE;
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
-use rustc::hir::map as hir_map;
use abi::{Abi, FnType};
-use adt;
use attributes;
use base;
use base::*;
use build::*;
-use cleanup;
-use cleanup::CleanupMethods;
use closure;
-use common::{self, Block, Result, CrateContext, FunctionContext, C_undef};
+use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
use consts;
-use datum::*;
use debuginfo::DebugLoc;
use declare;
-use expr;
-use glue;
-use inline;
-use intrinsic;
-use machine::llalign_of_min;
use meth;
use monomorphize::{self, Instance};
use trans_item::TransItem;
-use type_::Type;
use type_of;
-use value::Value;
use Disr;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
use rustc::hir;
use syntax_pos::DUMMY_SP;
-use errors;
-use syntax::ptr::P;
#[derive(Debug)]
pub enum CalleeData {
impl<'tcx> Callee<'tcx> {
/// Function pointer.
- pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
+ pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
Callee {
- data: Fn(datum.val),
- ty: datum.ty
+ data: Fn(llfn),
+ ty: ty
}
}
return Callee::trait_method(ccx, trait_id, def_id, substs);
}
- let maybe_node_id = inline::get_local_instance(ccx, def_id)
- .and_then(|def_id| tcx.map.as_local_node_id(def_id));
- let maybe_ast_node = maybe_node_id.and_then(|node_id| {
- tcx.map.find(node_id)
- });
-
- let data = match maybe_ast_node {
- Some(hir_map::NodeStructCtor(_)) => {
- NamedTupleConstructor(Disr(0))
- }
- Some(hir_map::NodeVariant(_)) => {
- let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
- NamedTupleConstructor(Disr::from(vinfo.disr_val))
+ let fn_ty = def_ty(ccx.shared(), def_id, substs);
+ if let ty::TyFnDef(_, _, f) = fn_ty.sty {
+ if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
+ return Callee {
+ data: Intrinsic,
+ ty: fn_ty
+ };
}
- Some(hir_map::NodeForeignItem(fi)) if {
- let abi = tcx.map.get_foreign_abi(fi.id);
- abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
- } => Intrinsic,
-
- _ => return Callee::ptr(get_fn(ccx, def_id, substs))
- };
+ }
- Callee {
- data: data,
- ty: def_ty(tcx, def_id, substs)
+ // FIXME(eddyb) Detect ADT constructors more efficiently.
+ if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
+ if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
+ return Callee {
+ data: NamedTupleConstructor(Disr::from(v.disr_val)),
+ ty: fn_ty
+ };
+ }
}
+
+ let (llfn, ty) = get_fn(ccx, def_id, substs);
+ Callee::ptr(llfn, ty)
}
/// Trait method, which has to be resolved to an impl method.
// 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))
+ let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
+ Callee::ptr(llfn, ty)
}
traits::VtableClosure(vtable_closure) => {
// The substitutions should have no type parameters remaining
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_fn_ptr(fty),
- _ => bug!("expected fn item type, found {}",
- method_ty)
- };
- Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
+ let method_ty = def_ty(ccx.shared(), def_id, substs);
+ Callee::ptr(llfn, method_ty)
}
traits::VtableFnPointer(vtable_fn_pointer) => {
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
- let method_ty = def_ty(tcx, def_id, substs);
- let fn_ptr_ty = match method_ty.sty {
- ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty),
- _ => bug!("expected fn item type, found {}",
- method_ty)
- };
- Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
+ let method_ty = def_ty(ccx.shared(), def_id, substs);
+ Callee::ptr(llfn, method_ty)
}
traits::VtableObject(ref data) => {
Callee {
data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
- ty: def_ty(tcx, def_id, substs)
+ ty: def_ty(ccx.shared(), def_id, substs)
}
}
vtable => {
/// function.
pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc,
- args: CallArgs<'a, 'tcx>,
- dest: Option<expr::Dest>)
+ args: &[ValueRef],
+ dest: Option<ValueRef>)
-> Result<'blk, 'tcx> {
trans_call_inner(bcx, debug_loc, self, args, dest)
}
/// 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_fn_ptr(f),
- _ => self.ty
- };
+ pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
match self.data {
- Fn(llfn) => {
- immediate_rvalue(llfn, fn_ptr_ty)
- }
+ Fn(llfn) => llfn,
Virtual(idx) => {
- let llfn = meth::trans_object_shim(ccx, self.ty, idx);
- immediate_rvalue(llfn, fn_ptr_ty)
+ meth::trans_object_shim(ccx, self.ty, idx)
}
- NamedTupleConstructor(_) => match self.ty.sty {
+ NamedTupleConstructor(disr) => match self.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
- return get_fn(ccx, def_id, substs);
+ let instance = Instance::new(def_id, substs);
+ if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
+ return llfn;
+ }
+
+ let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
+ TransItem::Fn(instance));
+ assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
+ let lldecl = declare::define_internal_fn(ccx, &sym, self.ty);
+ base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl);
+ ccx.instances().borrow_mut().insert(instance, lldecl);
+
+ lldecl
}
_ => bug!("expected fn item type, found {}", self.ty)
},
}
/// Given a DefId and some Substs, produces the monomorphic item type.
-fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> {
- let ty = tcx.lookup_item_type(def_id).ty;
- monomorphize::apply_param_substs(tcx, substs, &ty)
+ let ty = shared.tcx().lookup_item_type(def_id).ty;
+ monomorphize::apply_param_substs(shared, substs, &ty)
}
/// Translates an adapter that implements the `Fn` trait for a fn
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;
+ let llfn = Callee::def(ccx, def_id, substs).reify(ccx);
if !is_by_ref {
// A by-value fn item is ignored, so the shim has
// the same signature as the original function.
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
- let mut bcx = fcx.init(false, None);
+ let mut bcx = fcx.init(false);
let llargs = get_params(fcx.llfn);
}
});
- assert!(!fcx.needs_ret_allocas);
-
- let dest = fcx.llretslotptr.get().map(|_|
- expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
- );
+ let dest = fcx.llretslotptr.get();
let callee = Callee {
data: Fn(llfnpointer),
ty: bare_fn_ty
};
- bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+ bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
fcx.finish(bcx, DebugLoc::None);
fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
- -> Datum<'tcx, Rvalue> {
+ -> (ValueRef, Ty<'tcx>) {
let tcx = ccx.tcx();
debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
- assert!(!substs.types.needs_infer());
- assert!(!substs.types.has_escaping_regions());
-
- // Check whether this fn has an inlined copy and, if so, redirect
- // def_id to the local id of the inlined copy.
- let def_id = inline::maybe_instantiate_inline(ccx, def_id);
-
- fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool {
- let node_id = match tcx.map.as_local_node_id(def_id) {
- Some(n) => n,
- None => { return false; }
- };
- let map_node = errors::expect(
- &tcx.sess.diagnostic(),
- tcx.map.find(node_id),
- || "local item should be in ast map".to_string());
-
- match map_node {
- hir_map::NodeVariant(v) => {
- v.node.data.is_tuple()
- }
- hir_map::NodeStructCtor(_) => true,
- _ => false
- }
- }
- let must_monomorphise =
- !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
-
- debug!("get_fn({:?}) must_monomorphise: {}",
- def_id, must_monomorphise);
-
- // Create a monomorphic version of generic functions
- if must_monomorphise {
- // Should be either intra-crate or inlined.
- assert_eq!(def_id.krate, LOCAL_CRATE);
-
- let substs = tcx.normalize_associated_type(&substs);
- 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.
- tcx.mk_fn_ptr(fty)
- }
- _ => bug!("expected fn item type, found {}", fn_ty)
- };
- assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val));
- return immediate_rvalue(val, fn_ptr_ty);
- }
+ assert!(!substs.needs_infer());
+ assert!(!substs.has_escaping_regions());
+ assert!(!substs.has_param_types());
- // Find the actual function pointer.
- let ty = ccx.tcx().lookup_item_type(def_id).ty;
- let fn_ptr_ty = match ty.sty {
- ty::TyFnDef(_, _, ref fty) => {
- // Create a fn pointer with the normalized signature.
- tcx.mk_fn_ptr(tcx.normalize_associated_type(fty))
- }
- _ => bug!("expected fn item type, found {}", ty)
- };
+ let substs = tcx.normalize_associated_type(&substs);
+ let instance = Instance::new(def_id, substs);
+ let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
+ let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
- let instance = Instance::mono(ccx.shared(), def_id);
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
- return immediate_rvalue(llfn, fn_ptr_ty);
+ return (llfn, fn_ty);
}
- let local_id = ccx.tcx().map.as_local_node_id(def_id);
- let local_item = match local_id.and_then(|id| tcx.map.find(id)) {
- Some(hir_map::NodeItem(&hir::Item {
- span, node: hir::ItemFn(..), ..
- })) |
- Some(hir_map::NodeTraitItem(&hir::TraitItem {
- span, node: hir::MethodTraitItem(_, Some(_)), ..
- })) |
- Some(hir_map::NodeImplItem(&hir::ImplItem {
- span, node: hir::ImplItemKind::Method(..), ..
- })) => {
- Some(span)
- }
- _ => None
- };
+ let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
+ TransItem::Fn(instance));
+ debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
// This is subtle and surprising, but sometimes we have to bitcast
// the resulting fn pointer. The reason has to do with external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
- let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
- TransItem::Fn(instance));
-
- let llptrty = type_of::type_of(ccx, fn_ptr_ty);
- let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
- if let Some(span) = local_item {
- if declare::get_defined_value(ccx, &sym).is_some() {
- ccx.sess().span_fatal(span,
- &format!("symbol `{}` is already defined", &sym));
- }
+ let fn_ptr_ty = match fn_ty.sty {
+ ty::TyFnDef(_, _, fty) => {
+ // Create a fn pointer with the substituted signature.
+ tcx.mk_fn_ptr(fty)
}
+ _ => bug!("expected fn item type, found {}", fn_ty)
+ };
+ let llptrty = type_of::type_of(ccx, fn_ptr_ty);
+ let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
if common::val_ty(llfn) != llptrty {
- if local_item.is_some() {
- bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}",
- sym, Value(llfn), llptrty);
- }
debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
consts::ptrcast(llfn, llptrty)
} else {
llfn
}
} else {
- let llfn = declare::declare_fn(ccx, &sym, ty);
+ let llfn = declare::declare_fn(ccx, &sym, fn_ty);
assert_eq!(common::val_ty(llfn), llptrty);
debug!("get_fn: not casting pointer!");
let attrs = ccx.tcx().get_attrs(def_id);
attributes::from_fn_attrs(ccx, &attrs, llfn);
- if local_item.is_some() {
+
+ let is_local_def = ccx.shared().translation_items().borrow()
+ .contains(&TransItem::Fn(instance));
+ if is_local_def {
// FIXME(eddyb) Doubt all extern fn should allow unwinding.
attributes::unwind(llfn, true);
+ unsafe {
+ llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
+ }
}
llfn
ccx.instances().borrow_mut().insert(instance, llfn);
- immediate_rvalue(llfn, fn_ptr_ty)
+ (llfn, fn_ty)
}
// ______________________________________________________________________
// Translating calls
-fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
+fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc,
callee: Callee<'tcx>,
- args: CallArgs<'a, 'tcx>,
- dest: Option<expr::Dest>)
+ args: &[ValueRef],
+ opt_llretslot: Option<ValueRef>)
-> Result<'blk, 'tcx> {
// Introduce a temporary cleanup scope that will contain cleanups
// for the arguments while they are being evaluated. The purpose
let fcx = bcx.fcx;
let ccx = fcx.ccx;
- let abi = callee.ty.fn_abi();
- let sig = callee.ty.fn_sig();
- let output = bcx.tcx().erase_late_bound_regions(&sig.output());
- let output = bcx.tcx().normalize_associated_type(&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()
- }
- _ => vec![]
- };
- let fn_ty = callee.direct_fn_type(ccx, &extra_args);
+ let fn_ret = callee.ty.fn_ret();
+ let fn_ty = callee.direct_fn_type(ccx, &[]);
let mut callee = match callee.data {
- Intrinsic => {
- assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
- assert!(dest.is_some());
-
- return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
- args, dest.unwrap(),
- debug_loc);
- }
- NamedTupleConstructor(disr) => {
- assert!(dest.is_some());
-
- return base::trans_named_tuple_constructor(bcx,
- callee.ty,
- disr,
- args,
- dest.unwrap(),
- debug_loc);
+ NamedTupleConstructor(_) | Intrinsic => {
+ bug!("{:?} calls should not go through Callee::call", callee);
}
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 needs_drop = || bcx.fcx.type_needs_drop(output);
- 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 fn_ty.ret.is_ignore() {
- Some(C_undef(fn_ty.ret.original_ty.ptr_to()))
- } else {
- let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
- call_lifetime_start(bcx, llresult);
- Some(llresult)
- }
- } else {
- None
- }
- }
- });
-
// 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());
llargs.push(llretslot);
}
- 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();
+ match callee {
+ Virtual(idx) => {
+ llargs.push(args[0]);
+
+ let fn_ptr = meth::get_virtual_method(bcx, args[1], idx);
+ let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+ callee = Fn(PointerCast(bcx, fn_ptr, llty));
+ llargs.extend_from_slice(&args[2..]);
+ }
+ _ => llargs.extend_from_slice(args)
+ }
let llfn = match callee {
Fn(f) => f,
_ => bug!("expected fn pointer callee, found {:?}", callee)
};
- let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
+ let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
if !bcx.unreachable.get() {
fn_ty.apply_attrs_callsite(llret);
}
}
- 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) {
- (Some(expr::Ignore), Some(llretslot)) => {
- // drop the value if it is not being saved.
- bcx = glue::drop_ty(bcx, llretslot, output, debug_loc);
- call_lifetime_end(bcx, llretslot);
- }
- _ => {}
- }
-
- // FIXME(canndrew): This is_never should really be an is_uninhabited
- if output.is_never() {
+ if fn_ret.0.is_never() {
Unreachable(bcx);
}
Result::new(bcx, llret)
}
-
-pub enum CallArgs<'a, 'tcx> {
- /// Supply value of arguments as a list of expressions that must be
- /// translated. This is used in the common case of `foo(bar, qux)`.
- ArgExprs(&'a [P<hir::Expr>]),
-
- /// Supply value of arguments as a list of LLVM value refs; frequently
- /// used with lang items and so forth, when the argument is an internal
- /// value.
- ArgVals(&'a [ValueRef]),
-
- /// For overloaded operators: `(lhs, Option(rhs))`.
- /// `lhs` is the left-hand-side and `rhs` is the datum
- /// of the right-hand-side argument (if any).
- ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
-
- /// Supply value of arguments as a list of expressions that must be
- /// translated, for overloaded call operators.
- ArgOverloadedCall(Vec<&'a hir::Expr>),
-}
-
-fn trans_args_under_call_abi<'blk, 'tcx>(
- mut bcx: Block<'blk, 'tcx>,
- arg_exprs: &[P<hir::Expr>],
- callee: &mut CalleeData,
- fn_ty: &FnType,
- llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId)
- -> Block<'blk, 'tcx>
-{
- 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,
- arg_datum,
- callee, fn_ty, &mut arg_idx,
- arg_cleanup_scope,
- llargs);
-
- // Now untuple the rest of the arguments.
- let tuple_expr = &arg_exprs[1];
- let tuple_type = common::node_id_type(bcx, tuple_expr.id);
-
- match tuple_type.sty {
- ty::TyTuple(ref field_types) => {
- let tuple_datum = unpack_datum!(bcx,
- expr::trans(bcx, &tuple_expr));
- let tuple_lvalue_datum =
- unpack_datum!(bcx,
- tuple_datum.to_lvalue_datum(bcx,
- "args",
- tuple_expr.id));
- let repr = adt::represent_type(bcx.ccx(), tuple_type);
- let repr_ptr = &repr;
- for (i, field_type) in field_types.iter().enumerate() {
- let arg_datum = tuple_lvalue_datum.get_element(
- bcx,
- field_type,
- |srcval| {
- adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
- }).to_expr_datum();
- bcx = trans_arg_datum(bcx,
- arg_datum,
- callee, fn_ty, &mut arg_idx,
- arg_cleanup_scope,
- llargs);
- }
- }
- _ => {
- span_bug!(tuple_expr.span,
- "argument to `.call()` wasn't a tuple?!")
- }
- };
-
- bcx
-}
-
-pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- abi: Abi,
- fn_ty: &FnType,
- callee: &mut CalleeData,
- args: CallArgs<'a, 'tcx>,
- llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId)
- -> Block<'blk, 'tcx> {
- debug!("trans_args(abi={})", abi);
-
- let _icx = push_ctxt("trans_args");
-
- 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
- // to cast her view of the arguments to the caller's view.
- match args {
- ArgExprs(arg_exprs) => {
- 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(bcx,
- arg_exprs, callee, fn_ty,
- llargs,
- arg_cleanup_scope)
- }
-
- for arg_expr in arg_exprs {
- let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
- bcx = trans_arg_datum(bcx,
- arg_datum,
- callee, fn_ty, &mut arg_idx,
- arg_cleanup_scope,
- llargs);
- }
- }
- ArgOverloadedCall(arg_exprs) => {
- 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) => {
- bcx = trans_arg_datum(bcx, lhs,
- callee, fn_ty, &mut arg_idx,
- arg_cleanup_scope,
- llargs);
-
- if let Some(rhs) = rhs {
- bcx = trans_arg_datum(bcx, rhs,
- callee, fn_ty, &mut arg_idx,
- arg_cleanup_scope,
- llargs);
- }
- }
- ArgVals(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
-}
-
-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;
-
- debug!("trans_arg_datum({:?})", arg_datum);
-
- 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));
- }
-
- // Determine whether we want a by-ref datum even if not appropriate.
- let want_by_ref = arg.is_indirect() || arg.cast.is_some();
-
- 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.
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
- // Now that arg_datum is owned, get it into the appropriate
- // mode (ref vs value).
- 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.kind.is_by_ref(),
- arg_datum.add_clean(bcx.fcx, arg_cleanup_scope))
- };
-
- if arg.is_ignore() {
- return bcx;
- }
-
- debug!("--- trans_arg_datum passing {:?}", Value(val));
-
- 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)));
-
- 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
-}