]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/callee.rs
translate tuple-variant constructors using MIR
[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 llvm::{self, ValueRef, get_params};
20 use rustc::hir::def_id::DefId;
21 use rustc::ty::subst::{Substs, Subst};
22 use rustc::traits;
23 use abi::{Abi, FnType};
24 use attributes;
25 use builder::Builder;
26 use common::{self, CrateContext};
27 use cleanup::CleanupScope;
28 use mir::lvalue::LvalueRef;
29 use consts;
30 use common::def_ty;
31 use declare;
32 use value::Value;
33 use meth;
34 use monomorphize::Instance;
35 use trans_item::TransItem;
36 use type_of;
37 use rustc::ty::{self, Ty, TypeFoldable};
38 use rustc::hir;
39 use std::iter;
40
41 use syntax_pos::DUMMY_SP;
42
43 use mir::lvalue::Alignment;
44
45 #[derive(Debug)]
46 pub enum CalleeData {
47     /// Function pointer.
48     Fn(ValueRef),
49
50     Intrinsic,
51
52     /// Trait object found in the vtable at that index.
53     Virtual(usize)
54 }
55
56 #[derive(Debug)]
57 pub struct Callee<'tcx> {
58     pub data: CalleeData,
59     pub ty: Ty<'tcx>
60 }
61
62 impl<'tcx> Callee<'tcx> {
63     /// Function pointer.
64     pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
65         Callee {
66             data: Fn(llfn),
67             ty: ty
68         }
69     }
70
71     /// Function or method definition.
72     pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>)
73                    -> Callee<'tcx> {
74         let tcx = ccx.tcx();
75
76         if let Some(trait_id) = tcx.trait_of_item(def_id) {
77             return Callee::trait_method(ccx, trait_id, def_id, substs);
78         }
79
80         let fn_ty = def_ty(ccx.shared(), def_id, substs);
81         if let ty::TyFnDef(.., f) = fn_ty.sty {
82             if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
83                 return Callee {
84                     data: Intrinsic,
85                     ty: fn_ty
86                 };
87             }
88         }
89
90         let (llfn, ty) = get_fn(ccx, def_id, substs);
91         Callee::ptr(llfn, ty)
92     }
93
94     /// Trait method, which has to be resolved to an impl method.
95     pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
96                             trait_id: DefId,
97                             def_id: DefId,
98                             substs: &'tcx Substs<'tcx>)
99                             -> Callee<'tcx> {
100         let tcx = ccx.tcx();
101
102         let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs);
103         let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
104         match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
105             traits::VtableImpl(vtable_impl) => {
106                 let name = tcx.item_name(def_id);
107                 let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
108
109                 // Translate the function, bypassing Callee::def.
110                 // That is because default methods have the same ID as the
111                 // trait method used to look up the impl method that ended
112                 // up here, so calling Callee::def would infinitely recurse.
113                 let (llfn, ty) = get_fn(ccx, def_id, substs);
114                 Callee::ptr(llfn, ty)
115             }
116             traits::VtableClosure(vtable_closure) => {
117                 // The substitutions should have no type parameters remaining
118                 // after passing through fulfill_obligation
119                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
120                 let instance = Instance::new(def_id, substs);
121                 let llfn = trans_closure_method(
122                     ccx,
123                     vtable_closure.closure_def_id,
124                     vtable_closure.substs,
125                     instance,
126                     trait_closure_kind);
127
128                 let method_ty = def_ty(ccx.shared(), def_id, substs);
129                 Callee::ptr(llfn, method_ty)
130             }
131             traits::VtableFnPointer(vtable_fn_pointer) => {
132                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
133                 let instance = Instance::new(def_id, substs);
134                 let llfn = trans_fn_pointer_shim(ccx, instance,
135                                                  trait_closure_kind,
136                                                  vtable_fn_pointer.fn_ty);
137
138                 let method_ty = def_ty(ccx.shared(), def_id, substs);
139                 Callee::ptr(llfn, method_ty)
140             }
141             traits::VtableObject(ref data) => {
142                 Callee {
143                     data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
144                     ty: def_ty(ccx.shared(), def_id, substs)
145                 }
146             }
147             vtable => {
148                 bug!("resolved vtable bad vtable {:?} in trans", vtable);
149             }
150         }
151     }
152
153     /// Get the abi::FnType for a direct call. Mainly deals with the fact
154     /// that a Virtual call doesn't take the vtable, like its shim does.
155     /// The extra argument types are for variadic (extern "C") functions.
156     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
157                               extra_args: &[Ty<'tcx>]) -> FnType {
158         let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig());
159         let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
160         if let Virtual(_) = self.data {
161             // Don't pass the vtable, it's not an argument of the virtual fn.
162             fn_ty.args[1].ignore();
163         }
164         fn_ty.adjust_for_abi(ccx, sig);
165         fn_ty
166     }
167
168     /// Turn the callee into a function pointer.
169     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
170         match self.data {
171             Fn(llfn) => llfn,
172             Virtual(_) => meth::trans_object_shim(ccx, self),
173             Intrinsic => bug!("intrinsic {} getting reified", self.ty)
174         }
175     }
176 }
177
178 fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
179                                   def_id: DefId,
180                                   substs: ty::ClosureSubsts<'tcx>,
181                                   method_instance: Instance<'tcx>,
182                                   trait_closure_kind: ty::ClosureKind)
183                                   -> ValueRef
184 {
185     // If this is a closure, redirect to it.
186     let (llfn, _) = get_fn(ccx, def_id, substs.substs);
187
188     // If the closure is a Fn closure, but a FnOnce is needed (etc),
189     // then adapt the self type
190     let llfn_closure_kind = ccx.tcx().closure_kind(def_id);
191
192     debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
193            trait_closure_kind={:?}, llfn={:?})",
194            llfn_closure_kind, trait_closure_kind, Value(llfn));
195
196     match needs_fn_once_adapter_shim(llfn_closure_kind, trait_closure_kind) {
197         Ok(true) => trans_fn_once_adapter_shim(ccx,
198                                                def_id,
199                                                substs,
200                                                method_instance,
201                                                llfn),
202         Ok(false) => llfn,
203         Err(()) => {
204             bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
205                  llfn_closure_kind,
206                  trait_closure_kind);
207         }
208     }
209 }
210
211 pub fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
212                                   trait_closure_kind: ty::ClosureKind)
213                                   -> Result<bool, ()>
214 {
215     match (actual_closure_kind, trait_closure_kind) {
216         (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
217         (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
218         (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
219             // No adapter needed.
220            Ok(false)
221         }
222         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
223             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
224             // `fn(&mut self, ...)`. In fact, at trans time, these are
225             // basically the same thing, so we can just return llfn.
226             Ok(false)
227         }
228         (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
229         (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
230             // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
231             // self, ...)`.  We want a `fn(self, ...)`. We can produce
232             // this by doing something like:
233             //
234             //     fn call_once(self, ...) { call_mut(&self, ...) }
235             //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
236             //
237             // These are both the same at trans time.
238             Ok(true)
239         }
240         _ => Err(()),
241     }
242 }
243
244 fn trans_fn_once_adapter_shim<'a, 'tcx>(
245     ccx: &'a CrateContext<'a, 'tcx>,
246     def_id: DefId,
247     substs: ty::ClosureSubsts<'tcx>,
248     method_instance: Instance<'tcx>,
249     llreffn: ValueRef)
250     -> ValueRef
251 {
252     if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
253         return llfn;
254     }
255
256     debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
257            def_id, substs, Value(llreffn));
258
259     let tcx = ccx.tcx();
260
261     // Find a version of the closure type. Substitute static for the
262     // region since it doesn't really matter.
263     let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs);
264     let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
265
266     // Make a version with the type of by-ref closure.
267     let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
268     let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
269     assert_eq!(sig.abi, Abi::RustCall);
270     let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
271         iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
272         sig.output(),
273         sig.variadic,
274         sig.unsafety,
275         Abi::RustCall
276     )));
277     debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
278            llref_fn_ty);
279
280
281     // Make a version of the closure type with the same arguments, but
282     // with argument #0 being by value.
283     let sig = tcx.mk_fn_sig(
284         iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
285         sig.output(),
286         sig.variadic,
287         sig.unsafety,
288         Abi::RustCall
289     );
290
291     let fn_ty = FnType::new(ccx, sig, &[]);
292     let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
293
294     // Create the by-value helper.
295     let function_name = method_instance.symbol_name(ccx.shared());
296     let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
297     attributes::set_frame_pointer_elimination(ccx, lloncefn);
298
299     let orig_fn_ty = fn_ty;
300     let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block");
301
302     let callee = Callee {
303         data: Fn(llreffn),
304         ty: llref_fn_ty
305     };
306
307     // the first argument (`self`) will be the (by value) closure env.
308
309     let mut llargs = get_params(lloncefn);
310     let fn_ret = callee.ty.fn_ret();
311     let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
312     let self_idx = fn_ty.ret.is_indirect() as usize;
313     let env_arg = &orig_fn_ty.args[0];
314     let env = if env_arg.is_indirect() {
315         LvalueRef::new_sized_ty(llargs[self_idx], closure_ty, Alignment::AbiAligned)
316     } else {
317         let scratch = LvalueRef::alloca(&bcx, closure_ty, "self");
318         let mut llarg_idx = self_idx;
319         env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch.llval);
320         scratch
321     };
322
323     debug!("trans_fn_once_adapter_shim: env={:?}", env);
324     // Adjust llargs such that llargs[self_idx..] has the call arguments.
325     // For zero-sized closures that means sneaking in a new argument.
326     if env_arg.is_ignore() {
327         llargs.insert(self_idx, env.llval);
328     } else {
329         llargs[self_idx] = env.llval;
330     }
331
332     // Call the by-ref closure body with `self` in a cleanup scope,
333     // to drop `self` when the body returns, or in case it unwinds.
334     let self_scope = CleanupScope::schedule_drop_mem(&bcx, env);
335
336     let llfn = callee.reify(bcx.ccx);
337     let llret;
338     if let Some(landing_pad) = self_scope.landing_pad {
339         let normal_bcx = bcx.build_sibling_block("normal-return");
340         llret = bcx.invoke(llfn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
341         bcx = normal_bcx;
342     } else {
343         llret = bcx.call(llfn, &llargs[..], None);
344     }
345     fn_ty.apply_attrs_callsite(llret);
346
347     if fn_ret.0.is_never() {
348         bcx.unreachable();
349     } else {
350         self_scope.trans(&bcx);
351
352         if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
353             bcx.ret_void();
354         } else {
355             bcx.ret(llret);
356         }
357     }
358
359     ccx.instances().borrow_mut().insert(method_instance, lloncefn);
360
361     lloncefn
362 }
363
364 /// Translates an adapter that implements the `Fn` trait for a fn
365 /// pointer. This is basically the equivalent of something like:
366 ///
367 /// ```
368 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
369 ///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
370 ///         (*self)(args.0)
371 ///     }
372 /// }
373 /// ```
374 ///
375 /// but for the bare function type given.
376 fn trans_fn_pointer_shim<'a, 'tcx>(
377     ccx: &'a CrateContext<'a, 'tcx>,
378     method_instance: Instance<'tcx>,
379     closure_kind: ty::ClosureKind,
380     bare_fn_ty: Ty<'tcx>)
381     -> ValueRef
382 {
383     let tcx = ccx.tcx();
384
385     // Normalize the type for better caching.
386     let bare_fn_ty = tcx.normalize_associated_type(&bare_fn_ty);
387
388     // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
389     let is_by_ref = match closure_kind {
390         ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
391         ty::ClosureKind::FnOnce => false,
392     };
393
394     let llfnpointer = match bare_fn_ty.sty {
395         ty::TyFnDef(def_id, substs, _) => {
396             // Function definitions have to be turned into a pointer.
397             let llfn = Callee::def(ccx, def_id, substs).reify(ccx);
398             if !is_by_ref {
399                 // A by-value fn item is ignored, so the shim has
400                 // the same signature as the original function.
401                 return llfn;
402             }
403             Some(llfn)
404         }
405         _ => None
406     };
407
408     let bare_fn_ty_maybe_ref = if is_by_ref {
409         tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty)
410     } else {
411         bare_fn_ty
412     };
413
414     // Check if we already trans'd this shim.
415     if let Some(&llval) = ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
416         return llval;
417     }
418
419     debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
420            bare_fn_ty);
421
422     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
423     // which is the fn pointer, and `args`, which is the arguments tuple.
424     let sig = bare_fn_ty.fn_sig();
425     let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
426     assert_eq!(sig.unsafety, hir::Unsafety::Normal);
427     assert_eq!(sig.abi, Abi::Rust);
428     let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
429     let sig = tcx.mk_fn_sig(
430         [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
431         sig.output(),
432         false,
433         hir::Unsafety::Normal,
434         Abi::RustCall
435     );
436     let fn_ty = FnType::new(ccx, sig, &[]);
437     let tuple_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
438     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
439
440     //
441     let function_name = method_instance.symbol_name(ccx.shared());
442     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
443     attributes::set_frame_pointer_elimination(ccx, llfn);
444     //
445     let bcx = Builder::new_block(ccx, llfn, "entry-block");
446
447     let mut llargs = get_params(llfn);
448
449     let self_arg = llargs.remove(fn_ty.ret.is_indirect() as usize);
450     let llfnpointer = llfnpointer.unwrap_or_else(|| {
451         // the first argument (`self`) will be ptr to the fn pointer
452         if is_by_ref {
453             bcx.load(self_arg, None)
454         } else {
455             self_arg
456         }
457     });
458
459     let callee = Callee {
460         data: Fn(llfnpointer),
461         ty: bare_fn_ty
462     };
463     let fn_ret = callee.ty.fn_ret();
464     let fn_ty = callee.direct_fn_type(ccx, &[]);
465     let llret = bcx.call(llfnpointer, &llargs, None);
466     fn_ty.apply_attrs_callsite(llret);
467
468     if fn_ret.0.is_never() {
469         bcx.unreachable();
470     } else {
471         if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
472             bcx.ret_void();
473         } else {
474             bcx.ret(llret);
475         }
476     }
477
478     ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
479
480     llfn
481 }
482
483 /// Translates a reference to a fn/method item, monomorphizing and
484 /// inlining as it goes.
485 ///
486 /// # Parameters
487 ///
488 /// - `ccx`: the crate context
489 /// - `def_id`: def id of the fn or method item being referenced
490 /// - `substs`: values for each of the fn/method's parameters
491 fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
492                     def_id: DefId,
493                     substs: &'tcx Substs<'tcx>)
494                     -> (ValueRef, Ty<'tcx>) {
495     let tcx = ccx.tcx();
496
497     debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
498
499     assert!(!substs.needs_infer());
500     assert!(!substs.has_escaping_regions());
501     assert!(!substs.has_param_types());
502
503     let substs = tcx.normalize_associated_type(&substs);
504     let instance = Instance::new(def_id, substs);
505     let fn_ty = common::def_ty(ccx.shared(), def_id, substs);
506
507     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
508         return (llfn, fn_ty);
509     }
510
511     let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
512                                               TransItem::Fn(instance));
513     debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
514
515     // This is subtle and surprising, but sometimes we have to bitcast
516     // the resulting fn pointer.  The reason has to do with external
517     // functions.  If you have two crates that both bind the same C
518     // library, they may not use precisely the same types: for
519     // example, they will probably each declare their own structs,
520     // which are distinct types from LLVM's point of view (nominal
521     // types).
522     //
523     // Now, if those two crates are linked into an application, and
524     // they contain inlined code, you can wind up with a situation
525     // where both of those functions wind up being loaded into this
526     // application simultaneously. In that case, the same function
527     // (from LLVM's point of view) requires two types. But of course
528     // LLVM won't allow one function to have two types.
529     //
530     // What we currently do, therefore, is declare the function with
531     // one of the two types (whichever happens to come first) and then
532     // bitcast as needed when the function is referenced to make sure
533     // it has the type we expect.
534     //
535     // This can occur on either a crate-local or crate-external
536     // reference. It also occurs when testing libcore and in some
537     // other weird situations. Annoying.
538
539     // Create a fn pointer with the substituted signature.
540     let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
541     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
542
543     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
544         if common::val_ty(llfn) != llptrty {
545             debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
546             consts::ptrcast(llfn, llptrty)
547         } else {
548             debug!("get_fn: not casting pointer!");
549             llfn
550         }
551     } else {
552         let llfn = declare::declare_fn(ccx, &sym, fn_ty);
553         assert_eq!(common::val_ty(llfn), llptrty);
554         debug!("get_fn: not casting pointer!");
555
556         let attrs = ccx.tcx().get_attrs(def_id);
557         attributes::from_fn_attrs(ccx, &attrs, llfn);
558
559         let is_local_def = ccx.shared().translation_items().borrow()
560                               .contains(&TransItem::Fn(instance));
561         if is_local_def {
562             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
563             attributes::unwind(llfn, true);
564             unsafe {
565                 llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
566             }
567         }
568         if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) {
569             unsafe {
570                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
571             }
572         }
573         llfn
574     };
575
576     ccx.instances().borrow_mut().insert(instance, llfn);
577
578     (llfn, fn_ty)
579 }