]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/callee.rs
1013c5d64b6097039119d3942c98d4ad6b413c38
[rust.git] / src / librustc_trans / 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::link;
22 use llvm::{self, ValueRef, get_params};
23 use middle::cstore::LOCAL_CRATE;
24 use middle::def_id::DefId;
25 use middle::infer;
26 use middle::subst;
27 use middle::subst::{Substs};
28 use middle::traits;
29 use rustc::front::map as hir_map;
30 use trans::abi::{Abi, FnType};
31 use trans::adt;
32 use trans::attributes;
33 use trans::base;
34 use trans::base::*;
35 use trans::build::*;
36 use trans::cleanup;
37 use trans::cleanup::CleanupMethods;
38 use trans::closure;
39 use trans::common::{self, Block, Result, CrateContext, FunctionContext};
40 use trans::common::{C_uint, C_undef};
41 use trans::consts;
42 use trans::datum::*;
43 use trans::debuginfo::DebugLoc;
44 use trans::declare;
45 use trans::expr;
46 use trans::glue;
47 use trans::inline;
48 use trans::intrinsic;
49 use trans::machine::{llalign_of_min, llsize_of_store};
50 use trans::meth;
51 use trans::monomorphize::{self, Instance};
52 use trans::type_::Type;
53 use trans::type_of;
54 use trans::value::Value;
55 use trans::Disr;
56 use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
57 use rustc_front::hir;
58
59 use syntax::codemap::DUMMY_SP;
60 use syntax::errors;
61 use syntax::ptr::P;
62
63 use std::cmp;
64
65 #[derive(Debug)]
66 pub enum CalleeData {
67     /// Constructor for enum variant/tuple-like-struct.
68     NamedTupleConstructor(Disr),
69
70     /// Function pointer.
71     Fn(ValueRef),
72
73     Intrinsic,
74
75     /// Trait object found in the vtable at that index.
76     Virtual(usize)
77 }
78
79 #[derive(Debug)]
80 pub struct Callee<'tcx> {
81     pub data: CalleeData,
82     pub ty: Ty<'tcx>
83 }
84
85 impl<'tcx> Callee<'tcx> {
86     /// Function pointer.
87     pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
88         Callee {
89             data: Fn(datum.val),
90             ty: datum.ty
91         }
92     }
93
94     /// Trait or impl method call.
95     pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
96                              method_call: ty::MethodCall)
97                              -> Callee<'tcx> {
98         let method = bcx.tcx().tables.borrow().method_map[&method_call];
99         Callee::method(bcx, method)
100     }
101
102     /// Trait or impl method.
103     pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
104                         method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
105         let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
106         Callee::def(bcx.ccx(), method.def_id, substs)
107     }
108
109     /// Function or method definition.
110     pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
111                    def_id: DefId,
112                    substs: &'tcx subst::Substs<'tcx>)
113                    -> Callee<'tcx> {
114         let tcx = ccx.tcx();
115
116         if substs.self_ty().is_some() {
117             // Only trait methods can have a Self parameter.
118             return Callee::trait_method(ccx, def_id, substs);
119         }
120
121         let maybe_node_id = inline::get_local_instance(ccx, def_id)
122             .and_then(|def_id| tcx.map.as_local_node_id(def_id));
123         let maybe_ast_node = maybe_node_id.and_then(|node_id| {
124             tcx.map.find(node_id)
125         });
126
127         let data = match maybe_ast_node {
128             Some(hir_map::NodeStructCtor(_)) => {
129                 NamedTupleConstructor(Disr(0))
130             }
131             Some(hir_map::NodeVariant(_)) => {
132                 let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
133                 NamedTupleConstructor(Disr::from(vinfo.disr_val))
134             }
135             Some(hir_map::NodeForeignItem(fi)) if {
136                 let abi = tcx.map.get_foreign_abi(fi.id);
137                 abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
138             } => Intrinsic,
139
140             _ => return Callee::ptr(get_fn(ccx, def_id, substs))
141         };
142
143         Callee {
144             data: data,
145             ty: def_ty(tcx, def_id, substs)
146         }
147     }
148
149     /// Trait method, which has to be resolved to an impl method.
150     pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
151                             def_id: DefId,
152                             substs: &'tcx subst::Substs<'tcx>)
153                             -> Callee<'tcx> {
154         let tcx = ccx.tcx();
155
156         let method_item = tcx.impl_or_trait_item(def_id);
157         let trait_id = method_item.container().id();
158         let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
159         match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
160             traits::VtableImpl(vtable_impl) => {
161                 let impl_did = vtable_impl.impl_def_id;
162                 let mname = tcx.item_name(def_id);
163                 // create a concatenated set of substitutions which includes
164                 // those from the impl and those from the method:
165                 let impl_substs = vtable_impl.substs.with_method_from(&substs);
166                 let substs = tcx.mk_substs(impl_substs);
167                 let mth = meth::get_impl_method(tcx, impl_did, substs, mname);
168
169                 // Translate the function, bypassing Callee::def.
170                 // That is because default methods have the same ID as the
171                 // trait method used to look up the impl method that ended
172                 // up here, so calling Callee::def would infinitely recurse.
173                 Callee::ptr(get_fn(ccx, mth.method.def_id, mth.substs))
174             }
175             traits::VtableClosure(vtable_closure) => {
176                 // The substitutions should have no type parameters remaining
177                 // after passing through fulfill_obligation
178                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
179                 let llfn = closure::trans_closure_method(ccx,
180                                                          vtable_closure.closure_def_id,
181                                                          vtable_closure.substs,
182                                                          trait_closure_kind);
183
184                 let method_ty = def_ty(tcx, def_id, substs);
185                 let fn_ptr_ty = match method_ty.sty {
186                     ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
187                     _ => unreachable!("expected fn item type, found {}",
188                                       method_ty)
189                 };
190                 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
191             }
192             traits::VtableFnPointer(fn_ty) => {
193                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
194                 let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
195
196                 let method_ty = def_ty(tcx, def_id, substs);
197                 let fn_ptr_ty = match method_ty.sty {
198                     ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
199                     _ => unreachable!("expected fn item type, found {}",
200                                       method_ty)
201                 };
202                 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
203             }
204             traits::VtableObject(ref data) => {
205                 Callee {
206                     data: Virtual(traits::get_vtable_index_of_object_method(
207                         tcx, data, def_id)),
208                     ty: def_ty(tcx, def_id, substs)
209                 }
210             }
211             vtable => {
212                 unreachable!("resolved vtable bad vtable {:?} in trans", vtable);
213             }
214         }
215     }
216
217     /// Get the abi::FnType for a direct call. Mainly deals with the fact
218     /// that a Virtual call doesn't take the vtable, like its shim does.
219     /// The extra argument types are for variadic (extern "C") functions.
220     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
221                               extra_args: &[Ty<'tcx>]) -> FnType {
222         let abi = self.ty.fn_abi();
223         let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
224         let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
225         let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
226         if let Virtual(_) = self.data {
227             // Don't pass the vtable, it's not an argument of the virtual fn.
228             fn_ty.args[1].ignore();
229         }
230         fn_ty.adjust_for_abi(ccx, abi, &sig);
231         fn_ty
232     }
233
234     /// This behemoth of a function translates function calls. Unfortunately, in
235     /// order to generate more efficient LLVM output at -O0, it has quite a complex
236     /// signature (refactoring this into two functions seems like a good idea).
237     ///
238     /// In particular, for lang items, it is invoked with a dest of None, and in
239     /// that case the return value contains the result of the fn. The lang item must
240     /// not return a structural type or else all heck breaks loose.
241     ///
242     /// For non-lang items, `dest` is always Some, and hence the result is written
243     /// into memory somewhere. Nonetheless we return the actual return value of the
244     /// function.
245     pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
246                           debug_loc: DebugLoc,
247                           args: CallArgs<'a, 'tcx>,
248                           dest: Option<expr::Dest>)
249                           -> Result<'blk, 'tcx> {
250         trans_call_inner(bcx, debug_loc, self, args, dest)
251     }
252
253     /// Turn the callee into a function pointer.
254     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
255                      -> Datum<'tcx, Rvalue> {
256         let fn_ptr_ty = match self.ty.sty {
257             ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
258             _ => self.ty
259         };
260         match self.data {
261             Fn(llfn) => {
262                 immediate_rvalue(llfn, fn_ptr_ty)
263             }
264             Virtual(idx) => {
265                 let llfn = meth::trans_object_shim(ccx, self.ty, idx);
266                 immediate_rvalue(llfn, fn_ptr_ty)
267             }
268             NamedTupleConstructor(_) => match self.ty.sty {
269                 ty::TyFnDef(def_id, substs, _) => {
270                     return get_fn(ccx, def_id, substs);
271                 }
272                 _ => unreachable!("expected fn item type, found {}", self.ty)
273             },
274             Intrinsic => unreachable!("intrinsic {} getting reified", self.ty)
275         }
276     }
277 }
278
279 /// Given a DefId and some Substs, produces the monomorphic item type.
280 fn def_ty<'tcx>(tcx: &TyCtxt<'tcx>,
281                 def_id: DefId,
282                 substs: &'tcx subst::Substs<'tcx>)
283                 -> Ty<'tcx> {
284     let ty = tcx.lookup_item_type(def_id).ty;
285     monomorphize::apply_param_substs(tcx, substs, &ty)
286 }
287
288 /// Translates an adapter that implements the `Fn` trait for a fn
289 /// pointer. This is basically the equivalent of something like:
290 ///
291 /// ```
292 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
293 ///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
294 ///         (*self)(args.0)
295 ///     }
296 /// }
297 /// ```
298 ///
299 /// but for the bare function type given.
300 pub fn trans_fn_pointer_shim<'a, 'tcx>(
301     ccx: &'a CrateContext<'a, 'tcx>,
302     closure_kind: ty::ClosureKind,
303     bare_fn_ty: Ty<'tcx>)
304     -> ValueRef
305 {
306     let _icx = push_ctxt("trans_fn_pointer_shim");
307     let tcx = ccx.tcx();
308
309     // Normalize the type for better caching.
310     let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
311
312     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
313     let is_by_ref = match closure_kind {
314         ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
315         ty::ClosureKind::FnOnce => false,
316     };
317
318     let llfnpointer = match bare_fn_ty.sty {
319         ty::TyFnDef(def_id, substs, _) => {
320             // Function definitions have to be turned into a pointer.
321             let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val;
322             if !is_by_ref {
323                 // A by-value fn item is ignored, so the shim has
324                 // the same signature as the original function.
325                 return llfn;
326             }
327             Some(llfn)
328         }
329         _ => None
330     };
331
332     let bare_fn_ty_maybe_ref = if is_by_ref {
333         tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
334     } else {
335         bare_fn_ty
336     };
337
338     // Check if we already trans'd this shim.
339     match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
340         Some(&llval) => { return llval; }
341         None => { }
342     }
343
344     debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
345            bare_fn_ty);
346
347     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
348     // which is the fn pointer, and `args`, which is the arguments tuple.
349     let sig = match bare_fn_ty.sty {
350         ty::TyFnDef(_, _,
351                     &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
352                                     abi: Abi::Rust,
353                                     ref sig }) |
354         ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
355                                     abi: Abi::Rust,
356                                     ref sig }) => sig,
357
358         _ => {
359             tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
360                                     bare_fn_ty));
361         }
362     };
363     let sig = tcx.erase_late_bound_regions(sig);
364     let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
365     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
366     let sig = ty::FnSig {
367         inputs: vec![bare_fn_ty_maybe_ref,
368                      tuple_input_ty],
369         output: sig.output,
370         variadic: false
371     };
372     let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
373     let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
374         unsafety: hir::Unsafety::Normal,
375         abi: Abi::RustCall,
376         sig: ty::Binder(sig)
377     });
378     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
379
380     //
381     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
382                                                                    "fn_pointer_shim");
383     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
384
385     //
386     let empty_substs = tcx.mk_substs(Substs::empty());
387     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
388     block_arena = TypedArena::new();
389     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &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             _ => unreachable!("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         _ => unreachable!("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, id, ty, 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             ccx.sess().bug(&format!("get_fn: unexpected variant: {:?}", variant))
539         }
540     };
541
542     let llfn = declare::declare_fn(ccx, &sym, ty);
543     attributes::from_fn_attrs(ccx, attrs, llfn);
544     if let Some(id) = local_item {
545         // FIXME(eddyb) Doubt all extern fn should allow unwinding.
546         attributes::unwind(llfn, true);
547         ccx.item_symbols().borrow_mut().insert(id, sym);
548     }
549
550     // This is subtle and surprising, but sometimes we have to bitcast
551     // the resulting fn pointer.  The reason has to do with external
552     // functions.  If you have two crates that both bind the same C
553     // library, they may not use precisely the same types: for
554     // example, they will probably each declare their own structs,
555     // which are distinct types from LLVM's point of view (nominal
556     // types).
557     //
558     // Now, if those two crates are linked into an application, and
559     // they contain inlined code, you can wind up with a situation
560     // where both of those functions wind up being loaded into this
561     // application simultaneously. In that case, the same function
562     // (from LLVM's point of view) requires two types. But of course
563     // LLVM won't allow one function to have two types.
564     //
565     // What we currently do, therefore, is declare the function with
566     // one of the two types (whichever happens to come first) and then
567     // bitcast as needed when the function is referenced to make sure
568     // it has the type we expect.
569     //
570     // This can occur on either a crate-local or crate-external
571     // reference. It also occurs when testing libcore and in some
572     // other weird situations. Annoying.
573     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
574     let llfn = if common::val_ty(llfn) != llptrty {
575         debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
576         consts::ptrcast(llfn, llptrty)
577     } else {
578         debug!("get_fn: not casting pointer!");
579         llfn
580     };
581
582     ccx.instances().borrow_mut().insert(instance, llfn);
583
584     immediate_rvalue(llfn, fn_ptr_ty)
585 }
586
587 // ______________________________________________________________________
588 // Translating calls
589
590 fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
591                                     debug_loc: DebugLoc,
592                                     callee: Callee<'tcx>,
593                                     args: CallArgs<'a, 'tcx>,
594                                     dest: Option<expr::Dest>)
595                                     -> Result<'blk, 'tcx> {
596     // Introduce a temporary cleanup scope that will contain cleanups
597     // for the arguments while they are being evaluated. The purpose
598     // this cleanup is to ensure that, should a panic occur while
599     // evaluating argument N, the values for arguments 0...N-1 are all
600     // cleaned up. If no panic occurs, the values are handed off to
601     // the callee, and hence none of the cleanups in this temporary
602     // scope will ever execute.
603     let fcx = bcx.fcx;
604     let ccx = fcx.ccx;
605
606     let abi = callee.ty.fn_abi();
607     let sig = callee.ty.fn_sig();
608     let output = bcx.tcx().erase_late_bound_regions(&sig.output());
609     let output = infer::normalize_associated_type(bcx.tcx(), &output);
610
611     let extra_args = match args {
612         ArgExprs(args) if abi != Abi::RustCall => {
613             args[sig.0.inputs.len()..].iter().map(|expr| {
614                 common::expr_ty_adjusted(bcx, expr)
615             }).collect()
616         }
617         _ => vec![]
618     };
619     let fn_ty = callee.direct_fn_type(ccx, &extra_args);
620
621     let mut callee = match callee.data {
622         Intrinsic => {
623             assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
624             assert!(dest.is_some());
625
626             return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
627                                                    args, dest.unwrap(),
628                                                    debug_loc);
629         }
630         NamedTupleConstructor(disr) => {
631             assert!(dest.is_some());
632
633             return base::trans_named_tuple_constructor(bcx,
634                                                        callee.ty,
635                                                        disr,
636                                                        args,
637                                                        dest.unwrap(),
638                                                        debug_loc);
639         }
640         f => f
641     };
642
643     // Generate a location to store the result. If the user does
644     // not care about the result, just make a stack slot.
645     let opt_llretslot = dest.and_then(|dest| match dest {
646         expr::SaveIn(dst) => Some(dst),
647         expr::Ignore => {
648             let needs_drop = || match output {
649                 ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
650                 ty::FnDiverging => false
651             };
652             if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
653                 // Push the out-pointer if we use an out-pointer for this
654                 // return type, otherwise push "undef".
655                 if fn_ty.ret.is_ignore() {
656                     Some(C_undef(fn_ty.ret.original_ty.ptr_to()))
657                 } else {
658                     let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
659                     call_lifetime_start(bcx, llresult);
660                     Some(llresult)
661                 }
662             } else {
663                 None
664             }
665         }
666     });
667
668     // If there no destination, return must be direct, with no cast.
669     if opt_llretslot.is_none() {
670         assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
671     }
672
673     let mut llargs = Vec::new();
674
675     if fn_ty.ret.is_indirect() {
676         let mut llretslot = opt_llretslot.unwrap();
677         if let Some(ty) = fn_ty.ret.cast {
678             llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
679         }
680         llargs.push(llretslot);
681     }
682
683     let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
684     bcx = trans_args(bcx, abi, &fn_ty, &mut callee, args, &mut llargs,
685                      cleanup::CustomScope(arg_cleanup_scope));
686     fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
687
688     let llfn = match callee {
689         Fn(f) => f,
690         _ => unreachable!("expected fn pointer callee, found {:?}", callee)
691     };
692
693     let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
694     if !bcx.unreachable.get() {
695         fn_ty.apply_attrs_callsite(llret);
696     }
697
698     // If the function we just called does not use an outpointer,
699     // store the result into the rust outpointer. Cast the outpointer
700     // type to match because some ABIs will use a different type than
701     // the Rust type. e.g., a {u32,u32} struct could be returned as
702     // u64.
703     if !fn_ty.ret.is_ignore() && !fn_ty.ret.is_indirect() {
704         if let Some(llforeign_ret_ty) = fn_ty.ret.cast {
705             let llrust_ret_ty = fn_ty.ret.original_ty;
706             let llretslot = opt_llretslot.unwrap();
707
708             // The actual return type is a struct, but the ABI
709             // adaptation code has cast it into some scalar type.  The
710             // code that follows is the only reliable way I have
711             // found to do a transform like i64 -> {i32,i32}.
712             // Basically we dump the data onto the stack then memcpy it.
713             //
714             // Other approaches I tried:
715             // - Casting rust ret pointer to the foreign type and using Store
716             //   is (a) unsafe if size of foreign type > size of rust type and
717             //   (b) runs afoul of strict aliasing rules, yielding invalid
718             //   assembly under -O (specifically, the store gets removed).
719             // - Truncating foreign type to correct integral type and then
720             //   bitcasting to the struct type yields invalid cast errors.
721             let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
722             base::call_lifetime_start(bcx, llscratch);
723             Store(bcx, llret, llscratch);
724             let llscratch_i8 = PointerCast(bcx, llscratch, Type::i8(ccx).ptr_to());
725             let llretptr_i8 = PointerCast(bcx, llretslot, Type::i8(ccx).ptr_to());
726             let llrust_size = llsize_of_store(ccx, llrust_ret_ty);
727             let llforeign_align = llalign_of_min(ccx, llforeign_ret_ty);
728             let llrust_align = llalign_of_min(ccx, llrust_ret_ty);
729             let llalign = cmp::min(llforeign_align, llrust_align);
730             debug!("llrust_size={}", llrust_size);
731
732             if !bcx.unreachable.get() {
733                 base::call_memcpy(&B(bcx), llretptr_i8, llscratch_i8,
734                                   C_uint(ccx, llrust_size), llalign as u32);
735             }
736             base::call_lifetime_end(bcx, llscratch);
737         } else if let Some(llretslot) = opt_llretslot {
738             base::store_ty(bcx, llret, llretslot, output.unwrap());
739         }
740     }
741
742     fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
743
744     // If the caller doesn't care about the result of this fn call,
745     // drop the temporary slot we made.
746     match (dest, opt_llretslot, output) {
747         (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
748             // drop the value if it is not being saved.
749             bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc);
750             call_lifetime_end(bcx, llretslot);
751         }
752         _ => {}
753     }
754
755     if output == ty::FnDiverging {
756         Unreachable(bcx);
757     }
758
759     Result::new(bcx, llret)
760 }
761
762 pub enum CallArgs<'a, 'tcx> {
763     /// Supply value of arguments as a list of expressions that must be
764     /// translated. This is used in the common case of `foo(bar, qux)`.
765     ArgExprs(&'a [P<hir::Expr>]),
766
767     /// Supply value of arguments as a list of LLVM value refs; frequently
768     /// used with lang items and so forth, when the argument is an internal
769     /// value.
770     ArgVals(&'a [ValueRef]),
771
772     /// For overloaded operators: `(lhs, Option(rhs))`.
773     /// `lhs` is the left-hand-side and `rhs` is the datum
774     /// of the right-hand-side argument (if any).
775     ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
776
777     /// Supply value of arguments as a list of expressions that must be
778     /// translated, for overloaded call operators.
779     ArgOverloadedCall(Vec<&'a hir::Expr>),
780 }
781
782 fn trans_args_under_call_abi<'blk, 'tcx>(
783                              mut bcx: Block<'blk, 'tcx>,
784                              arg_exprs: &[P<hir::Expr>],
785                              callee: &mut CalleeData,
786                              fn_ty: &FnType,
787                              llargs: &mut Vec<ValueRef>,
788                              arg_cleanup_scope: cleanup::ScopeId)
789                              -> Block<'blk, 'tcx>
790 {
791     let mut arg_idx = 0;
792
793     // Translate the `self` argument first.
794     let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
795     bcx = trans_arg_datum(bcx,
796                           arg_datum,
797                           callee, fn_ty, &mut arg_idx,
798                           arg_cleanup_scope,
799                           llargs);
800
801     // Now untuple the rest of the arguments.
802     let tuple_expr = &arg_exprs[1];
803     let tuple_type = common::node_id_type(bcx, tuple_expr.id);
804
805     match tuple_type.sty {
806         ty::TyTuple(ref field_types) => {
807             let tuple_datum = unpack_datum!(bcx,
808                                             expr::trans(bcx, &tuple_expr));
809             let tuple_lvalue_datum =
810                 unpack_datum!(bcx,
811                               tuple_datum.to_lvalue_datum(bcx,
812                                                           "args",
813                                                           tuple_expr.id));
814             let repr = adt::represent_type(bcx.ccx(), tuple_type);
815             let repr_ptr = &repr;
816             for (i, field_type) in field_types.iter().enumerate() {
817                 let arg_datum = tuple_lvalue_datum.get_element(
818                     bcx,
819                     field_type,
820                     |srcval| {
821                         adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
822                     }).to_expr_datum();
823                 bcx = trans_arg_datum(bcx,
824                                       arg_datum,
825                                       callee, fn_ty, &mut arg_idx,
826                                       arg_cleanup_scope,
827                                       llargs);
828             }
829         }
830         _ => {
831             bcx.sess().span_bug(tuple_expr.span,
832                                 "argument to `.call()` wasn't a tuple?!")
833         }
834     };
835
836     bcx
837 }
838
839 pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
840                                   abi: Abi,
841                                   fn_ty: &FnType,
842                                   callee: &mut CalleeData,
843                                   args: CallArgs<'a, 'tcx>,
844                                   llargs: &mut Vec<ValueRef>,
845                                   arg_cleanup_scope: cleanup::ScopeId)
846                                   -> Block<'blk, 'tcx> {
847     debug!("trans_args(abi={})", abi);
848
849     let _icx = push_ctxt("trans_args");
850
851     let mut bcx = bcx;
852     let mut arg_idx = 0;
853
854     // First we figure out the caller's view of the types of the arguments.
855     // This will be needed if this is a generic call, because the callee has
856     // to cast her view of the arguments to the caller's view.
857     match args {
858         ArgExprs(arg_exprs) => {
859             if abi == Abi::RustCall {
860                 // This is only used for direct calls to the `call`,
861                 // `call_mut` or `call_once` functions.
862                 return trans_args_under_call_abi(bcx,
863                                                  arg_exprs, callee, fn_ty,
864                                                  llargs,
865                                                  arg_cleanup_scope)
866             }
867
868             for arg_expr in arg_exprs {
869                 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
870                 bcx = trans_arg_datum(bcx,
871                                       arg_datum,
872                                       callee, fn_ty, &mut arg_idx,
873                                       arg_cleanup_scope,
874                                       llargs);
875             }
876         }
877         ArgOverloadedCall(arg_exprs) => {
878             for expr in arg_exprs {
879                 let arg_datum =
880                     unpack_datum!(bcx, expr::trans(bcx, expr));
881                 bcx = trans_arg_datum(bcx,
882                                       arg_datum,
883                                       callee, fn_ty, &mut arg_idx,
884                                       arg_cleanup_scope,
885                                       llargs);
886             }
887         }
888         ArgOverloadedOp(lhs, rhs) => {
889             bcx = trans_arg_datum(bcx, lhs,
890                                   callee, fn_ty, &mut arg_idx,
891                                   arg_cleanup_scope,
892                                   llargs);
893
894             if let Some(rhs) = rhs {
895                 bcx = trans_arg_datum(bcx, rhs,
896                                       callee, fn_ty, &mut arg_idx,
897                                       arg_cleanup_scope,
898                                       llargs);
899             }
900         }
901         ArgVals(vs) => {
902             match *callee {
903                 Virtual(idx) => {
904                     llargs.push(vs[0]);
905
906                     let fn_ptr = meth::get_virtual_method(bcx, vs[1], idx);
907                     let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
908                     *callee = Fn(PointerCast(bcx, fn_ptr, llty));
909                     llargs.extend_from_slice(&vs[2..]);
910                 }
911                 _ => llargs.extend_from_slice(vs)
912             }
913         }
914     }
915
916     bcx
917 }
918
919 fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
920                                arg_datum: Datum<'tcx, Expr>,
921                                callee: &mut CalleeData,
922                                fn_ty: &FnType,
923                                next_idx: &mut usize,
924                                arg_cleanup_scope: cleanup::ScopeId,
925                                llargs: &mut Vec<ValueRef>)
926                                -> Block<'blk, 'tcx> {
927     let _icx = push_ctxt("trans_arg_datum");
928     let mut bcx = bcx;
929
930     debug!("trans_arg_datum({:?})", arg_datum);
931
932     let arg = &fn_ty.args[*next_idx];
933     *next_idx += 1;
934
935     // Fill padding with undef value, where applicable.
936     if let Some(ty) = arg.pad {
937         llargs.push(C_undef(ty));
938     }
939
940     // Determine whether we want a by-ref datum even if not appropriate.
941     let want_by_ref = arg.is_indirect() || arg.cast.is_some();
942
943     let fat_ptr = common::type_is_fat_ptr(bcx.tcx(), arg_datum.ty);
944     let (by_ref, val) = if fat_ptr && !bcx.fcx.type_needs_drop(arg_datum.ty) {
945         (true, arg_datum.val)
946     } else {
947         // Make this an rvalue, since we are going to be
948         // passing ownership.
949         let arg_datum = unpack_datum!(
950             bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
951
952         // Now that arg_datum is owned, get it into the appropriate
953         // mode (ref vs value).
954         let arg_datum = unpack_datum!(bcx, if want_by_ref {
955             arg_datum.to_ref_datum(bcx)
956         } else {
957             arg_datum.to_appropriate_datum(bcx)
958         });
959
960         // Technically, ownership of val passes to the callee.
961         // However, we must cleanup should we panic before the
962         // callee is actually invoked.
963         (arg_datum.kind.is_by_ref(),
964          arg_datum.add_clean(bcx.fcx, arg_cleanup_scope))
965     };
966
967     if arg.is_ignore() {
968         return bcx;
969     }
970
971     debug!("--- trans_arg_datum passing {:?}", Value(val));
972
973     if fat_ptr {
974         // Fat pointers should be passed without any transformations.
975         assert!(!arg.is_indirect() && arg.cast.is_none());
976         llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
977
978         let info_arg = &fn_ty.args[*next_idx];
979         *next_idx += 1;
980         assert!(!info_arg.is_indirect() && info_arg.cast.is_none());
981         let info = Load(bcx, expr::get_meta(bcx, val));
982
983         if let Virtual(idx) = *callee {
984             // We have to grab the fn pointer from the vtable when
985             // handling the first argument, ensure that here.
986             assert_eq!(*next_idx, 2);
987             assert!(info_arg.is_ignore());
988             let fn_ptr = meth::get_virtual_method(bcx, info, idx);
989             let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
990             *callee = Fn(PointerCast(bcx, fn_ptr, llty));
991         } else {
992             assert!(!info_arg.is_ignore());
993             llargs.push(info);
994         }
995         return bcx;
996     }
997
998     let mut val = val;
999     if by_ref && !arg.is_indirect() {
1000         // Have to load the argument, maybe while casting it.
1001         if arg.original_ty == Type::i1(bcx.ccx()) {
1002             // We store bools as i8 so we need to truncate to i1.
1003             val = LoadRangeAssert(bcx, val, 0, 2, llvm::False);
1004             val = Trunc(bcx, val, arg.original_ty);
1005         } else if let Some(ty) = arg.cast {
1006             val = Load(bcx, PointerCast(bcx, val, ty.ptr_to()));
1007             if !bcx.unreachable.get() {
1008                 let llalign = llalign_of_min(bcx.ccx(), arg.ty);
1009                 unsafe {
1010                     llvm::LLVMSetAlignment(val, llalign);
1011                 }
1012             }
1013         } else {
1014             val = Load(bcx, val);
1015         }
1016     }
1017
1018     llargs.push(val);
1019     bcx
1020 }