]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/callee.rs
7675e1de958277426a9a2f9b374e6ee342caf537
[rust.git] / src / librustc_trans / callee.rs
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.
4 //
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.
10
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
15 //! closure.
16
17 pub use self::CalleeData::*;
18 pub use self::CallArgs::*;
19
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;
25 use rustc::infer;
26 use rustc::ty::subst;
27 use rustc::traits;
28 use rustc::hir::map as hir_map;
29 use abi::{Abi, FnType};
30 use adt;
31 use attributes;
32 use base;
33 use base::*;
34 use build::*;
35 use cleanup;
36 use cleanup::CleanupMethods;
37 use closure;
38 use common::{self, Block, Result, CrateContext, FunctionContext};
39 use common::{C_uint, C_undef};
40 use consts;
41 use datum::*;
42 use debuginfo::DebugLoc;
43 use declare;
44 use expr;
45 use glue;
46 use inline;
47 use intrinsic;
48 use machine::{llalign_of_min, llsize_of_store};
49 use meth;
50 use monomorphize::{self, Instance};
51 use type_::Type;
52 use type_of;
53 use value::Value;
54 use Disr;
55 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
56 use rustc::hir;
57
58 use syntax::codemap::DUMMY_SP;
59 use syntax::errors;
60 use syntax::ptr::P;
61
62 use std::cmp;
63
64 #[derive(Debug)]
65 pub enum CalleeData {
66     /// Constructor for enum variant/tuple-like-struct.
67     NamedTupleConstructor(Disr),
68
69     /// Function pointer.
70     Fn(ValueRef),
71
72     Intrinsic,
73
74     /// Trait object found in the vtable at that index.
75     Virtual(usize)
76 }
77
78 #[derive(Debug)]
79 pub struct Callee<'tcx> {
80     pub data: CalleeData,
81     pub ty: Ty<'tcx>
82 }
83
84 impl<'tcx> Callee<'tcx> {
85     /// Function pointer.
86     pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
87         Callee {
88             data: Fn(datum.val),
89             ty: datum.ty
90         }
91     }
92
93     /// Trait or impl method call.
94     pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
95                              method_call: ty::MethodCall)
96                              -> Callee<'tcx> {
97         let method = bcx.tcx().tables.borrow().method_map[&method_call];
98         Callee::method(bcx, method)
99     }
100
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)
106     }
107
108     /// Function or method definition.
109     pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
110                    def_id: DefId,
111                    substs: &'tcx subst::Substs<'tcx>)
112                    -> Callee<'tcx> {
113         let tcx = ccx.tcx();
114
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);
118         }
119
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)
124         });
125
126         let data = match maybe_ast_node {
127             Some(hir_map::NodeStructCtor(_)) => {
128                 NamedTupleConstructor(Disr(0))
129             }
130             Some(hir_map::NodeVariant(_)) => {
131                 let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
132                 NamedTupleConstructor(Disr::from(vinfo.disr_val))
133             }
134             Some(hir_map::NodeForeignItem(fi)) if {
135                 let abi = tcx.map.get_foreign_abi(fi.id);
136                 abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
137             } => Intrinsic,
138
139             _ => return Callee::ptr(get_fn(ccx, def_id, substs))
140         };
141
142         Callee {
143             data: data,
144             ty: def_ty(tcx, def_id, substs)
145         }
146     }
147
148     /// Trait method, which has to be resolved to an impl method.
149     pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
150                             def_id: DefId,
151                             substs: &'tcx subst::Substs<'tcx>)
152                             -> Callee<'tcx> {
153         let tcx = ccx.tcx();
154
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);
167
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))
173             }
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,
181                                                          trait_closure_kind);
182
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 {}",
187                               method_ty)
188                 };
189                 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
190             }
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);
194
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 {}",
199                               method_ty)
200                 };
201                 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
202             }
203             traits::VtableObject(ref data) => {
204                 Callee {
205                     data: Virtual(traits::get_vtable_index_of_object_method(
206                         tcx, data, def_id)),
207                     ty: def_ty(tcx, def_id, substs)
208                 }
209             }
210             vtable => {
211                 bug!("resolved vtable bad vtable {:?} in trans", vtable);
212             }
213         }
214     }
215
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();
228         }
229         fn_ty.adjust_for_abi(ccx, abi, &sig);
230         fn_ty
231     }
232
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).
236     ///
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.
240     ///
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
243     /// function.
244     pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
245                           debug_loc: DebugLoc,
246                           args: CallArgs<'a, 'tcx>,
247                           dest: Option<expr::Dest>)
248                           -> Result<'blk, 'tcx> {
249         trans_call_inner(bcx, debug_loc, self, args, dest)
250     }
251
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)),
257             _ => self.ty
258         };
259         match self.data {
260             Fn(llfn) => {
261                 immediate_rvalue(llfn, fn_ptr_ty)
262             }
263             Virtual(idx) => {
264                 let llfn = meth::trans_object_shim(ccx, self.ty, idx);
265                 immediate_rvalue(llfn, fn_ptr_ty)
266             }
267             NamedTupleConstructor(_) => match self.ty.sty {
268                 ty::TyFnDef(def_id, substs, _) => {
269                     return get_fn(ccx, def_id, substs);
270                 }
271                 _ => bug!("expected fn item type, found {}", self.ty)
272             },
273             Intrinsic => bug!("intrinsic {} getting reified", self.ty)
274         }
275     }
276 }
277
278 /// Given a DefId and some Substs, produces the monomorphic item type.
279 fn def_ty<'tcx>(tcx: &TyCtxt<'tcx>,
280                 def_id: DefId,
281                 substs: &'tcx subst::Substs<'tcx>)
282                 -> Ty<'tcx> {
283     let ty = tcx.lookup_item_type(def_id).ty;
284     monomorphize::apply_param_substs(tcx, substs, &ty)
285 }
286
287 /// Translates an adapter that implements the `Fn` trait for a fn
288 /// pointer. This is basically the equivalent of something like:
289 ///
290 /// ```
291 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
292 ///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
293 ///         (*self)(args.0)
294 ///     }
295 /// }
296 /// ```
297 ///
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>)
303     -> ValueRef
304 {
305     let _icx = push_ctxt("trans_fn_pointer_shim");
306     let tcx = ccx.tcx();
307
308     // Normalize the type for better caching.
309     let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
310
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,
315     };
316
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;
321             if !is_by_ref {
322                 // A by-value fn item is ignored, so the shim has
323                 // the same signature as the original function.
324                 return llfn;
325             }
326             Some(llfn)
327         }
328         _ => None
329     };
330
331     let bare_fn_ty_maybe_ref = if is_by_ref {
332         tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
333     } else {
334         bare_fn_ty
335     };
336
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; }
340         None => { }
341     }
342
343     debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
344            bare_fn_ty);
345
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 {
349         ty::TyFnDef(_, _,
350                     &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
351                                     abi: Abi::Rust,
352                                     ref sig }) |
353         ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
354                                     abi: Abi::Rust,
355                                     ref sig }) => sig,
356
357         _ => {
358             bug!("trans_fn_pointer_shim invoked on invalid type: {}",
359                  bare_fn_ty);
360         }
361     };
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,
367                      tuple_input_ty],
368         output: sig.output,
369         variadic: false
370     };
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,
374         abi: Abi::RustCall,
375         sig: ty::Binder(sig)
376     });
377     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
378
379     //
380     let function_name =
381         symbol_names::internal_name_from_type_and_suffix(ccx,
382                                                          bare_fn_ty,
383                                                          "fn_pointer_shim");
384     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
385
386     //
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);
391
392     let llargs = get_params(fcx.llfn);
393
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
397         if is_by_ref {
398             Load(bcx, llargs[self_idx])
399         } else {
400             llargs[self_idx]
401         }
402     });
403
404     assert!(!fcx.needs_ret_allocas);
405
406     let dest = fcx.llretslotptr.get().map(|_|
407         expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
408     );
409
410     let callee = Callee {
411         data: Fn(llfnpointer),
412         ty: bare_fn_ty
413     };
414     bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
415
416     fcx.finish(bcx, DebugLoc::None);
417
418     ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
419
420     llfn
421 }
422
423 /// Translates a reference to a fn/method item, monomorphizing and
424 /// inlining as it goes.
425 ///
426 /// # Parameters
427 ///
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>,
432                     def_id: DefId,
433                     substs: &'tcx subst::Substs<'tcx>)
434                     -> Datum<'tcx, Rvalue> {
435     let tcx = ccx.tcx();
436
437     debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
438
439     assert!(!substs.types.needs_infer());
440     assert!(!substs.types.has_escaping_regions());
441
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);
445
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) {
448             Some(n) => n,
449             None => { return false; }
450         };
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());
455
456         match map_node {
457             hir_map::NodeVariant(v) => {
458                 v.node.data.is_tuple()
459             }
460             hir_map::NodeStructCtor(_) => true,
461             _ => false
462         }
463     }
464     let must_monomorphise =
465         !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
466
467     debug!("get_fn({:?}) must_monomorphise: {}",
468            def_id, must_monomorphise);
469
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);
474
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))
481             }
482             _ => bug!("expected fn item type, found {}", fn_ty)
483         };
484         assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val));
485         return immediate_rvalue(val, fn_ptr_ty);
486     }
487
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))
494         }
495         _ => bug!("expected fn item type, found {}", ty)
496     };
497
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);
501     }
502
503     let attrs;
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(..), ..
509         })) |
510         Some(hir_map::NodeTraitItem(&hir::TraitItem {
511             ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), ..
512         })) |
513         Some(hir_map::NodeImplItem(&hir::ImplItem {
514             ref attrs, id, span, node: hir::ImplItemKind::Method(..), ..
515         })) => {
516             let sym = exported_name(ccx, instance, attrs);
517
518             if declare::get_defined_value(ccx, &sym).is_some() {
519                 ccx.sess().span_fatal(span,
520                     &format!("symbol `{}` is already defined", sym));
521             }
522
523             (sym, &attrs[..], Some(id))
524         }
525
526         Some(hir_map::NodeForeignItem(&hir::ForeignItem {
527             ref attrs, name, node: hir::ForeignItemFn(..), ..
528         })) => {
529             (imported_name(name, attrs).to_string(), &attrs[..], None)
530         }
531
532         None => {
533             attrs = ccx.sess().cstore.item_attrs(def_id);
534             (ccx.sess().cstore.item_symbol(def_id), &attrs[..], None)
535         }
536
537         ref variant => {
538             bug!("get_fn: unexpected variant: {:?}", variant)
539         }
540     };
541
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
548     // types).
549     //
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.
556     //
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.
561     //
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.
565
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);
572             }
573             debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
574             consts::ptrcast(llfn, llptrty)
575         } else {
576             debug!("get_fn: not casting pointer!");
577             llfn
578         }
579     } else {
580         let llfn = declare::declare_fn(ccx, &sym, ty);
581         assert_eq!(common::val_ty(llfn), llptrty);
582         debug!("get_fn: not casting pointer!");
583
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);
589         }
590
591         llfn
592     };
593
594     ccx.instances().borrow_mut().insert(instance, llfn);
595
596     immediate_rvalue(llfn, fn_ptr_ty)
597 }
598
599 // ______________________________________________________________________
600 // Translating calls
601
602 fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
603                                     debug_loc: DebugLoc,
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.
615     let fcx = bcx.fcx;
616     let ccx = fcx.ccx;
617
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);
622
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)
627             }).collect()
628         }
629         _ => vec![]
630     };
631     let fn_ty = callee.direct_fn_type(ccx, &extra_args);
632
633     let mut callee = match callee.data {
634         Intrinsic => {
635             assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
636             assert!(dest.is_some());
637
638             return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
639                                                    args, dest.unwrap(),
640                                                    debug_loc);
641         }
642         NamedTupleConstructor(disr) => {
643             assert!(dest.is_some());
644
645             return base::trans_named_tuple_constructor(bcx,
646                                                        callee.ty,
647                                                        disr,
648                                                        args,
649                                                        dest.unwrap(),
650                                                        debug_loc);
651         }
652         f => f
653     };
654
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),
659         expr::Ignore => {
660             let needs_drop = || match output {
661                 ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
662                 ty::FnDiverging => false
663             };
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()))
669                 } else {
670                     let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
671                     call_lifetime_start(bcx, llresult);
672                     Some(llresult)
673                 }
674             } else {
675                 None
676             }
677         }
678     });
679
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());
683     }
684
685     let mut llargs = Vec::new();
686
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());
691         }
692         llargs.push(llretslot);
693     }
694
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();
699
700     let llfn = match callee {
701         Fn(f) => f,
702         _ => bug!("expected fn pointer callee, found {:?}", callee)
703     };
704
705     let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
706     if !bcx.unreachable.get() {
707         fn_ty.apply_attrs_callsite(llret);
708     }
709
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
714     // u64.
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();
719
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.
725             //
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);
743
744             if !bcx.unreachable.get() {
745                 base::call_memcpy(&B(bcx), llretptr_i8, llscratch_i8,
746                                   C_uint(ccx, llrust_size), llalign as u32);
747             }
748             base::call_lifetime_end(bcx, llscratch);
749         } else if let Some(llretslot) = opt_llretslot {
750             base::store_ty(bcx, llret, llretslot, output.unwrap());
751         }
752     }
753
754     fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
755
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);
763         }
764         _ => {}
765     }
766
767     if output == ty::FnDiverging {
768         Unreachable(bcx);
769     }
770
771     Result::new(bcx, llret)
772 }
773
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>]),
778
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
781     /// value.
782     ArgVals(&'a [ValueRef]),
783
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>>),
788
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>),
792 }
793
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,
798                              fn_ty: &FnType,
799                              llargs: &mut Vec<ValueRef>,
800                              arg_cleanup_scope: cleanup::ScopeId)
801                              -> Block<'blk, 'tcx>
802 {
803     let mut arg_idx = 0;
804
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,
808                           arg_datum,
809                           callee, fn_ty, &mut arg_idx,
810                           arg_cleanup_scope,
811                           llargs);
812
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);
816
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 =
822                 unpack_datum!(bcx,
823                               tuple_datum.to_lvalue_datum(bcx,
824                                                           "args",
825                                                           tuple_expr.id));
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(
830                     bcx,
831                     field_type,
832                     |srcval| {
833                         adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
834                     }).to_expr_datum();
835                 bcx = trans_arg_datum(bcx,
836                                       arg_datum,
837                                       callee, fn_ty, &mut arg_idx,
838                                       arg_cleanup_scope,
839                                       llargs);
840             }
841         }
842         _ => {
843             span_bug!(tuple_expr.span,
844                       "argument to `.call()` wasn't a tuple?!")
845         }
846     };
847
848     bcx
849 }
850
851 pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
852                                   abi: Abi,
853                                   fn_ty: &FnType,
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);
860
861     let _icx = push_ctxt("trans_args");
862
863     let mut bcx = bcx;
864     let mut arg_idx = 0;
865
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.
869     match args {
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,
876                                                  llargs,
877                                                  arg_cleanup_scope)
878             }
879
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,
883                                       arg_datum,
884                                       callee, fn_ty, &mut arg_idx,
885                                       arg_cleanup_scope,
886                                       llargs);
887             }
888         }
889         ArgOverloadedCall(arg_exprs) => {
890             for expr in arg_exprs {
891                 let arg_datum =
892                     unpack_datum!(bcx, expr::trans(bcx, expr));
893                 bcx = trans_arg_datum(bcx,
894                                       arg_datum,
895                                       callee, fn_ty, &mut arg_idx,
896                                       arg_cleanup_scope,
897                                       llargs);
898             }
899         }
900         ArgOverloadedOp(lhs, rhs) => {
901             bcx = trans_arg_datum(bcx, lhs,
902                                   callee, fn_ty, &mut arg_idx,
903                                   arg_cleanup_scope,
904                                   llargs);
905
906             if let Some(rhs) = rhs {
907                 bcx = trans_arg_datum(bcx, rhs,
908                                       callee, fn_ty, &mut arg_idx,
909                                       arg_cleanup_scope,
910                                       llargs);
911             }
912         }
913         ArgVals(vs) => {
914             match *callee {
915                 Virtual(idx) => {
916                     llargs.push(vs[0]);
917
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..]);
922                 }
923                 _ => llargs.extend_from_slice(vs)
924             }
925         }
926     }
927
928     bcx
929 }
930
931 fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
932                                arg_datum: Datum<'tcx, Expr>,
933                                callee: &mut CalleeData,
934                                fn_ty: &FnType,
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");
940     let mut bcx = bcx;
941
942     debug!("trans_arg_datum({:?})", arg_datum);
943
944     let arg = &fn_ty.args[*next_idx];
945     *next_idx += 1;
946
947     // Fill padding with undef value, where applicable.
948     if let Some(ty) = arg.pad {
949         llargs.push(C_undef(ty));
950     }
951
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();
954
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)
958     } else {
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"));
963
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)
968         } else {
969             arg_datum.to_appropriate_datum(bcx)
970         });
971
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))
977     };
978
979     if arg.is_ignore() {
980         return bcx;
981     }
982
983     debug!("--- trans_arg_datum passing {:?}", Value(val));
984
985     if fat_ptr {
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)));
989
990         let info_arg = &fn_ty.args[*next_idx];
991         *next_idx += 1;
992         assert!(!info_arg.is_indirect() && info_arg.cast.is_none());
993         let info = Load(bcx, expr::get_meta(bcx, val));
994
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));
1003         } else {
1004             assert!(!info_arg.is_ignore());
1005             llargs.push(info);
1006         }
1007         return bcx;
1008     }
1009
1010     let mut val = val;
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);
1021                 unsafe {
1022                     llvm::LLVMSetAlignment(val, llalign);
1023                 }
1024             }
1025         } else {
1026             val = Load(bcx, val);
1027         }
1028     }
1029
1030     llargs.push(val);
1031     bcx
1032 }