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.
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.
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
17 pub use self::CalleeData::*;
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;
25 use abi::{Abi, FnType};
31 use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
33 use debuginfo::DebugLoc;
36 use monomorphize::{self, Instance};
37 use trans_item::TransItem;
40 use rustc::ty::{self, Ty, TypeFoldable};
43 use syntax_pos::DUMMY_SP;
47 /// Constructor for enum variant/tuple-like-struct.
48 NamedTupleConstructor(Disr),
55 /// Trait object found in the vtable at that index.
60 pub struct Callee<'tcx> {
65 impl<'tcx> Callee<'tcx> {
67 pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
74 /// Trait or impl method call.
75 pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
76 method_call: ty::MethodCall)
78 let method = bcx.tcx().tables.borrow().method_map[&method_call];
79 Callee::method(bcx, method)
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)
89 /// Function or method definition.
90 pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
92 substs: &'tcx Substs<'tcx>)
96 if let Some(trait_id) = tcx.trait_of_item(def_id) {
97 return Callee::trait_method(ccx, trait_id, def_id, substs);
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 {
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) {
114 data: NamedTupleConstructor(Disr::from(v.disr_val)),
120 let (llfn, ty) = get_fn(ccx, def_id, substs);
121 Callee::ptr(llfn, ty)
124 /// Trait method, which has to be resolved to an impl method.
125 pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
128 substs: &'tcx Substs<'tcx>)
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);
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)
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,
158 let method_ty = def_ty(ccx.shared(), def_id, substs);
159 Callee::ptr(llfn, method_ty)
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);
165 let method_ty = def_ty(ccx.shared(), def_id, substs);
166 Callee::ptr(llfn, method_ty)
168 traits::VtableObject(ref data) => {
170 data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
171 ty: def_ty(ccx.shared(), def_id, substs)
175 bug!("resolved vtable bad vtable {:?} in trans", vtable);
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();
193 fn_ty.adjust_for_abi(ccx, abi, &sig);
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).
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.
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
208 pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
211 dest: Option<ValueRef>)
212 -> Result<'blk, 'tcx> {
213 trans_call_inner(bcx, debug_loc, self, args, dest)
216 /// Turn the callee into a function pointer.
217 pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
221 meth::trans_object_shim(ccx, self.ty, idx)
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) {
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);
239 _ => bug!("expected fn item type, found {}", self.ty)
241 Intrinsic => bug!("intrinsic {} getting reified", self.ty)
246 /// Given a DefId and some Substs, produces the monomorphic item type.
247 fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
249 substs: &'tcx Substs<'tcx>)
251 let ty = shared.tcx().lookup_item_type(def_id).ty;
252 monomorphize::apply_param_substs(shared, substs, &ty)
255 /// Translates an adapter that implements the `Fn` trait for a fn
256 /// pointer. This is basically the equivalent of something like:
259 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
260 /// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
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>)
273 let _icx = push_ctxt("trans_fn_pointer_shim");
276 // Normalize the type for better caching.
277 let bare_fn_ty = tcx.normalize_associated_type(&bare_fn_ty);
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,
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);
290 // A by-value fn item is ignored, so the shim has
291 // the same signature as the original function.
299 let bare_fn_ty_maybe_ref = if is_by_ref {
300 tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty)
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; }
311 debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
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 {
318 &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
321 ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
326 bug!("trans_fn_pointer_shim invoked on invalid type: {}",
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,
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,
345 debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
349 symbol_names::internal_name_from_type_and_suffix(ccx,
352 let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
353 attributes::set_frame_pointer_elimination(ccx, llfn);
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);
360 let llargs = get_params(fcx.llfn);
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
366 Load(bcx, llargs[self_idx])
372 let dest = fcx.llretslotptr.get();
374 let callee = Callee {
375 data: Fn(llfnpointer),
378 bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
380 fcx.finish(bcx, DebugLoc::None);
382 ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
387 /// Translates a reference to a fn/method item, monomorphizing and
388 /// inlining as it goes.
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>,
397 substs: &'tcx Substs<'tcx>)
398 -> (ValueRef, Ty<'tcx>) {
401 debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
403 assert!(!substs.needs_infer());
404 assert!(!substs.has_escaping_regions());
405 assert!(!substs.has_param_types());
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);
412 if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
413 return (llfn, fn_ty);
416 let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
417 TransItem::Fn(instance));
418 debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
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
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.
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.
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.
444 let fn_ptr_ty = match fn_ty.sty {
445 ty::TyFnDef(_, _, fty) => {
446 // Create a fn pointer with the substituted signature.
449 _ => bug!("expected fn item type, found {}", fn_ty)
451 let llptrty = type_of::type_of(ccx, fn_ptr_ty);
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)
458 debug!("get_fn: not casting pointer!");
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!");
466 let attrs = ccx.tcx().get_attrs(def_id);
467 attributes::from_fn_attrs(ccx, &attrs, llfn);
469 let is_local_def = ccx.shared().translation_items().borrow()
470 .contains(&TransItem::Fn(instance));
472 // FIXME(eddyb) Doubt all extern fn should allow unwinding.
473 attributes::unwind(llfn, true);
475 llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
482 ccx.instances().borrow_mut().insert(instance, llfn);
487 // ______________________________________________________________________
490 fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
492 callee: Callee<'tcx>,
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.
506 let fn_ret = callee.ty.fn_ret();
507 let fn_ty = callee.direct_fn_type(ccx, &[]);
509 let mut callee = match callee.data {
510 NamedTupleConstructor(_) | Intrinsic => {
511 bug!("{:?} calls should not go through Callee::call", callee);
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());
521 let mut llargs = Vec::new();
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());
528 llargs.push(llretslot);
533 llargs.push(args[0]);
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..]);
540 _ => llargs.extend_from_slice(args)
543 let llfn = match callee {
545 _ => bug!("expected fn pointer callee, found {:?}", callee)
548 let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
549 if !bcx.unreachable.get() {
550 fn_ty.apply_attrs_callsite(llret);
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
557 if !fn_ty.ret.is_indirect() {
558 if let Some(llretslot) = opt_llretslot {
559 fn_ty.ret.store(&bcx.build(), llret, llretslot);
564 if fn_ret.0.is_never() {
568 Result::new(bcx, llret)