1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Handles translation of callees as well as other call-related
12 //! things. Callees are a superset of normal rust values and sometimes
13 //! have different representations. In particular, top-level fn items
14 //! and methods are represented as just a fn ptr and not a full
17 pub use self::CalleeData::*;
18 pub use self::CallArgs::*;
20 use arena::TypedArena;
21 use back::symbol_names;
22 use llvm::{self, ValueRef, get_params};
23 use middle::cstore::LOCAL_CRATE;
24 use rustc::hir::def_id::DefId;
28 use rustc::hir::map as hir_map;
29 use abi::{Abi, FnType};
36 use cleanup::CleanupMethods;
38 use common::{self, Block, Result, CrateContext, FunctionContext};
39 use common::{C_uint, C_undef};
42 use debuginfo::DebugLoc;
48 use machine::{llalign_of_min, llsize_of_store};
50 use monomorphize::{self, Instance};
55 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
58 use syntax::codemap::DUMMY_SP;
66 /// Constructor for enum variant/tuple-like-struct.
67 NamedTupleConstructor(Disr),
74 /// Trait object found in the vtable at that index.
79 pub struct Callee<'tcx> {
84 impl<'tcx> Callee<'tcx> {
86 pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
93 /// Trait or impl method call.
94 pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
95 method_call: ty::MethodCall)
97 let method = bcx.tcx().tables.borrow().method_map[&method_call];
98 Callee::method(bcx, method)
101 /// Trait or impl method.
102 pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
103 method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
104 let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
105 Callee::def(bcx.ccx(), method.def_id, substs)
108 /// Function or method definition.
109 pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
111 substs: &'tcx subst::Substs<'tcx>)
115 if substs.self_ty().is_some() {
116 // Only trait methods can have a Self parameter.
117 return Callee::trait_method(ccx, def_id, substs);
120 let maybe_node_id = inline::get_local_instance(ccx, def_id)
121 .and_then(|def_id| tcx.map.as_local_node_id(def_id));
122 let maybe_ast_node = maybe_node_id.and_then(|node_id| {
123 tcx.map.find(node_id)
126 let data = match maybe_ast_node {
127 Some(hir_map::NodeStructCtor(_)) => {
128 NamedTupleConstructor(Disr(0))
130 Some(hir_map::NodeVariant(_)) => {
131 let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
132 NamedTupleConstructor(Disr::from(vinfo.disr_val))
134 Some(hir_map::NodeForeignItem(fi)) if {
135 let abi = tcx.map.get_foreign_abi(fi.id);
136 abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
139 _ => return Callee::ptr(get_fn(ccx, def_id, substs))
144 ty: def_ty(tcx, def_id, substs)
148 /// Trait method, which has to be resolved to an impl method.
149 pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
151 substs: &'tcx subst::Substs<'tcx>)
155 let method_item = tcx.impl_or_trait_item(def_id);
156 let trait_id = method_item.container().id();
157 let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
158 match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
159 traits::VtableImpl(vtable_impl) => {
160 let impl_did = vtable_impl.impl_def_id;
161 let mname = tcx.item_name(def_id);
162 // create a concatenated set of substitutions which includes
163 // those from the impl and those from the method:
164 let impl_substs = vtable_impl.substs.with_method_from(&substs);
165 let substs = tcx.mk_substs(impl_substs);
166 let mth = meth::get_impl_method(tcx, impl_did, substs, mname);
168 // Translate the function, bypassing Callee::def.
169 // That is because default methods have the same ID as the
170 // trait method used to look up the impl method that ended
171 // up here, so calling Callee::def would infinitely recurse.
172 Callee::ptr(get_fn(ccx, mth.method.def_id, mth.substs))
174 traits::VtableClosure(vtable_closure) => {
175 // The substitutions should have no type parameters remaining
176 // after passing through fulfill_obligation
177 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
178 let llfn = closure::trans_closure_method(ccx,
179 vtable_closure.closure_def_id,
180 vtable_closure.substs,
183 let method_ty = def_ty(tcx, def_id, substs);
184 let fn_ptr_ty = match method_ty.sty {
185 ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
186 _ => bug!("expected fn item type, found {}",
189 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
191 traits::VtableFnPointer(fn_ty) => {
192 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
193 let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
195 let method_ty = def_ty(tcx, def_id, substs);
196 let fn_ptr_ty = match method_ty.sty {
197 ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
198 _ => bug!("expected fn item type, found {}",
201 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
203 traits::VtableObject(ref data) => {
205 data: Virtual(traits::get_vtable_index_of_object_method(
207 ty: def_ty(tcx, def_id, substs)
211 bug!("resolved vtable bad vtable {:?} in trans", vtable);
216 /// Get the abi::FnType for a direct call. Mainly deals with the fact
217 /// that a Virtual call doesn't take the vtable, like its shim does.
218 /// The extra argument types are for variadic (extern "C") functions.
219 pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
220 extra_args: &[Ty<'tcx>]) -> FnType {
221 let abi = self.ty.fn_abi();
222 let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
223 let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
224 let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
225 if let Virtual(_) = self.data {
226 // Don't pass the vtable, it's not an argument of the virtual fn.
227 fn_ty.args[1].ignore();
229 fn_ty.adjust_for_abi(ccx, abi, &sig);
233 /// This behemoth of a function translates function calls. Unfortunately, in
234 /// order to generate more efficient LLVM output at -O0, it has quite a complex
235 /// signature (refactoring this into two functions seems like a good idea).
237 /// In particular, for lang items, it is invoked with a dest of None, and in
238 /// that case the return value contains the result of the fn. The lang item must
239 /// not return a structural type or else all heck breaks loose.
241 /// For non-lang items, `dest` is always Some, and hence the result is written
242 /// into memory somewhere. Nonetheless we return the actual return value of the
244 pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
246 args: CallArgs<'a, 'tcx>,
247 dest: Option<expr::Dest>)
248 -> Result<'blk, 'tcx> {
249 trans_call_inner(bcx, debug_loc, self, args, dest)
252 /// Turn the callee into a function pointer.
253 pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
254 -> Datum<'tcx, Rvalue> {
255 let fn_ptr_ty = match self.ty.sty {
256 ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
261 immediate_rvalue(llfn, fn_ptr_ty)
264 let llfn = meth::trans_object_shim(ccx, self.ty, idx);
265 immediate_rvalue(llfn, fn_ptr_ty)
267 NamedTupleConstructor(_) => match self.ty.sty {
268 ty::TyFnDef(def_id, substs, _) => {
269 return get_fn(ccx, def_id, substs);
271 _ => bug!("expected fn item type, found {}", self.ty)
273 Intrinsic => bug!("intrinsic {} getting reified", self.ty)
278 /// Given a DefId and some Substs, produces the monomorphic item type.
279 fn def_ty<'tcx>(tcx: &TyCtxt<'tcx>,
281 substs: &'tcx subst::Substs<'tcx>)
283 let ty = tcx.lookup_item_type(def_id).ty;
284 monomorphize::apply_param_substs(tcx, substs, &ty)
287 /// Translates an adapter that implements the `Fn` trait for a fn
288 /// pointer. This is basically the equivalent of something like:
291 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
292 /// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
298 /// but for the bare function type given.
299 pub fn trans_fn_pointer_shim<'a, 'tcx>(
300 ccx: &'a CrateContext<'a, 'tcx>,
301 closure_kind: ty::ClosureKind,
302 bare_fn_ty: Ty<'tcx>)
305 let _icx = push_ctxt("trans_fn_pointer_shim");
308 // Normalize the type for better caching.
309 let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
311 // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
312 let is_by_ref = match closure_kind {
313 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
314 ty::ClosureKind::FnOnce => false,
317 let llfnpointer = match bare_fn_ty.sty {
318 ty::TyFnDef(def_id, substs, _) => {
319 // Function definitions have to be turned into a pointer.
320 let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val;
322 // A by-value fn item is ignored, so the shim has
323 // the same signature as the original function.
331 let bare_fn_ty_maybe_ref = if is_by_ref {
332 tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
337 // Check if we already trans'd this shim.
338 match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
339 Some(&llval) => { return llval; }
343 debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
346 // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
347 // which is the fn pointer, and `args`, which is the arguments tuple.
348 let sig = match bare_fn_ty.sty {
350 &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
353 ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
358 bug!("trans_fn_pointer_shim invoked on invalid type: {}",
362 let sig = tcx.erase_late_bound_regions(sig);
363 let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
364 let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
365 let sig = ty::FnSig {
366 inputs: vec![bare_fn_ty_maybe_ref,
371 let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
372 let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
373 unsafety: hir::Unsafety::Normal,
377 debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
381 symbol_names::internal_name_from_type_and_suffix(ccx,
384 let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
387 let (block_arena, fcx): (TypedArena<_>, FunctionContext);
388 block_arena = TypedArena::new();
389 fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
390 let mut bcx = fcx.init(false, None);
392 let llargs = get_params(fcx.llfn);
394 let self_idx = fcx.fn_ty.ret.is_indirect() as usize;
395 let llfnpointer = llfnpointer.unwrap_or_else(|| {
396 // the first argument (`self`) will be ptr to the fn pointer
398 Load(bcx, llargs[self_idx])
404 assert!(!fcx.needs_ret_allocas);
406 let dest = fcx.llretslotptr.get().map(|_|
407 expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
410 let callee = Callee {
411 data: Fn(llfnpointer),
414 bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
416 fcx.finish(bcx, DebugLoc::None);
418 ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
423 /// Translates a reference to a fn/method item, monomorphizing and
424 /// inlining as it goes.
428 /// - `ccx`: the crate context
429 /// - `def_id`: def id of the fn or method item being referenced
430 /// - `substs`: values for each of the fn/method's parameters
431 fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
433 substs: &'tcx subst::Substs<'tcx>)
434 -> Datum<'tcx, Rvalue> {
437 debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
439 assert!(!substs.types.needs_infer());
440 assert!(!substs.types.has_escaping_regions());
442 // Check whether this fn has an inlined copy and, if so, redirect
443 // def_id to the local id of the inlined copy.
444 let def_id = inline::maybe_instantiate_inline(ccx, def_id);
446 fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
447 let node_id = match tcx.map.as_local_node_id(def_id) {
449 None => { return false; }
451 let map_node = errors::expect(
452 &tcx.sess.diagnostic(),
453 tcx.map.find(node_id),
454 || "local item should be in ast map".to_string());
457 hir_map::NodeVariant(v) => {
458 v.node.data.is_tuple()
460 hir_map::NodeStructCtor(_) => true,
464 let must_monomorphise =
465 !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
467 debug!("get_fn({:?}) must_monomorphise: {}",
468 def_id, must_monomorphise);
470 // Create a monomorphic version of generic functions
471 if must_monomorphise {
472 // Should be either intra-crate or inlined.
473 assert_eq!(def_id.krate, LOCAL_CRATE);
475 let substs = tcx.mk_substs(substs.clone().erase_regions());
476 let (val, fn_ty) = monomorphize::monomorphic_fn(ccx, def_id, substs);
477 let fn_ptr_ty = match fn_ty.sty {
478 ty::TyFnDef(_, _, fty) => {
479 // Create a fn pointer with the substituted signature.
480 tcx.mk_ty(ty::TyFnPtr(fty))
482 _ => bug!("expected fn item type, found {}", fn_ty)
484 assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val));
485 return immediate_rvalue(val, fn_ptr_ty);
488 // Find the actual function pointer.
489 let ty = ccx.tcx().lookup_item_type(def_id).ty;
490 let fn_ptr_ty = match ty.sty {
491 ty::TyFnDef(_, _, fty) => {
492 // Create a fn pointer with the normalized signature.
493 tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
495 _ => bug!("expected fn item type, found {}", ty)
498 let instance = Instance::mono(ccx.tcx(), def_id);
499 if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
500 return immediate_rvalue(llfn, fn_ptr_ty);
504 let local_id = ccx.tcx().map.as_local_node_id(def_id);
505 let maybe_node = local_id.and_then(|id| tcx.map.find(id));
506 let (sym, attrs, local_item) = match maybe_node {
507 Some(hir_map::NodeItem(&hir::Item {
508 ref attrs, id, span, node: hir::ItemFn(..), ..
510 Some(hir_map::NodeTraitItem(&hir::TraitItem {
511 ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), ..
513 Some(hir_map::NodeImplItem(&hir::ImplItem {
514 ref attrs, id, span, node: hir::ImplItemKind::Method(..), ..
516 let sym = exported_name(ccx, instance, attrs);
518 if declare::get_defined_value(ccx, &sym).is_some() {
519 ccx.sess().span_fatal(span,
520 &format!("symbol `{}` is already defined", sym));
523 (sym, &attrs[..], Some(id))
526 Some(hir_map::NodeForeignItem(&hir::ForeignItem {
527 ref attrs, name, node: hir::ForeignItemFn(..), ..
529 (imported_name(name, attrs).to_string(), &attrs[..], None)
533 attrs = ccx.sess().cstore.item_attrs(def_id);
534 (ccx.sess().cstore.item_symbol(def_id), &attrs[..], None)
538 bug!("get_fn: unexpected variant: {:?}", variant)
542 // This is subtle and surprising, but sometimes we have to bitcast
543 // the resulting fn pointer. The reason has to do with external
544 // functions. If you have two crates that both bind the same C
545 // library, they may not use precisely the same types: for
546 // example, they will probably each declare their own structs,
547 // which are distinct types from LLVM's point of view (nominal
550 // Now, if those two crates are linked into an application, and
551 // they contain inlined code, you can wind up with a situation
552 // where both of those functions wind up being loaded into this
553 // application simultaneously. In that case, the same function
554 // (from LLVM's point of view) requires two types. But of course
555 // LLVM won't allow one function to have two types.
557 // What we currently do, therefore, is declare the function with
558 // one of the two types (whichever happens to come first) and then
559 // bitcast as needed when the function is referenced to make sure
560 // it has the type we expect.
562 // This can occur on either a crate-local or crate-external
563 // reference. It also occurs when testing libcore and in some
564 // other weird situations. Annoying.
566 let llptrty = type_of::type_of(ccx, fn_ptr_ty);
567 let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
568 if common::val_ty(llfn) != llptrty {
569 if local_item.is_some() {
570 bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}",
571 sym, Value(llfn), llptrty);
573 debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
574 consts::ptrcast(llfn, llptrty)
576 debug!("get_fn: not casting pointer!");
580 let llfn = declare::declare_fn(ccx, &sym, ty);
581 assert_eq!(common::val_ty(llfn), llptrty);
582 debug!("get_fn: not casting pointer!");
584 attributes::from_fn_attrs(ccx, attrs, llfn);
585 if let Some(id) = local_item {
586 // FIXME(eddyb) Doubt all extern fn should allow unwinding.
587 attributes::unwind(llfn, true);
588 ccx.item_symbols().borrow_mut().insert(id, sym);
594 ccx.instances().borrow_mut().insert(instance, llfn);
596 immediate_rvalue(llfn, fn_ptr_ty)
599 // ______________________________________________________________________
602 fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
604 callee: Callee<'tcx>,
605 args: CallArgs<'a, 'tcx>,
606 dest: Option<expr::Dest>)
607 -> Result<'blk, 'tcx> {
608 // Introduce a temporary cleanup scope that will contain cleanups
609 // for the arguments while they are being evaluated. The purpose
610 // this cleanup is to ensure that, should a panic occur while
611 // evaluating argument N, the values for arguments 0...N-1 are all
612 // cleaned up. If no panic occurs, the values are handed off to
613 // the callee, and hence none of the cleanups in this temporary
614 // scope will ever execute.
618 let abi = callee.ty.fn_abi();
619 let sig = callee.ty.fn_sig();
620 let output = bcx.tcx().erase_late_bound_regions(&sig.output());
621 let output = infer::normalize_associated_type(bcx.tcx(), &output);
623 let extra_args = match args {
624 ArgExprs(args) if abi != Abi::RustCall => {
625 args[sig.0.inputs.len()..].iter().map(|expr| {
626 common::expr_ty_adjusted(bcx, expr)
631 let fn_ty = callee.direct_fn_type(ccx, &extra_args);
633 let mut callee = match callee.data {
635 assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
636 assert!(dest.is_some());
638 return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
642 NamedTupleConstructor(disr) => {
643 assert!(dest.is_some());
645 return base::trans_named_tuple_constructor(bcx,
655 // Generate a location to store the result. If the user does
656 // not care about the result, just make a stack slot.
657 let opt_llretslot = dest.and_then(|dest| match dest {
658 expr::SaveIn(dst) => Some(dst),
660 let needs_drop = || match output {
661 ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
662 ty::FnDiverging => false
664 if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
665 // Push the out-pointer if we use an out-pointer for this
666 // return type, otherwise push "undef".
667 if fn_ty.ret.is_ignore() {
668 Some(C_undef(fn_ty.ret.original_ty.ptr_to()))
670 let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
671 call_lifetime_start(bcx, llresult);
680 // If there no destination, return must be direct, with no cast.
681 if opt_llretslot.is_none() {
682 assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
685 let mut llargs = Vec::new();
687 if fn_ty.ret.is_indirect() {
688 let mut llretslot = opt_llretslot.unwrap();
689 if let Some(ty) = fn_ty.ret.cast {
690 llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
692 llargs.push(llretslot);
695 let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
696 bcx = trans_args(bcx, abi, &fn_ty, &mut callee, args, &mut llargs,
697 cleanup::CustomScope(arg_cleanup_scope));
698 fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
700 let llfn = match callee {
702 _ => bug!("expected fn pointer callee, found {:?}", callee)
705 let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
706 if !bcx.unreachable.get() {
707 fn_ty.apply_attrs_callsite(llret);
710 // If the function we just called does not use an outpointer,
711 // store the result into the rust outpointer. Cast the outpointer
712 // type to match because some ABIs will use a different type than
713 // the Rust type. e.g., a {u32,u32} struct could be returned as
715 if !fn_ty.ret.is_ignore() && !fn_ty.ret.is_indirect() {
716 if let Some(llforeign_ret_ty) = fn_ty.ret.cast {
717 let llrust_ret_ty = fn_ty.ret.original_ty;
718 let llretslot = opt_llretslot.unwrap();
720 // The actual return type is a struct, but the ABI
721 // adaptation code has cast it into some scalar type. The
722 // code that follows is the only reliable way I have
723 // found to do a transform like i64 -> {i32,i32}.
724 // Basically we dump the data onto the stack then memcpy it.
726 // Other approaches I tried:
727 // - Casting rust ret pointer to the foreign type and using Store
728 // is (a) unsafe if size of foreign type > size of rust type and
729 // (b) runs afoul of strict aliasing rules, yielding invalid
730 // assembly under -O (specifically, the store gets removed).
731 // - Truncating foreign type to correct integral type and then
732 // bitcasting to the struct type yields invalid cast errors.
733 let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
734 base::call_lifetime_start(bcx, llscratch);
735 Store(bcx, llret, llscratch);
736 let llscratch_i8 = PointerCast(bcx, llscratch, Type::i8(ccx).ptr_to());
737 let llretptr_i8 = PointerCast(bcx, llretslot, Type::i8(ccx).ptr_to());
738 let llrust_size = llsize_of_store(ccx, llrust_ret_ty);
739 let llforeign_align = llalign_of_min(ccx, llforeign_ret_ty);
740 let llrust_align = llalign_of_min(ccx, llrust_ret_ty);
741 let llalign = cmp::min(llforeign_align, llrust_align);
742 debug!("llrust_size={}", llrust_size);
744 if !bcx.unreachable.get() {
745 base::call_memcpy(&B(bcx), llretptr_i8, llscratch_i8,
746 C_uint(ccx, llrust_size), llalign as u32);
748 base::call_lifetime_end(bcx, llscratch);
749 } else if let Some(llretslot) = opt_llretslot {
750 base::store_ty(bcx, llret, llretslot, output.unwrap());
754 fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
756 // If the caller doesn't care about the result of this fn call,
757 // drop the temporary slot we made.
758 match (dest, opt_llretslot, output) {
759 (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
760 // drop the value if it is not being saved.
761 bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc);
762 call_lifetime_end(bcx, llretslot);
767 if output == ty::FnDiverging {
771 Result::new(bcx, llret)
774 pub enum CallArgs<'a, 'tcx> {
775 /// Supply value of arguments as a list of expressions that must be
776 /// translated. This is used in the common case of `foo(bar, qux)`.
777 ArgExprs(&'a [P<hir::Expr>]),
779 /// Supply value of arguments as a list of LLVM value refs; frequently
780 /// used with lang items and so forth, when the argument is an internal
782 ArgVals(&'a [ValueRef]),
784 /// For overloaded operators: `(lhs, Option(rhs))`.
785 /// `lhs` is the left-hand-side and `rhs` is the datum
786 /// of the right-hand-side argument (if any).
787 ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
789 /// Supply value of arguments as a list of expressions that must be
790 /// translated, for overloaded call operators.
791 ArgOverloadedCall(Vec<&'a hir::Expr>),
794 fn trans_args_under_call_abi<'blk, 'tcx>(
795 mut bcx: Block<'blk, 'tcx>,
796 arg_exprs: &[P<hir::Expr>],
797 callee: &mut CalleeData,
799 llargs: &mut Vec<ValueRef>,
800 arg_cleanup_scope: cleanup::ScopeId)
805 // Translate the `self` argument first.
806 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
807 bcx = trans_arg_datum(bcx,
809 callee, fn_ty, &mut arg_idx,
813 // Now untuple the rest of the arguments.
814 let tuple_expr = &arg_exprs[1];
815 let tuple_type = common::node_id_type(bcx, tuple_expr.id);
817 match tuple_type.sty {
818 ty::TyTuple(ref field_types) => {
819 let tuple_datum = unpack_datum!(bcx,
820 expr::trans(bcx, &tuple_expr));
821 let tuple_lvalue_datum =
823 tuple_datum.to_lvalue_datum(bcx,
826 let repr = adt::represent_type(bcx.ccx(), tuple_type);
827 let repr_ptr = &repr;
828 for (i, field_type) in field_types.iter().enumerate() {
829 let arg_datum = tuple_lvalue_datum.get_element(
833 adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
835 bcx = trans_arg_datum(bcx,
837 callee, fn_ty, &mut arg_idx,
843 span_bug!(tuple_expr.span,
844 "argument to `.call()` wasn't a tuple?!")
851 pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
854 callee: &mut CalleeData,
855 args: CallArgs<'a, 'tcx>,
856 llargs: &mut Vec<ValueRef>,
857 arg_cleanup_scope: cleanup::ScopeId)
858 -> Block<'blk, 'tcx> {
859 debug!("trans_args(abi={})", abi);
861 let _icx = push_ctxt("trans_args");
866 // First we figure out the caller's view of the types of the arguments.
867 // This will be needed if this is a generic call, because the callee has
868 // to cast her view of the arguments to the caller's view.
870 ArgExprs(arg_exprs) => {
871 if abi == Abi::RustCall {
872 // This is only used for direct calls to the `call`,
873 // `call_mut` or `call_once` functions.
874 return trans_args_under_call_abi(bcx,
875 arg_exprs, callee, fn_ty,
880 for arg_expr in arg_exprs {
881 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
882 bcx = trans_arg_datum(bcx,
884 callee, fn_ty, &mut arg_idx,
889 ArgOverloadedCall(arg_exprs) => {
890 for expr in arg_exprs {
892 unpack_datum!(bcx, expr::trans(bcx, expr));
893 bcx = trans_arg_datum(bcx,
895 callee, fn_ty, &mut arg_idx,
900 ArgOverloadedOp(lhs, rhs) => {
901 bcx = trans_arg_datum(bcx, lhs,
902 callee, fn_ty, &mut arg_idx,
906 if let Some(rhs) = rhs {
907 bcx = trans_arg_datum(bcx, rhs,
908 callee, fn_ty, &mut arg_idx,
918 let fn_ptr = meth::get_virtual_method(bcx, vs[1], idx);
919 let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
920 *callee = Fn(PointerCast(bcx, fn_ptr, llty));
921 llargs.extend_from_slice(&vs[2..]);
923 _ => llargs.extend_from_slice(vs)
931 fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
932 arg_datum: Datum<'tcx, Expr>,
933 callee: &mut CalleeData,
935 next_idx: &mut usize,
936 arg_cleanup_scope: cleanup::ScopeId,
937 llargs: &mut Vec<ValueRef>)
938 -> Block<'blk, 'tcx> {
939 let _icx = push_ctxt("trans_arg_datum");
942 debug!("trans_arg_datum({:?})", arg_datum);
944 let arg = &fn_ty.args[*next_idx];
947 // Fill padding with undef value, where applicable.
948 if let Some(ty) = arg.pad {
949 llargs.push(C_undef(ty));
952 // Determine whether we want a by-ref datum even if not appropriate.
953 let want_by_ref = arg.is_indirect() || arg.cast.is_some();
955 let fat_ptr = common::type_is_fat_ptr(bcx.tcx(), arg_datum.ty);
956 let (by_ref, val) = if fat_ptr && !bcx.fcx.type_needs_drop(arg_datum.ty) {
957 (true, arg_datum.val)
959 // Make this an rvalue, since we are going to be
960 // passing ownership.
961 let arg_datum = unpack_datum!(
962 bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
964 // Now that arg_datum is owned, get it into the appropriate
965 // mode (ref vs value).
966 let arg_datum = unpack_datum!(bcx, if want_by_ref {
967 arg_datum.to_ref_datum(bcx)
969 arg_datum.to_appropriate_datum(bcx)
972 // Technically, ownership of val passes to the callee.
973 // However, we must cleanup should we panic before the
974 // callee is actually invoked.
975 (arg_datum.kind.is_by_ref(),
976 arg_datum.add_clean(bcx.fcx, arg_cleanup_scope))
983 debug!("--- trans_arg_datum passing {:?}", Value(val));
986 // Fat pointers should be passed without any transformations.
987 assert!(!arg.is_indirect() && arg.cast.is_none());
988 llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
990 let info_arg = &fn_ty.args[*next_idx];
992 assert!(!info_arg.is_indirect() && info_arg.cast.is_none());
993 let info = Load(bcx, expr::get_meta(bcx, val));
995 if let Virtual(idx) = *callee {
996 // We have to grab the fn pointer from the vtable when
997 // handling the first argument, ensure that here.
998 assert_eq!(*next_idx, 2);
999 assert!(info_arg.is_ignore());
1000 let fn_ptr = meth::get_virtual_method(bcx, info, idx);
1001 let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
1002 *callee = Fn(PointerCast(bcx, fn_ptr, llty));
1004 assert!(!info_arg.is_ignore());
1011 if by_ref && !arg.is_indirect() {
1012 // Have to load the argument, maybe while casting it.
1013 if arg.original_ty == Type::i1(bcx.ccx()) {
1014 // We store bools as i8 so we need to truncate to i1.
1015 val = LoadRangeAssert(bcx, val, 0, 2, llvm::False);
1016 val = Trunc(bcx, val, arg.original_ty);
1017 } else if let Some(ty) = arg.cast {
1018 val = Load(bcx, PointerCast(bcx, val, ty.ptr_to()));
1019 if !bcx.unreachable.get() {
1020 let llalign = llalign_of_min(bcx.ccx(), arg.ty);
1022 llvm::LLVMSetAlignment(val, llalign);
1026 val = Load(bcx, val);