]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/callee.rs
Autoderef in librustc_trans
[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::AutorefArg::*;
18 pub use self::CalleeData::*;
19 pub use self::CallArgs::*;
20
21 use arena::TypedArena;
22 use back::link;
23 use llvm::{self, ValueRef, get_params};
24 use middle::cstore::LOCAL_CRATE;
25 use middle::def::Def;
26 use middle::def_id::DefId;
27 use middle::infer;
28 use middle::subst;
29 use middle::subst::{Substs};
30 use rustc::front::map as hir_map;
31 use trans::adt;
32 use trans::base;
33 use trans::base::*;
34 use trans::build::*;
35 use trans::callee;
36 use trans::cleanup;
37 use trans::cleanup::CleanupMethods;
38 use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
39                     ExprOrMethodCall, FunctionContext, MethodCallKey};
40 use trans::consts;
41 use trans::datum::*;
42 use trans::debuginfo::{DebugLoc, ToDebugLoc};
43 use trans::declare;
44 use trans::expr;
45 use trans::glue;
46 use trans::inline;
47 use trans::foreign;
48 use trans::intrinsic;
49 use trans::meth;
50 use trans::monomorphize;
51 use trans::type_::Type;
52 use trans::type_of;
53 use trans::Disr;
54 use middle::ty::{self, Ty, TypeFoldable};
55 use middle::ty::MethodCall;
56 use rustc_front::hir;
57
58 use syntax::abi::Abi;
59 use syntax::ast;
60 use syntax::errors;
61 use syntax::ptr::P;
62
63 #[derive(Copy, Clone)]
64 pub struct MethodData {
65     pub llfn: ValueRef,
66     pub llself: ValueRef,
67 }
68
69 pub enum CalleeData<'tcx> {
70     // Constructor for enum variant/tuple-like-struct
71     // i.e. Some, Ok
72     NamedTupleConstructor(Disr),
73
74     // Represents a (possibly monomorphized) top-level fn item or method
75     // item. Note that this is just the fn-ptr and is not a Rust closure
76     // value (which is a pair).
77     Fn(/* llfn */ ValueRef),
78
79     Intrinsic(ast::NodeId, subst::Substs<'tcx>),
80
81     TraitItem(MethodData)
82 }
83
84 pub struct Callee<'blk, 'tcx: 'blk> {
85     pub bcx: Block<'blk, 'tcx>,
86     pub data: CalleeData<'tcx>,
87     pub ty: Ty<'tcx>
88 }
89
90 fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
91                      -> Callee<'blk, 'tcx> {
92     let _icx = push_ctxt("trans_callee");
93     debug!("callee::trans(expr={:?})", expr);
94
95     // pick out special kinds of expressions that can be called:
96     match expr.node {
97         hir::ExprPath(..) => {
98             return trans_def(bcx, bcx.def(expr.id), expr);
99         }
100         _ => {}
101     }
102
103     // any other expressions are closures:
104     return datum_callee(bcx, expr);
105
106     fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
107                                 -> Callee<'blk, 'tcx> {
108         let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
109         match datum.ty.sty {
110             ty::TyBareFn(..) => {
111                 Callee {
112                     bcx: bcx,
113                     ty: datum.ty,
114                     data: Fn(datum.to_llscalarish(bcx))
115                 }
116             }
117             _ => {
118                 bcx.tcx().sess.span_bug(
119                     expr.span,
120                     &format!("type of callee is neither bare-fn nor closure: {}",
121                              datum.ty));
122             }
123         }
124     }
125
126     fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
127                              -> Callee<'blk, 'tcx> {
128         Callee {
129             bcx: bcx,
130             data: Fn(datum.val),
131             ty: datum.ty
132         }
133     }
134
135     fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
136                              def: Def,
137                              ref_expr: &hir::Expr)
138                              -> Callee<'blk, 'tcx> {
139         debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
140         let expr_ty = common::node_id_type(bcx, ref_expr.id);
141         match def {
142             Def::Fn(did) if {
143                 let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
144                 let maybe_ast_node = maybe_def_id.and_then(|def_id| {
145                     let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
146                     bcx.tcx().map.find(node_id)
147                 });
148                 match maybe_ast_node {
149                     Some(hir_map::NodeStructCtor(_)) => true,
150                     _ => false
151                 }
152             } => {
153                 Callee {
154                     bcx: bcx,
155                     data: NamedTupleConstructor(Disr(0)),
156                     ty: expr_ty
157                 }
158             }
159             Def::Fn(did) if match expr_ty.sty {
160                 ty::TyBareFn(_, ref f) => f.abi == Abi::RustIntrinsic ||
161                                           f.abi == Abi::PlatformIntrinsic,
162                 _ => false
163             } => {
164                 let substs = common::node_id_substs(bcx.ccx(),
165                                                     ExprId(ref_expr.id),
166                                                     bcx.fcx.param_substs);
167                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
168                 let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
169                 Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
170             }
171             Def::Fn(did) => {
172                 fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
173                                             bcx.fcx.param_substs))
174             }
175             Def::Method(meth_did) => {
176                 let method_item = bcx.tcx().impl_or_trait_item(meth_did);
177                 let fn_datum = match method_item.container() {
178                     ty::ImplContainer(_) => {
179                         trans_fn_ref(bcx.ccx(), meth_did,
180                                      ExprId(ref_expr.id),
181                                      bcx.fcx.param_substs)
182                     }
183                     ty::TraitContainer(trait_did) => {
184                         meth::trans_static_method_callee(bcx.ccx(),
185                                                          meth_did,
186                                                          trait_did,
187                                                          ref_expr.id,
188                                                          bcx.fcx.param_substs)
189                     }
190                 };
191                 fn_callee(bcx, fn_datum)
192             }
193             Def::Variant(tid, vid) => {
194                 let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
195                 assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
196
197                 Callee {
198                     bcx: bcx,
199                     data: NamedTupleConstructor(Disr::from(vinfo.disr_val)),
200                     ty: expr_ty
201                 }
202             }
203             Def::Struct(..) => {
204                 Callee {
205                     bcx: bcx,
206                     data: NamedTupleConstructor(Disr(0)),
207                     ty: expr_ty
208                 }
209             }
210             Def::Static(..) |
211             Def::Const(..) |
212             Def::AssociatedConst(..) |
213             Def::Local(..) |
214             Def::Upvar(..) => {
215                 datum_callee(bcx, ref_expr)
216             }
217             Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
218             Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
219             Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
220             Def::SelfTy(..) | Def::Err => {
221                 bcx.tcx().sess.span_bug(
222                     ref_expr.span,
223                     &format!("cannot translate def {:?} \
224                              to a callable thing!", def));
225             }
226         }
227     }
228 }
229
230 /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
231 /// pointer. This may require monomorphization or inlining.
232 pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
233                               def_id: DefId,
234                               node: ExprOrMethodCall,
235                               param_substs: &'tcx subst::Substs<'tcx>)
236                               -> Datum<'tcx, Rvalue> {
237     let _icx = push_ctxt("trans_fn_ref");
238
239     let substs = common::node_id_substs(ccx, node, param_substs);
240     debug!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
241            def_id,
242            node,
243            substs);
244     trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
245 }
246
247 /// Translates an adapter that implements the `Fn` trait for a fn
248 /// pointer. This is basically the equivalent of something like:
249 ///
250 /// ```
251 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
252 ///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
253 ///         (*self)(args.0)
254 ///     }
255 /// }
256 /// ```
257 ///
258 /// but for the bare function type given.
259 pub fn trans_fn_pointer_shim<'a, 'tcx>(
260     ccx: &'a CrateContext<'a, 'tcx>,
261     closure_kind: ty::ClosureKind,
262     bare_fn_ty: Ty<'tcx>)
263     -> ValueRef
264 {
265     let _icx = push_ctxt("trans_fn_pointer_shim");
266     let tcx = ccx.tcx();
267
268     // Normalize the type for better caching.
269     let bare_fn_ty = tcx.erase_regions(&bare_fn_ty);
270
271     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
272     let is_by_ref = match closure_kind {
273         ty::FnClosureKind | ty::FnMutClosureKind => true,
274         ty::FnOnceClosureKind => false,
275     };
276     let bare_fn_ty_maybe_ref = if is_by_ref {
277         tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty)
278     } else {
279         bare_fn_ty
280     };
281
282     // Check if we already trans'd this shim.
283     match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
284         Some(&llval) => { return llval; }
285         None => { }
286     }
287
288     debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
289            bare_fn_ty);
290
291     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
292     // which is the fn pointer, and `args`, which is the arguments tuple.
293     let (opt_def_id, sig) =
294         match bare_fn_ty.sty {
295             ty::TyBareFn(opt_def_id,
296                            &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
297                                            abi: Abi::Rust,
298                                            ref sig }) => {
299                 (opt_def_id, sig)
300             }
301
302             _ => {
303                 tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
304                                       bare_fn_ty));
305             }
306         };
307     let sig = tcx.erase_late_bound_regions(sig);
308     let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
309     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
310     let tuple_fn_ty = tcx.mk_fn(opt_def_id,
311         tcx.mk_bare_fn(ty::BareFnTy {
312             unsafety: hir::Unsafety::Normal,
313             abi: Abi::RustCall,
314             sig: ty::Binder(ty::FnSig {
315                 inputs: vec![bare_fn_ty_maybe_ref,
316                              tuple_input_ty],
317                 output: sig.output,
318                 variadic: false
319             })}));
320     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
321
322     //
323     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
324                                                                    "fn_pointer_shim");
325     let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty);
326
327     //
328     let empty_substs = tcx.mk_substs(Substs::trans_empty());
329     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
330     block_arena = TypedArena::new();
331     fcx = new_fn_ctxt(ccx,
332                       llfn,
333                       ast::DUMMY_NODE_ID,
334                       false,
335                       sig.output,
336                       empty_substs,
337                       None,
338                       &block_arena);
339     let mut bcx = init_function(&fcx, false, sig.output);
340
341     let llargs = get_params(fcx.llfn);
342
343     let self_idx = fcx.arg_offset();
344     // the first argument (`self`) will be ptr to the fn pointer
345     let llfnpointer = if is_by_ref {
346         Load(bcx, llargs[self_idx])
347     } else {
348         llargs[self_idx]
349     };
350
351     assert!(!fcx.needs_ret_allocas);
352
353     let dest = fcx.llretslotptr.get().map(|_|
354         expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
355     );
356
357     bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
358         Callee {
359             bcx: bcx,
360             data: Fn(llfnpointer),
361             ty: bare_fn_ty
362         }
363     }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
364
365     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
366
367     ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
368
369     llfn
370 }
371
372 /// Translates a reference to a fn/method item, monomorphizing and
373 /// inlining as it goes.
374 ///
375 /// # Parameters
376 ///
377 /// - `ccx`: the crate context
378 /// - `def_id`: def id of the fn or method item being referenced
379 /// - `node`: node id of the reference to the fn/method, if applicable.
380 ///   This parameter may be zero; but, if so, the resulting value may not
381 ///   have the right type, so it must be cast before being used.
382 /// - `param_substs`: if the `node` is in a polymorphic function, these
383 ///   are the substitutions required to monomorphize its type
384 /// - `substs`: values for each of the fn/method's parameters
385 pub fn trans_fn_ref_with_substs<'a, 'tcx>(
386     ccx: &CrateContext<'a, 'tcx>,
387     def_id: DefId,
388     node: ExprOrMethodCall,
389     param_substs: &'tcx subst::Substs<'tcx>,
390     substs: subst::Substs<'tcx>)
391     -> Datum<'tcx, Rvalue>
392 {
393     let _icx = push_ctxt("trans_fn_ref_with_substs");
394     let tcx = ccx.tcx();
395
396     debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
397             param_substs={:?}, substs={:?})",
398            def_id,
399            node,
400            param_substs,
401            substs);
402
403     assert!(!substs.types.needs_infer());
404     assert!(!substs.types.has_escaping_regions());
405     let substs = substs.erase_regions();
406
407     // Check whether this fn has an inlined copy and, if so, redirect
408     // def_id to the local id of the inlined copy.
409     let def_id = inline::maybe_instantiate_inline(ccx, def_id);
410
411     fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
412         let node_id = match tcx.map.as_local_node_id(def_id) {
413             Some(n) => n,
414             None => { return false; }
415         };
416         let map_node = errors::expect(
417             &tcx.sess.diagnostic(),
418             tcx.map.find(node_id),
419             || "local item should be in ast map".to_string());
420
421         match map_node {
422             hir_map::NodeVariant(v) => {
423                 v.node.data.is_tuple()
424             }
425             hir_map::NodeStructCtor(_) => true,
426             _ => false
427         }
428     }
429     let must_monomorphise =
430         !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
431
432     debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
433            def_id, must_monomorphise);
434
435     // Create a monomorphic version of generic functions
436     if must_monomorphise {
437         // Should be either intra-crate or inlined.
438         assert_eq!(def_id.krate, LOCAL_CRATE);
439
440         let opt_ref_id = match node {
441             ExprId(id) => if id != 0 { Some(id) } else { None },
442             MethodCallKey(_) => None,
443         };
444
445         let substs = tcx.mk_substs(substs);
446         let (val, fn_ty, must_cast) =
447             monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id);
448         if must_cast && node != ExprId(0) {
449             // Monotype of the REFERENCE to the function (type params
450             // are subst'd)
451             let ref_ty = match node {
452                 ExprId(id) => tcx.node_id_to_type(id),
453                 MethodCallKey(method_call) => {
454                     tcx.tables.borrow().method_map[&method_call].ty
455                 }
456             };
457             let ref_ty = monomorphize::apply_param_substs(tcx,
458                                                           param_substs,
459                                                           &ref_ty);
460             let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
461             if llptrty != common::val_ty(val) {
462                 let val = consts::ptrcast(val, llptrty);
463                 return Datum::new(val, ref_ty, Rvalue::new(ByValue));
464             }
465         }
466         return Datum::new(val, fn_ty, Rvalue::new(ByValue));
467     }
468
469     // Type scheme of the function item (may have type params)
470     let fn_type_scheme = tcx.lookup_item_type(def_id);
471     let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty);
472
473     // Find the actual function pointer.
474     let mut val = {
475         if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
476             // Internal reference.
477             get_item_val(ccx, node_id)
478         } else {
479             // External reference.
480             trans_external_path(ccx, def_id, fn_type)
481         }
482     };
483
484     // This is subtle and surprising, but sometimes we have to bitcast
485     // the resulting fn pointer.  The reason has to do with external
486     // functions.  If you have two crates that both bind the same C
487     // library, they may not use precisely the same types: for
488     // example, they will probably each declare their own structs,
489     // which are distinct types from LLVM's point of view (nominal
490     // types).
491     //
492     // Now, if those two crates are linked into an application, and
493     // they contain inlined code, you can wind up with a situation
494     // where both of those functions wind up being loaded into this
495     // application simultaneously. In that case, the same function
496     // (from LLVM's point of view) requires two types. But of course
497     // LLVM won't allow one function to have two types.
498     //
499     // What we currently do, therefore, is declare the function with
500     // one of the two types (whichever happens to come first) and then
501     // bitcast as needed when the function is referenced to make sure
502     // it has the type we expect.
503     //
504     // This can occur on either a crate-local or crate-external
505     // reference. It also occurs when testing libcore and in some
506     // other weird situations. Annoying.
507     let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
508     let llptrty = llty.ptr_to();
509     if common::val_ty(val) != llptrty {
510         debug!("trans_fn_ref_with_substs(): casting pointer!");
511         val = consts::ptrcast(val, llptrty);
512     } else {
513         debug!("trans_fn_ref_with_substs(): not casting pointer!");
514     }
515
516     Datum::new(val, fn_type, Rvalue::new(ByValue))
517 }
518
519 // ______________________________________________________________________
520 // Translating calls
521
522 pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
523                                   call_expr: &hir::Expr,
524                                   f: &hir::Expr,
525                                   args: CallArgs<'a, 'tcx>,
526                                   dest: expr::Dest)
527                                   -> Block<'blk, 'tcx> {
528     let _icx = push_ctxt("trans_call");
529     trans_call_inner(bcx,
530                      call_expr.debug_loc(),
531                      |bcx, _| trans(bcx, f),
532                      args,
533                      Some(dest)).bcx
534 }
535
536 pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
537                                          call_expr: &hir::Expr,
538                                          rcvr: &hir::Expr,
539                                          args: CallArgs<'a, 'tcx>,
540                                          dest: expr::Dest)
541                                          -> Block<'blk, 'tcx> {
542     let _icx = push_ctxt("trans_method_call");
543     debug!("trans_method_call(call_expr={:?})", call_expr);
544     let method_call = MethodCall::expr(call_expr.id);
545     trans_call_inner(
546         bcx,
547         call_expr.debug_loc(),
548         |cx, arg_cleanup_scope| {
549             meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
550         },
551         args,
552         Some(dest)).bcx
553 }
554
555 pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
556                                    did: DefId,
557                                    args: &[ValueRef],
558                                    dest: Option<expr::Dest>,
559                                    debug_loc: DebugLoc)
560                                    -> Result<'blk, 'tcx> {
561     callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
562         let datum = trans_fn_ref_with_substs(bcx.ccx(),
563                                              did,
564                                              ExprId(0),
565                                              bcx.fcx.param_substs,
566                                              subst::Substs::trans_empty());
567         Callee {
568             bcx: bcx,
569             data: Fn(datum.val),
570             ty: datum.ty
571         }
572     }, ArgVals(args), dest)
573 }
574
575 /// This behemoth of a function translates function calls. Unfortunately, in
576 /// order to generate more efficient LLVM output at -O0, it has quite a complex
577 /// signature (refactoring this into two functions seems like a good idea).
578 ///
579 /// In particular, for lang items, it is invoked with a dest of None, and in
580 /// that case the return value contains the result of the fn. The lang item must
581 /// not return a structural type or else all heck breaks loose.
582 ///
583 /// For non-lang items, `dest` is always Some, and hence the result is written
584 /// into memory somewhere. Nonetheless we return the actual return value of the
585 /// function.
586 pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
587                                            debug_loc: DebugLoc,
588                                            get_callee: F,
589                                            args: CallArgs<'a, 'tcx>,
590                                            dest: Option<expr::Dest>)
591                                            -> Result<'blk, 'tcx> where
592     F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>,
593 {
594     // Introduce a temporary cleanup scope that will contain cleanups
595     // for the arguments while they are being evaluated. The purpose
596     // this cleanup is to ensure that, should a panic occur while
597     // evaluating argument N, the values for arguments 0...N-1 are all
598     // cleaned up. If no panic occurs, the values are handed off to
599     // the callee, and hence none of the cleanups in this temporary
600     // scope will ever execute.
601     let fcx = bcx.fcx;
602     let ccx = fcx.ccx;
603     let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
604
605     let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
606     let mut bcx = callee.bcx;
607
608     let (abi, ret_ty) = match callee.ty.sty {
609         ty::TyBareFn(_, ref f) => {
610             let sig = bcx.tcx().erase_late_bound_regions(&f.sig);
611             let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
612             (f.abi, sig.output)
613         }
614         _ => panic!("expected bare rust fn or closure in trans_call_inner")
615     };
616
617     let (llfn, llself) = match callee.data {
618         Fn(llfn) => {
619             (llfn, None)
620         }
621         TraitItem(d) => {
622             (d.llfn, Some(d.llself))
623         }
624         Intrinsic(node, substs) => {
625             assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
626             assert!(dest.is_some());
627
628             let call_info = match debug_loc {
629                 DebugLoc::At(id, span) => NodeIdAndSpan { id: id, span: span },
630                 DebugLoc::None => {
631                     bcx.sess().bug("No call info for intrinsic call?")
632                 }
633             };
634
635             return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
636                                                    arg_cleanup_scope, args,
637                                                    dest.unwrap(), substs,
638                                                    call_info);
639         }
640         NamedTupleConstructor(disr) => {
641             assert!(dest.is_some());
642             fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
643
644             return base::trans_named_tuple_constructor(bcx,
645                                                        callee.ty,
646                                                        disr,
647                                                        args,
648                                                        dest.unwrap(),
649                                                        debug_loc);
650         }
651     };
652
653     // Intrinsics should not become actual functions.
654     // We trans them in place in `trans_intrinsic_call`
655     assert!(abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic);
656
657     let is_rust_fn = abi == Abi::Rust || abi == Abi::RustCall;
658
659     // Generate a location to store the result. If the user does
660     // not care about the result, just make a stack slot.
661     let opt_llretslot = dest.and_then(|dest| match dest {
662         expr::SaveIn(dst) => Some(dst),
663         expr::Ignore => {
664             let ret_ty = match ret_ty {
665                 ty::FnConverging(ret_ty) => ret_ty,
666                 ty::FnDiverging => ccx.tcx().mk_nil()
667             };
668             if !is_rust_fn ||
669               type_of::return_uses_outptr(ccx, ret_ty) ||
670               bcx.fcx.type_needs_drop(ret_ty) {
671                 // Push the out-pointer if we use an out-pointer for this
672                 // return type, otherwise push "undef".
673                 if common::type_is_zero_size(ccx, ret_ty) {
674                     let llty = type_of::type_of(ccx, ret_ty);
675                     Some(common::C_undef(llty.ptr_to()))
676                 } else {
677                     let llresult = alloc_ty(bcx, ret_ty, "__llret");
678                     call_lifetime_start(bcx, llresult);
679                     Some(llresult)
680                 }
681             } else {
682                 None
683             }
684         }
685     });
686
687     let mut llresult = unsafe {
688         llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
689     };
690
691     // The code below invokes the function, using either the Rust
692     // conventions (if it is a rust fn) or the native conventions
693     // (otherwise).  The important part is that, when all is said
694     // and done, either the return value of the function will have been
695     // written in opt_llretslot (if it is Some) or `llresult` will be
696     // set appropriately (otherwise).
697     if is_rust_fn {
698         let mut llargs = Vec::new();
699
700         if let (ty::FnConverging(ret_ty), Some(mut llretslot)) = (ret_ty, opt_llretslot) {
701             if type_of::return_uses_outptr(ccx, ret_ty) {
702                 let llformal_ret_ty = type_of::type_of(ccx, ret_ty).ptr_to();
703                 let llret_ty = common::val_ty(llretslot);
704                 if llformal_ret_ty != llret_ty {
705                     // this could happen due to e.g. subtyping
706                     debug!("casting actual return type ({}) to match formal ({})",
707                         bcx.llty_str(llret_ty), bcx.llty_str(llformal_ret_ty));
708                     llretslot = PointerCast(bcx, llretslot, llformal_ret_ty);
709                 }
710                 llargs.push(llretslot);
711             }
712         }
713
714         // Push a trait object's self.
715         if let Some(llself) = llself {
716             llargs.push(llself);
717         }
718
719         // Push the arguments.
720         bcx = trans_args(bcx,
721                          args,
722                          callee.ty,
723                          &mut llargs,
724                          cleanup::CustomScope(arg_cleanup_scope),
725                          llself.is_some(),
726                          abi);
727
728         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
729
730         // Invoke the actual rust fn and update bcx/llresult.
731         let (llret, b) = base::invoke(bcx,
732                                       llfn,
733                                       &llargs[..],
734                                       callee.ty,
735                                       debug_loc);
736         bcx = b;
737         llresult = llret;
738
739         // If the Rust convention for this type is return via
740         // the return value, copy it into llretslot.
741         match (opt_llretslot, ret_ty) {
742             (Some(llretslot), ty::FnConverging(ret_ty)) => {
743                 if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
744                     !common::type_is_zero_size(bcx.ccx(), ret_ty)
745                 {
746                     store_ty(bcx, llret, llretslot, ret_ty)
747                 }
748             }
749             (_, _) => {}
750         }
751     } else {
752         // Lang items are the only case where dest is None, and
753         // they are always Rust fns.
754         assert!(dest.is_some());
755
756         let mut llargs = Vec::new();
757         let arg_tys = match args {
758             ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(),
759             _ => panic!("expected arg exprs.")
760         };
761         bcx = trans_args(bcx,
762                          args,
763                          callee.ty,
764                          &mut llargs,
765                          cleanup::CustomScope(arg_cleanup_scope),
766                          false,
767                          abi);
768         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
769
770         bcx = foreign::trans_native_call(bcx,
771                                          callee.ty,
772                                          llfn,
773                                          opt_llretslot.unwrap(),
774                                          &llargs[..],
775                                          arg_tys,
776                                          debug_loc);
777     }
778
779     fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
780
781     // If the caller doesn't care about the result of this fn call,
782     // drop the temporary slot we made.
783     match (dest, opt_llretslot, ret_ty) {
784         (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
785             // drop the value if it is not being saved.
786             bcx = glue::drop_ty(bcx,
787                                 llretslot,
788                                 ret_ty,
789                                 debug_loc);
790             call_lifetime_end(bcx, llretslot);
791         }
792         _ => {}
793     }
794
795     if ret_ty == ty::FnDiverging {
796         Unreachable(bcx);
797     }
798
799     Result::new(bcx, llresult)
800 }
801
802 pub enum CallArgs<'a, 'tcx> {
803     // Supply value of arguments as a list of expressions that must be
804     // translated. This is used in the common case of `foo(bar, qux)`.
805     ArgExprs(&'a [P<hir::Expr>]),
806
807     // Supply value of arguments as a list of LLVM value refs; frequently
808     // used with lang items and so forth, when the argument is an internal
809     // value.
810     ArgVals(&'a [ValueRef]),
811
812     // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
813     // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
814     // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
815     // arguments should be auto-referenced
816     ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
817
818     // Supply value of arguments as a list of expressions that must be
819     // translated, for overloaded call operators.
820     ArgOverloadedCall(Vec<&'a hir::Expr>),
821 }
822
823 fn trans_args_under_call_abi<'blk, 'tcx>(
824                              mut bcx: Block<'blk, 'tcx>,
825                              arg_exprs: &[P<hir::Expr>],
826                              fn_ty: Ty<'tcx>,
827                              llargs: &mut Vec<ValueRef>,
828                              arg_cleanup_scope: cleanup::ScopeId,
829                              ignore_self: bool)
830                              -> Block<'blk, 'tcx>
831 {
832     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
833     let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
834     let args = sig.inputs;
835
836     // Translate the `self` argument first.
837     if !ignore_self {
838         let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
839         bcx = trans_arg_datum(bcx,
840                               args[0],
841                               arg_datum,
842                               arg_cleanup_scope,
843                               DontAutorefArg,
844                               llargs);
845     }
846
847     // Now untuple the rest of the arguments.
848     let tuple_expr = &arg_exprs[1];
849     let tuple_type = common::node_id_type(bcx, tuple_expr.id);
850
851     match tuple_type.sty {
852         ty::TyTuple(ref field_types) => {
853             let tuple_datum = unpack_datum!(bcx,
854                                             expr::trans(bcx, &tuple_expr));
855             let tuple_lvalue_datum =
856                 unpack_datum!(bcx,
857                               tuple_datum.to_lvalue_datum(bcx,
858                                                           "args",
859                                                           tuple_expr.id));
860             let repr = adt::represent_type(bcx.ccx(), tuple_type);
861             let repr_ptr = &repr;
862             for (i, field_type) in field_types.iter().enumerate() {
863                 let arg_datum = tuple_lvalue_datum.get_element(
864                     bcx,
865                     field_type,
866                     |srcval| {
867                         adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
868                     }).to_expr_datum();
869                 bcx = trans_arg_datum(bcx,
870                                       field_type,
871                                       arg_datum,
872                                       arg_cleanup_scope,
873                                       DontAutorefArg,
874                                       llargs);
875             }
876         }
877         _ => {
878             bcx.sess().span_bug(tuple_expr.span,
879                                 "argument to `.call()` wasn't a tuple?!")
880         }
881     };
882
883     bcx
884 }
885
886 fn trans_overloaded_call_args<'blk, 'tcx>(
887                               mut bcx: Block<'blk, 'tcx>,
888                               arg_exprs: Vec<&hir::Expr>,
889                               fn_ty: Ty<'tcx>,
890                               llargs: &mut Vec<ValueRef>,
891                               arg_cleanup_scope: cleanup::ScopeId,
892                               ignore_self: bool)
893                               -> Block<'blk, 'tcx> {
894     // Translate the `self` argument first.
895     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
896     let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
897     let arg_tys = sig.inputs;
898
899     if !ignore_self {
900         let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
901         bcx = trans_arg_datum(bcx,
902                               arg_tys[0],
903                               arg_datum,
904                               arg_cleanup_scope,
905                               DontAutorefArg,
906                               llargs);
907     }
908
909     // Now untuple the rest of the arguments.
910     let tuple_type = arg_tys[1];
911     match tuple_type.sty {
912         ty::TyTuple(ref field_types) => {
913             for (i, &field_type) in field_types.iter().enumerate() {
914                 let arg_datum =
915                     unpack_datum!(bcx, expr::trans(bcx, arg_exprs[i + 1]));
916                 bcx = trans_arg_datum(bcx,
917                                       field_type,
918                                       arg_datum,
919                                       arg_cleanup_scope,
920                                       DontAutorefArg,
921                                       llargs);
922             }
923         }
924         _ => {
925             bcx.sess().span_bug(arg_exprs[0].span,
926                                 "argument to `.call()` wasn't a tuple?!")
927         }
928     };
929
930     bcx
931 }
932
933 pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
934                                   args: CallArgs<'a, 'tcx>,
935                                   fn_ty: Ty<'tcx>,
936                                   llargs: &mut Vec<ValueRef>,
937                                   arg_cleanup_scope: cleanup::ScopeId,
938                                   ignore_self: bool,
939                                   abi: Abi)
940                                   -> Block<'blk, 'tcx> {
941     debug!("trans_args(abi={})", abi);
942
943     let _icx = push_ctxt("trans_args");
944     let sig = cx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
945     let sig = infer::normalize_associated_type(cx.tcx(), &sig);
946     let arg_tys = sig.inputs;
947     let variadic = sig.variadic;
948
949     let mut bcx = cx;
950
951     // First we figure out the caller's view of the types of the arguments.
952     // This will be needed if this is a generic call, because the callee has
953     // to cast her view of the arguments to the caller's view.
954     match args {
955         ArgExprs(arg_exprs) => {
956             if abi == Abi::RustCall {
957                 // This is only used for direct calls to the `call`,
958                 // `call_mut` or `call_once` functions.
959                 return trans_args_under_call_abi(cx,
960                                                  arg_exprs,
961                                                  fn_ty,
962                                                  llargs,
963                                                  arg_cleanup_scope,
964                                                  ignore_self)
965             }
966
967             let num_formal_args = arg_tys.len();
968             for (i, arg_expr) in arg_exprs.iter().enumerate() {
969                 if i == 0 && ignore_self {
970                     continue;
971                 }
972                 let arg_ty = if i >= num_formal_args {
973                     assert!(variadic);
974                     common::expr_ty_adjusted(cx, &arg_expr)
975                 } else {
976                     arg_tys[i]
977                 };
978
979                 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
980                 bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
981                                       arg_cleanup_scope,
982                                       DontAutorefArg,
983                                       llargs);
984             }
985         }
986         ArgOverloadedCall(arg_exprs) => {
987             return trans_overloaded_call_args(cx,
988                                               arg_exprs,
989                                               fn_ty,
990                                               llargs,
991                                               arg_cleanup_scope,
992                                               ignore_self)
993         }
994         ArgOverloadedOp(lhs, rhs, autoref) => {
995             assert!(!variadic);
996
997             bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
998                                   arg_cleanup_scope,
999                                   DontAutorefArg,
1000                                   llargs);
1001
1002             if let Some((rhs, rhs_id)) = rhs {
1003                 assert_eq!(arg_tys.len(), 2);
1004                 bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
1005                                       arg_cleanup_scope,
1006                                       if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
1007                                       llargs);
1008             } else {
1009                 assert_eq!(arg_tys.len(), 1);
1010             }
1011         }
1012         ArgVals(vs) => {
1013             llargs.extend_from_slice(vs);
1014         }
1015     }
1016
1017     bcx
1018 }
1019
1020 #[derive(Copy, Clone)]
1021 pub enum AutorefArg {
1022     DontAutorefArg,
1023     DoAutorefArg(ast::NodeId)
1024 }
1025
1026 pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1027                                    formal_arg_ty: Ty<'tcx>,
1028                                    arg_datum: Datum<'tcx, Expr>,
1029                                    arg_cleanup_scope: cleanup::ScopeId,
1030                                    autoref_arg: AutorefArg,
1031                                    llargs: &mut Vec<ValueRef>)
1032                                    -> Block<'blk, 'tcx> {
1033     let _icx = push_ctxt("trans_arg_datum");
1034     let mut bcx = bcx;
1035     let ccx = bcx.ccx();
1036
1037     debug!("trans_arg_datum({:?})",
1038            formal_arg_ty);
1039
1040     let arg_datum_ty = arg_datum.ty;
1041
1042     debug!("   arg datum: {}", arg_datum.to_string(bcx.ccx()));
1043
1044     let mut val;
1045     // FIXME(#3548) use the adjustments table
1046     match autoref_arg {
1047         DoAutorefArg(arg_id) => {
1048             // We will pass argument by reference
1049             // We want an lvalue, so that we can pass by reference and
1050             let arg_datum = unpack_datum!(
1051                 bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
1052             val = arg_datum.val;
1053         }
1054         DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
1055                 !bcx.fcx.type_needs_drop(arg_datum_ty) => {
1056             val = arg_datum.val
1057         }
1058         DontAutorefArg => {
1059             // Make this an rvalue, since we are going to be
1060             // passing ownership.
1061             let arg_datum = unpack_datum!(
1062                 bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
1063
1064             // Now that arg_datum is owned, get it into the appropriate
1065             // mode (ref vs value).
1066             let arg_datum = unpack_datum!(
1067                 bcx, arg_datum.to_appropriate_datum(bcx));
1068
1069             // Technically, ownership of val passes to the callee.
1070             // However, we must cleanup should we panic before the
1071             // callee is actually invoked.
1072             val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
1073         }
1074     }
1075
1076     if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
1077         // this could happen due to e.g. subtyping
1078         let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
1079         debug!("casting actual type ({}) to match formal ({})",
1080                bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
1081         debug!("Rust types: {:?}; {:?}", arg_datum_ty,
1082                                      formal_arg_ty);
1083         val = PointerCast(bcx, val, llformal_arg_ty);
1084     }
1085
1086     debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
1087
1088     if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
1089         llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
1090         llargs.push(Load(bcx, expr::get_meta(bcx, val)));
1091     } else {
1092         llargs.push(val);
1093     }
1094
1095     bcx
1096 }