]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/callee.rs
Rollup merge of #36210 - EugeneGonzalez:E0529, r=jonathandturner
[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
19 use arena::TypedArena;
20 use back::symbol_names;
21 use llvm::{self, ValueRef, get_params};
22 use rustc::hir::def_id::DefId;
23 use rustc::ty::subst::Substs;
24 use rustc::traits;
25 use abi::{Abi, FnType};
26 use attributes;
27 use base;
28 use base::*;
29 use build::*;
30 use closure;
31 use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
32 use consts;
33 use debuginfo::DebugLoc;
34 use declare;
35 use meth;
36 use monomorphize::{self, Instance};
37 use trans_item::TransItem;
38 use type_of;
39 use Disr;
40 use rustc::ty::{self, Ty, TypeFoldable};
41 use rustc::hir;
42
43 use syntax_pos::DUMMY_SP;
44
45 #[derive(Debug)]
46 pub enum CalleeData {
47     /// Constructor for enum variant/tuple-like-struct.
48     NamedTupleConstructor(Disr),
49
50     /// Function pointer.
51     Fn(ValueRef),
52
53     Intrinsic,
54
55     /// Trait object found in the vtable at that index.
56     Virtual(usize)
57 }
58
59 #[derive(Debug)]
60 pub struct Callee<'tcx> {
61     pub data: CalleeData,
62     pub ty: Ty<'tcx>
63 }
64
65 impl<'tcx> Callee<'tcx> {
66     /// Function pointer.
67     pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
68         Callee {
69             data: Fn(llfn),
70             ty: ty
71         }
72     }
73
74     /// Trait or impl method call.
75     pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
76                              method_call: ty::MethodCall)
77                              -> Callee<'tcx> {
78         let method = bcx.tcx().tables.borrow().method_map[&method_call];
79         Callee::method(bcx, method)
80     }
81
82     /// Trait or impl method.
83     pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
84                         method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
85         let substs = bcx.fcx.monomorphize(&method.substs);
86         Callee::def(bcx.ccx(), method.def_id, substs)
87     }
88
89     /// Function or method definition.
90     pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
91                    def_id: DefId,
92                    substs: &'tcx Substs<'tcx>)
93                    -> Callee<'tcx> {
94         let tcx = ccx.tcx();
95
96         if let Some(trait_id) = tcx.trait_of_item(def_id) {
97             return Callee::trait_method(ccx, trait_id, def_id, substs);
98         }
99
100         let fn_ty = def_ty(ccx.shared(), def_id, substs);
101         if let ty::TyFnDef(_, _, f) = fn_ty.sty {
102             if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
103                 return Callee {
104                     data: Intrinsic,
105                     ty: fn_ty
106                 };
107             }
108         }
109
110         // FIXME(eddyb) Detect ADT constructors more efficiently.
111         if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
112             if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
113                 return Callee {
114                     data: NamedTupleConstructor(Disr::from(v.disr_val)),
115                     ty: fn_ty
116                 };
117             }
118         }
119
120         let (llfn, ty) = get_fn(ccx, def_id, substs);
121         Callee::ptr(llfn, ty)
122     }
123
124     /// Trait method, which has to be resolved to an impl method.
125     pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
126                             trait_id: DefId,
127                             def_id: DefId,
128                             substs: &'tcx Substs<'tcx>)
129                             -> Callee<'tcx> {
130         let tcx = ccx.tcx();
131
132         let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs);
133         let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
134         match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
135             traits::VtableImpl(vtable_impl) => {
136                 let impl_did = vtable_impl.impl_def_id;
137                 let mname = tcx.item_name(def_id);
138                 // create a concatenated set of substitutions which includes
139                 // those from the impl and those from the method:
140                 let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
141
142                 // Translate the function, bypassing Callee::def.
143                 // That is because default methods have the same ID as the
144                 // trait method used to look up the impl method that ended
145                 // up here, so calling Callee::def would infinitely recurse.
146                 let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
147                 Callee::ptr(llfn, ty)
148             }
149             traits::VtableClosure(vtable_closure) => {
150                 // The substitutions should have no type parameters remaining
151                 // after passing through fulfill_obligation
152                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
153                 let llfn = closure::trans_closure_method(ccx,
154                                                          vtable_closure.closure_def_id,
155                                                          vtable_closure.substs,
156                                                          trait_closure_kind);
157
158                 let method_ty = def_ty(ccx.shared(), def_id, substs);
159                 Callee::ptr(llfn, method_ty)
160             }
161             traits::VtableFnPointer(vtable_fn_pointer) => {
162                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
163                 let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
164
165                 let method_ty = def_ty(ccx.shared(), def_id, substs);
166                 Callee::ptr(llfn, method_ty)
167             }
168             traits::VtableObject(ref data) => {
169                 Callee {
170                     data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
171                     ty: def_ty(ccx.shared(), def_id, substs)
172                 }
173             }
174             vtable => {
175                 bug!("resolved vtable bad vtable {:?} in trans", vtable);
176             }
177         }
178     }
179
180     /// Get the abi::FnType for a direct call. Mainly deals with the fact
181     /// that a Virtual call doesn't take the vtable, like its shim does.
182     /// The extra argument types are for variadic (extern "C") functions.
183     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
184                               extra_args: &[Ty<'tcx>]) -> FnType {
185         let abi = self.ty.fn_abi();
186         let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
187         let sig = ccx.tcx().normalize_associated_type(&sig);
188         let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
189         if let Virtual(_) = self.data {
190             // Don't pass the vtable, it's not an argument of the virtual fn.
191             fn_ty.args[1].ignore();
192         }
193         fn_ty.adjust_for_abi(ccx, abi, &sig);
194         fn_ty
195     }
196
197     /// This behemoth of a function translates function calls. Unfortunately, in
198     /// order to generate more efficient LLVM output at -O0, it has quite a complex
199     /// signature (refactoring this into two functions seems like a good idea).
200     ///
201     /// In particular, for lang items, it is invoked with a dest of None, and in
202     /// that case the return value contains the result of the fn. The lang item must
203     /// not return a structural type or else all heck breaks loose.
204     ///
205     /// For non-lang items, `dest` is always Some, and hence the result is written
206     /// into memory somewhere. Nonetheless we return the actual return value of the
207     /// function.
208     pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
209                           debug_loc: DebugLoc,
210                           args: &[ValueRef],
211                           dest: Option<ValueRef>)
212                           -> Result<'blk, 'tcx> {
213         trans_call_inner(bcx, debug_loc, self, args, dest)
214     }
215
216     /// Turn the callee into a function pointer.
217     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
218         match self.data {
219             Fn(llfn) => llfn,
220             Virtual(idx) => {
221                 meth::trans_object_shim(ccx, self.ty, idx)
222             }
223             NamedTupleConstructor(disr) => match self.ty.sty {
224                 ty::TyFnDef(def_id, substs, _) => {
225                     let instance = Instance::new(def_id, substs);
226                     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
227                         return llfn;
228                     }
229
230                     let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
231                                                               TransItem::Fn(instance));
232                     assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
233                     let lldecl = declare::define_internal_fn(ccx, &sym, self.ty);
234                     base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl);
235                     ccx.instances().borrow_mut().insert(instance, lldecl);
236
237                     lldecl
238                 }
239                 _ => bug!("expected fn item type, found {}", self.ty)
240             },
241             Intrinsic => bug!("intrinsic {} getting reified", self.ty)
242         }
243     }
244 }
245
246 /// Given a DefId and some Substs, produces the monomorphic item type.
247 fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
248                     def_id: DefId,
249                     substs: &'tcx Substs<'tcx>)
250                     -> Ty<'tcx> {
251     let ty = shared.tcx().lookup_item_type(def_id).ty;
252     monomorphize::apply_param_substs(shared, substs, &ty)
253 }
254
255 /// Translates an adapter that implements the `Fn` trait for a fn
256 /// pointer. This is basically the equivalent of something like:
257 ///
258 /// ```
259 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
260 ///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
261 ///         (*self)(args.0)
262 ///     }
263 /// }
264 /// ```
265 ///
266 /// but for the bare function type given.
267 pub fn trans_fn_pointer_shim<'a, 'tcx>(
268     ccx: &'a CrateContext<'a, 'tcx>,
269     closure_kind: ty::ClosureKind,
270     bare_fn_ty: Ty<'tcx>)
271     -> ValueRef
272 {
273     let _icx = push_ctxt("trans_fn_pointer_shim");
274     let tcx = ccx.tcx();
275
276     // Normalize the type for better caching.
277     let bare_fn_ty = tcx.normalize_associated_type(&bare_fn_ty);
278
279     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
280     let is_by_ref = match closure_kind {
281         ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
282         ty::ClosureKind::FnOnce => false,
283     };
284
285     let llfnpointer = match bare_fn_ty.sty {
286         ty::TyFnDef(def_id, substs, _) => {
287             // Function definitions have to be turned into a pointer.
288             let llfn = Callee::def(ccx, def_id, substs).reify(ccx);
289             if !is_by_ref {
290                 // A by-value fn item is ignored, so the shim has
291                 // the same signature as the original function.
292                 return llfn;
293             }
294             Some(llfn)
295         }
296         _ => None
297     };
298
299     let bare_fn_ty_maybe_ref = if is_by_ref {
300         tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty)
301     } else {
302         bare_fn_ty
303     };
304
305     // Check if we already trans'd this shim.
306     match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
307         Some(&llval) => { return llval; }
308         None => { }
309     }
310
311     debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
312            bare_fn_ty);
313
314     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
315     // which is the fn pointer, and `args`, which is the arguments tuple.
316     let sig = match bare_fn_ty.sty {
317         ty::TyFnDef(_, _,
318                     &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
319                                     abi: Abi::Rust,
320                                     ref sig }) |
321         ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
322                                     abi: Abi::Rust,
323                                     ref sig }) => sig,
324
325         _ => {
326             bug!("trans_fn_pointer_shim invoked on invalid type: {}",
327                  bare_fn_ty);
328         }
329     };
330     let sig = tcx.erase_late_bound_regions(sig);
331     let sig = ccx.tcx().normalize_associated_type(&sig);
332     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
333     let sig = ty::FnSig {
334         inputs: vec![bare_fn_ty_maybe_ref,
335                      tuple_input_ty],
336         output: sig.output,
337         variadic: false
338     };
339     let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
340     let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
341         unsafety: hir::Unsafety::Normal,
342         abi: Abi::RustCall,
343         sig: ty::Binder(sig)
344     }));
345     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
346
347     //
348     let function_name =
349         symbol_names::internal_name_from_type_and_suffix(ccx,
350                                                          bare_fn_ty,
351                                                          "fn_pointer_shim");
352     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
353     attributes::set_frame_pointer_elimination(ccx, llfn);
354     //
355     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
356     block_arena = TypedArena::new();
357     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
358     let mut bcx = fcx.init(false);
359
360     let llargs = get_params(fcx.llfn);
361
362     let self_idx = fcx.fn_ty.ret.is_indirect() as usize;
363     let llfnpointer = llfnpointer.unwrap_or_else(|| {
364         // the first argument (`self`) will be ptr to the fn pointer
365         if is_by_ref {
366             Load(bcx, llargs[self_idx])
367         } else {
368             llargs[self_idx]
369         }
370     });
371
372     let dest = fcx.llretslotptr.get();
373
374     let callee = Callee {
375         data: Fn(llfnpointer),
376         ty: bare_fn_ty
377     };
378     bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
379
380     fcx.finish(bcx, DebugLoc::None);
381
382     ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
383
384     llfn
385 }
386
387 /// Translates a reference to a fn/method item, monomorphizing and
388 /// inlining as it goes.
389 ///
390 /// # Parameters
391 ///
392 /// - `ccx`: the crate context
393 /// - `def_id`: def id of the fn or method item being referenced
394 /// - `substs`: values for each of the fn/method's parameters
395 fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
396                     def_id: DefId,
397                     substs: &'tcx Substs<'tcx>)
398                     -> (ValueRef, Ty<'tcx>) {
399     let tcx = ccx.tcx();
400
401     debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
402
403     assert!(!substs.needs_infer());
404     assert!(!substs.has_escaping_regions());
405     assert!(!substs.has_param_types());
406
407     let substs = tcx.normalize_associated_type(&substs);
408     let instance = Instance::new(def_id, substs);
409     let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
410     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
411
412     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
413         return (llfn, fn_ty);
414     }
415
416     let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
417                                               TransItem::Fn(instance));
418     debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
419
420     // This is subtle and surprising, but sometimes we have to bitcast
421     // the resulting fn pointer.  The reason has to do with external
422     // functions.  If you have two crates that both bind the same C
423     // library, they may not use precisely the same types: for
424     // example, they will probably each declare their own structs,
425     // which are distinct types from LLVM's point of view (nominal
426     // types).
427     //
428     // Now, if those two crates are linked into an application, and
429     // they contain inlined code, you can wind up with a situation
430     // where both of those functions wind up being loaded into this
431     // application simultaneously. In that case, the same function
432     // (from LLVM's point of view) requires two types. But of course
433     // LLVM won't allow one function to have two types.
434     //
435     // What we currently do, therefore, is declare the function with
436     // one of the two types (whichever happens to come first) and then
437     // bitcast as needed when the function is referenced to make sure
438     // it has the type we expect.
439     //
440     // This can occur on either a crate-local or crate-external
441     // reference. It also occurs when testing libcore and in some
442     // other weird situations. Annoying.
443
444     let fn_ptr_ty = match fn_ty.sty {
445         ty::TyFnDef(_, _, fty) => {
446             // Create a fn pointer with the substituted signature.
447             tcx.mk_fn_ptr(fty)
448         }
449         _ => bug!("expected fn item type, found {}", fn_ty)
450     };
451     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
452
453     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
454         if common::val_ty(llfn) != llptrty {
455             debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
456             consts::ptrcast(llfn, llptrty)
457         } else {
458             debug!("get_fn: not casting pointer!");
459             llfn
460         }
461     } else {
462         let llfn = declare::declare_fn(ccx, &sym, fn_ty);
463         assert_eq!(common::val_ty(llfn), llptrty);
464         debug!("get_fn: not casting pointer!");
465
466         let attrs = ccx.tcx().get_attrs(def_id);
467         attributes::from_fn_attrs(ccx, &attrs, llfn);
468
469         let is_local_def = ccx.shared().translation_items().borrow()
470                               .contains(&TransItem::Fn(instance));
471         if is_local_def {
472             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
473             attributes::unwind(llfn, true);
474             unsafe {
475                 llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
476             }
477         }
478
479         llfn
480     };
481
482     ccx.instances().borrow_mut().insert(instance, llfn);
483
484     (llfn, fn_ty)
485 }
486
487 // ______________________________________________________________________
488 // Translating calls
489
490 fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
491                                     debug_loc: DebugLoc,
492                                     callee: Callee<'tcx>,
493                                     args: &[ValueRef],
494                                     opt_llretslot: Option<ValueRef>)
495                                     -> Result<'blk, 'tcx> {
496     // Introduce a temporary cleanup scope that will contain cleanups
497     // for the arguments while they are being evaluated. The purpose
498     // this cleanup is to ensure that, should a panic occur while
499     // evaluating argument N, the values for arguments 0...N-1 are all
500     // cleaned up. If no panic occurs, the values are handed off to
501     // the callee, and hence none of the cleanups in this temporary
502     // scope will ever execute.
503     let fcx = bcx.fcx;
504     let ccx = fcx.ccx;
505
506     let fn_ret = callee.ty.fn_ret();
507     let fn_ty = callee.direct_fn_type(ccx, &[]);
508
509     let mut callee = match callee.data {
510         NamedTupleConstructor(_) | Intrinsic => {
511             bug!("{:?} calls should not go through Callee::call", callee);
512         }
513         f => f
514     };
515
516     // If there no destination, return must be direct, with no cast.
517     if opt_llretslot.is_none() {
518         assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
519     }
520
521     let mut llargs = Vec::new();
522
523     if fn_ty.ret.is_indirect() {
524         let mut llretslot = opt_llretslot.unwrap();
525         if let Some(ty) = fn_ty.ret.cast {
526             llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
527         }
528         llargs.push(llretslot);
529     }
530
531     match callee {
532         Virtual(idx) => {
533             llargs.push(args[0]);
534
535             let fn_ptr = meth::get_virtual_method(bcx, args[1], idx);
536             let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
537             callee = Fn(PointerCast(bcx, fn_ptr, llty));
538             llargs.extend_from_slice(&args[2..]);
539         }
540         _ => llargs.extend_from_slice(args)
541     }
542
543     let llfn = match callee {
544         Fn(f) => f,
545         _ => bug!("expected fn pointer callee, found {:?}", callee)
546     };
547
548     let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
549     if !bcx.unreachable.get() {
550         fn_ty.apply_attrs_callsite(llret);
551
552         // If the function we just called does not use an outpointer,
553         // store the result into the rust outpointer. Cast the outpointer
554         // type to match because some ABIs will use a different type than
555         // the Rust type. e.g., a {u32,u32} struct could be returned as
556         // u64.
557         if !fn_ty.ret.is_indirect() {
558             if let Some(llretslot) = opt_llretslot {
559                 fn_ty.ret.store(&bcx.build(), llret, llretslot);
560             }
561         }
562     }
563
564     if fn_ret.0.is_never() {
565         Unreachable(bcx);
566     }
567
568     Result::new(bcx, llret)
569 }