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::AutorefArg::*;
18 pub use self::CalleeData::*;
19 pub use self::CallArgs::*;
21 use arena::TypedArena;
27 use metadata::csearch;
30 use middle::subst::{Subst, Substs};
37 use trans::cleanup::CleanupMethods;
49 use trans::monomorphize;
50 use trans::type_::Type;
52 use middle::ty::{self, Ty};
53 use middle::ty::MethodCall;
54 use util::ppaux::Repr;
55 use util::ppaux::ty_to_string;
57 use syntax::abi as synabi;
63 pub struct MethodData {
68 pub enum CalleeData<'tcx> {
69 // Constructor for enum variant/tuple-like-struct
71 NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr),
73 // Represents a (possibly monomorphized) top-level fn item or method
74 // item. Note that this is just the fn-ptr and is not a Rust closure
75 // value (which is a pair).
76 Fn(/* llfn */ ValueRef),
78 Intrinsic(ast::NodeId, subst::Substs<'tcx>),
83 pub struct Callee<'blk, 'tcx: 'blk> {
84 pub bcx: Block<'blk, 'tcx>,
85 pub data: CalleeData<'tcx>,
88 fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
89 -> Callee<'blk, 'tcx> {
90 let _icx = push_ctxt("trans_callee");
91 debug!("callee::trans(expr={})", expr.repr(bcx.tcx()));
93 // pick out special kinds of expressions that can be called:
94 if let ast::ExprPath(_) = expr.node {
95 return trans_def(bcx, bcx.def(expr.id), expr);
98 // any other expressions are closures:
99 return datum_callee(bcx, expr);
101 fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
102 -> Callee<'blk, 'tcx> {
103 let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
105 ty::ty_bare_fn(..) => {
106 let llval = datum.to_llscalarish(bcx);
113 bcx.tcx().sess.span_bug(
115 &format!("type of callee is neither bare-fn nor closure: \
117 bcx.ty_to_string(datum.ty))[]);
122 fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef)
123 -> Callee<'blk, 'tcx> {
130 fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
132 ref_expr: &ast::Expr)
133 -> Callee<'blk, 'tcx> {
134 debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
135 let expr_ty = node_id_type(bcx, ref_expr.id);
137 def::DefFn(did, _) if {
138 let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
139 let maybe_ast_node = maybe_def_id.and_then(|def_id| bcx.tcx().map
141 match maybe_ast_node {
142 Some(ast_map::NodeStructCtor(_)) => true,
146 let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
147 bcx.fcx.param_substs);
150 data: NamedTupleConstructor(substs, 0)
153 def::DefFn(did, _) if match expr_ty.sty {
154 ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
157 let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
158 bcx.fcx.param_substs);
159 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
160 Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
162 def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) |
163 def::DefStaticMethod(did, def::FromImpl(_)) => {
164 fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
165 bcx.fcx.param_substs).val)
167 def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) |
168 def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => {
169 fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
173 bcx.fcx.param_substs).val)
175 def::DefVariant(tid, vid, _) => {
176 let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
177 let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
178 bcx.fcx.param_substs);
180 // Nullary variants are not callable
181 assert!(vinfo.args.len() > 0u);
185 data: NamedTupleConstructor(substs, vinfo.disr_val)
188 def::DefStruct(_) => {
189 let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
190 bcx.fcx.param_substs);
193 data: NamedTupleConstructor(substs, 0)
199 def::DefUpvar(..) => {
200 datum_callee(bcx, ref_expr)
202 def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
203 def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
204 def::DefUse(..) | def::DefTyParamBinder(..) |
205 def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) |
206 def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
207 bcx.tcx().sess.span_bug(
209 &format!("cannot translate def {:?} \
210 to a callable thing!", def)[]);
216 /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
217 /// pointer. This may require monomorphization or inlining.
218 pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
220 node: ExprOrMethodCall,
221 param_substs: &subst::Substs<'tcx>)
222 -> Datum<'tcx, Rvalue> {
223 let _icx = push_ctxt("trans_fn_ref");
225 let substs = node_id_substs(ccx, node, param_substs);
226 debug!("trans_fn_ref(def_id={}, node={:?}, substs={})",
227 def_id.repr(ccx.tcx()),
229 substs.repr(ccx.tcx()));
230 trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
233 fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
236 substs: subst::Substs<'tcx>)
237 -> Callee<'blk, 'tcx> {
240 data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
243 bcx.fcx.param_substs,
248 /// Translates an adapter that implements the `Fn` trait for a fn
249 /// pointer. This is basically the equivalent of something like:
252 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
253 /// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
259 /// but for the bare function type given.
260 pub fn trans_fn_pointer_shim<'a, 'tcx>(
261 ccx: &'a CrateContext<'a, 'tcx>,
262 bare_fn_ty: Ty<'tcx>)
265 let _icx = push_ctxt("trans_fn_pointer_shim");
268 let bare_fn_ty = erase_regions(tcx, &bare_fn_ty);
269 match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
270 Some(&llval) => { return llval; }
274 debug!("trans_fn_pointer_shim(bare_fn_ty={})",
275 bare_fn_ty.repr(tcx));
277 // This is an impl of `Fn` trait, so receiver is `&self`.
278 let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty);
280 // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
281 // which is the fn pointer, and `args`, which is the arguments tuple.
282 let (opt_def_id, sig) =
283 match bare_fn_ty.sty {
284 ty::ty_bare_fn(opt_def_id,
285 &ty::BareFnTy { unsafety: ast::Unsafety::Normal,
292 tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
293 bare_fn_ty.repr(tcx))[]);
296 let sig = ty::erase_late_bound_regions(tcx, sig);
297 let tuple_input_ty = ty::mk_tup(tcx, sig.inputs.to_vec());
298 let tuple_fn_ty = ty::mk_bare_fn(tcx,
300 tcx.mk_bare_fn(ty::BareFnTy {
301 unsafety: ast::Unsafety::Normal,
302 abi: synabi::RustCall,
303 sig: ty::Binder(ty::FnSig {
304 inputs: vec![bare_fn_ty_ref,
309 debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
313 link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
316 decl_internal_rust_fn(ccx,
321 let block_arena = TypedArena::new();
322 let empty_substs = Substs::trans_empty();
323 let fcx = new_fn_ctxt(ccx,
331 let mut bcx = init_function(&fcx, false, sig.output);
333 // the first argument (`self`) will be ptr to the the fn pointer
335 Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
337 // the remaining arguments will be the untupled values
341 .map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32))
343 assert!(!fcx.needs_ret_allocas);
345 let dest = fcx.llretslotptr.get().map(|_|
346 expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
349 bcx = trans_call_inner(bcx,
352 |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
356 finish_fn(&fcx, bcx, sig.output);
358 ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
363 /// Translates a reference to a fn/method item, monomorphizing and
364 /// inlining as it goes.
368 /// - `ccx`: the crate context
369 /// - `def_id`: def id of the fn or method item being referenced
370 /// - `node`: node id of the reference to the fn/method, if applicable.
371 /// This parameter may be zero; but, if so, the resulting value may not
372 /// have the right type, so it must be cast before being used.
373 /// - `param_substs`: if the `node` is in a polymorphic function, these
374 /// are the substitutions required to monomorphize its type
375 /// - `substs`: values for each of the fn/method's parameters
376 pub fn trans_fn_ref_with_substs<'a, 'tcx>(
377 ccx: &CrateContext<'a, 'tcx>,
379 node: ExprOrMethodCall,
380 param_substs: &subst::Substs<'tcx>,
381 substs: subst::Substs<'tcx>)
382 -> Datum<'tcx, Rvalue>
384 let _icx = push_ctxt("trans_fn_ref_with_substs");
387 debug!("trans_fn_ref_with_substs(def_id={}, node={:?}, \
388 param_substs={}, substs={})",
391 param_substs.repr(tcx),
394 assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
395 assert!(substs.types.all(|t| !ty::type_has_escaping_regions(*t)));
396 let substs = substs.erase_regions();
398 // Load the info for the appropriate trait if necessary.
399 match ty::trait_of_item(tcx, def_id) {
402 ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
406 // We need to do a bunch of special handling for default methods.
407 // We need to modify the def_id and our substs in order to monomorphize
409 let (is_default, def_id, substs) = match ty::provided_source(tcx, def_id) {
410 None => (false, def_id, substs),
412 // There are two relevant substitutions when compiling
413 // default methods. First, there is the substitution for
414 // the type parameters of the impl we are using and the
415 // method we are calling. This substitution is the substs
416 // argument we already have.
417 // In order to compile a default method, though, we need
418 // to consider another substitution: the substitution for
419 // the type parameters on trait; the impl we are using
420 // implements the trait at some particular type
421 // parameters, and we need to substitute for those first.
422 // So, what we need to do is find this substitution and
423 // compose it with the one we already have.
425 let impl_id = ty::impl_or_trait_item(tcx, def_id).container()
427 let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id);
428 match impl_or_trait_item {
429 ty::MethodTraitItem(method) => {
430 let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap();
432 // Compute the first substitution
434 ty::make_substs_for_receiver_types(tcx, &*trait_ref, &*method)
438 let new_substs = first_subst.subst(tcx, &substs);
440 debug!("trans_fn_with_vtables - default method: \
441 substs = {}, trait_subst = {}, \
442 first_subst = {}, new_subst = {}",
443 substs.repr(tcx), trait_ref.substs.repr(tcx),
444 first_subst.repr(tcx), new_substs.repr(tcx));
446 (true, source_id, new_substs)
448 ty::TypeTraitItem(_) => {
449 tcx.sess.bug("trans_fn_ref_with_vtables() tried \
450 to translate an associated type?!")
456 // If this is an unboxed closure, redirect to it.
457 match closure::get_or_create_declaration_if_unboxed_closure(ccx,
461 Some(llfn) => return llfn,
464 // Check whether this fn has an inlined copy and, if so, redirect
465 // def_id to the local id of the inlined copy.
466 let def_id = inline::maybe_instantiate_inline(ccx, def_id);
468 // We must monomorphise if the fn has type parameters, is a default method,
469 // or is a named tuple constructor.
470 let must_monomorphise = if !substs.types.is_empty() || is_default {
472 } else if def_id.krate == ast::LOCAL_CRATE {
473 let map_node = session::expect(
475 tcx.map.find(def_id.node),
476 || "local item should be in ast map".to_string());
479 ast_map::NodeVariant(v) => match v.node.kind {
480 ast::TupleVariantKind(ref args) => args.len() > 0,
483 ast_map::NodeStructCtor(_) => true,
490 // Create a monomorphic version of generic functions
491 if must_monomorphise {
492 // Should be either intra-crate or inlined.
493 assert_eq!(def_id.krate, ast::LOCAL_CRATE);
495 let opt_ref_id = match node {
496 ExprId(id) => if id != 0 { Some(id) } else { None },
497 MethodCallKey(_) => None,
500 let (val, fn_ty, must_cast) =
501 monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id);
502 if must_cast && node != ExprId(0) {
503 // Monotype of the REFERENCE to the function (type params
505 let ref_ty = match node {
506 ExprId(id) => ty::node_id_to_type(tcx, id),
507 MethodCallKey(method_call) => {
508 (*tcx.method_map.borrow())[method_call].ty
511 let ref_ty = monomorphize::apply_param_substs(tcx,
514 let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
515 if llptrty != val_ty(val) {
516 let val = consts::ptrcast(val, llptrty);
517 return Datum::new(val, ref_ty, Rvalue::new(ByValue));
520 return Datum::new(val, fn_ty, Rvalue::new(ByValue));
523 // Type scheme of the function item (may have type params)
524 let fn_type_scheme = ty::lookup_item_type(tcx, def_id);
525 let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty);
527 // Find the actual function pointer.
529 if def_id.krate == ast::LOCAL_CRATE {
530 // Internal reference.
531 get_item_val(ccx, def_id.node)
533 // External reference.
534 trans_external_path(ccx, def_id, fn_type)
538 // This is subtle and surprising, but sometimes we have to bitcast
539 // the resulting fn pointer. The reason has to do with external
540 // functions. If you have two crates that both bind the same C
541 // library, they may not use precisely the same types: for
542 // example, they will probably each declare their own structs,
543 // which are distinct types from LLVM's point of view (nominal
546 // Now, if those two crates are linked into an application, and
547 // they contain inlined code, you can wind up with a situation
548 // where both of those functions wind up being loaded into this
549 // application simultaneously. In that case, the same function
550 // (from LLVM's point of view) requires two types. But of course
551 // LLVM won't allow one function to have two types.
553 // What we currently do, therefore, is declare the function with
554 // one of the two types (whichever happens to come first) and then
555 // bitcast as needed when the function is referenced to make sure
556 // it has the type we expect.
558 // This can occur on either a crate-local or crate-external
559 // reference. It also occurs when testing libcore and in some
560 // other weird situations. Annoying.
561 let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
562 let llptrty = llty.ptr_to();
563 if val_ty(val) != llptrty {
564 debug!("trans_fn_ref_with_vtables(): casting pointer!");
565 val = consts::ptrcast(val, llptrty);
567 debug!("trans_fn_ref_with_vtables(): not casting pointer!");
570 Datum::new(val, fn_type, Rvalue::new(ByValue))
573 // ______________________________________________________________________
576 pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
579 args: CallArgs<'a, 'tcx>,
581 -> Block<'blk, 'tcx> {
582 let _icx = push_ctxt("trans_call");
583 trans_call_inner(in_cx,
584 Some(common::expr_info(call_ex)),
585 expr_ty_adjusted(in_cx, f),
586 |cx, _| trans(cx, f),
591 pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
594 args: CallArgs<'a, 'tcx>,
596 -> Block<'blk, 'tcx> {
597 let _icx = push_ctxt("trans_method_call");
598 debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx()));
599 let method_call = MethodCall::expr(call_ex.id);
600 let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
603 Some(common::expr_info(call_ex)),
604 monomorphize_type(bcx, method_ty),
605 |cx, arg_cleanup_scope| {
606 meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
612 pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
615 dest: Option<expr::Dest>)
616 -> Result<'blk, 'tcx> {
617 let fty = if did.krate == ast::LOCAL_CRATE {
618 ty::node_id_to_type(bcx.tcx(), did.node)
620 csearch::get_type(bcx.tcx(), did).ty
622 callee::trans_call_inner(bcx,
626 trans_fn_ref_with_substs_to_callee(bcx,
629 subst::Substs::trans_empty())
635 /// This behemoth of a function translates function calls. Unfortunately, in order to generate more
636 /// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two
637 /// functions seems like a good idea).
639 /// In particular, for lang items, it is invoked with a dest of None, and in that case the return
640 /// value contains the result of the fn. The lang item must not return a structural type or else
641 /// all heck breaks loose.
643 /// For non-lang items, `dest` is always Some, and hence the result is written into memory
644 /// somewhere. Nonetheless we return the actual return value of the function.
645 pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
646 call_info: Option<NodeInfo>,
649 args: CallArgs<'a, 'tcx>,
650 dest: Option<expr::Dest>)
651 -> Result<'blk, 'tcx> where
652 F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>,
654 // Introduce a temporary cleanup scope that will contain cleanups
655 // for the arguments while they are being evaluated. The purpose
656 // this cleanup is to ensure that, should a panic occur while
657 // evaluating argument N, the values for arguments 0...N-1 are all
658 // cleaned up. If no panic occurs, the values are handed off to
659 // the callee, and hence none of the cleanups in this temporary
660 // scope will ever execute.
663 let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
665 let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
666 let mut bcx = callee.bcx;
668 let (abi, ret_ty) = match callee_ty.sty {
669 ty::ty_bare_fn(_, ref f) => {
670 let output = ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output());
673 _ => panic!("expected bare rust fn or closure in trans_call_inner")
676 let (llfn, llenv, llself) = match callee.data {
681 (d.llfn, None, Some(d.llself))
683 Intrinsic(node, substs) => {
684 assert!(abi == synabi::RustIntrinsic);
685 assert!(dest.is_some());
687 let call_info = call_info.expect("no call info for intrinsic call?");
688 return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
689 arg_cleanup_scope, args,
690 dest.unwrap(), substs,
693 NamedTupleConstructor(substs, disr) => {
694 assert!(dest.is_some());
695 fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
697 let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
698 return base::trans_named_tuple_constructor(bcx,
707 // Intrinsics should not become actual functions.
708 // We trans them in place in `trans_intrinsic_call`
709 assert!(abi != synabi::RustIntrinsic);
711 let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall;
713 // Generate a location to store the result. If the user does
714 // not care about the result, just make a stack slot.
715 let opt_llretslot = dest.and_then(|dest| match dest {
716 expr::SaveIn(dst) => Some(dst),
718 let ret_ty = match ret_ty {
719 ty::FnConverging(ret_ty) => ret_ty,
720 ty::FnDiverging => ty::mk_nil(ccx.tcx())
723 type_of::return_uses_outptr(ccx, ret_ty) ||
724 type_needs_drop(bcx.tcx(), ret_ty) {
725 // Push the out-pointer if we use an out-pointer for this
726 // return type, otherwise push "undef".
727 if type_is_zero_size(ccx, ret_ty) {
728 let llty = type_of::type_of(ccx, ret_ty);
729 Some(C_undef(llty.ptr_to()))
731 Some(alloc_ty(bcx, ret_ty, "__llret"))
739 let mut llresult = unsafe {
740 llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
743 // The code below invokes the function, using either the Rust
744 // conventions (if it is a rust fn) or the native conventions
745 // (otherwise). The important part is that, when all is said
746 // and done, either the return value of the function will have been
747 // written in opt_llretslot (if it is Some) or `llresult` will be
748 // set appropriately (otherwise).
750 let mut llargs = Vec::new();
752 if let (ty::FnConverging(ret_ty), Some(llretslot)) = (ret_ty, opt_llretslot) {
753 if type_of::return_uses_outptr(ccx, ret_ty) {
754 llargs.push(llretslot);
758 // Push the environment (or a trait object's self).
759 match (llenv, llself) {
760 (Some(llenv), None) => llargs.push(llenv),
761 (None, Some(llself)) => llargs.push(llself),
765 // Push the arguments.
766 bcx = trans_args(bcx,
770 cleanup::CustomScope(arg_cleanup_scope),
774 fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
776 // Invoke the actual rust fn and update bcx/llresult.
777 let (llret, b) = base::invoke(bcx,
785 // If the Rust convention for this type is return via
786 // the return value, copy it into llretslot.
787 match (opt_llretslot, ret_ty) {
788 (Some(llretslot), ty::FnConverging(ret_ty)) => {
789 if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
790 !type_is_zero_size(bcx.ccx(), ret_ty)
792 store_ty(bcx, llret, llretslot, ret_ty)
798 // Lang items are the only case where dest is None, and
799 // they are always Rust fns.
800 assert!(dest.is_some());
802 let mut llargs = Vec::new();
803 let arg_tys = match args {
804 ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(),
805 _ => panic!("expected arg exprs.")
807 bcx = trans_args(bcx,
811 cleanup::CustomScope(arg_cleanup_scope),
814 fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
816 bcx = foreign::trans_native_call(bcx, callee_ty,
817 llfn, opt_llretslot.unwrap(),
821 fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
823 // If the caller doesn't care about the result of this fn call,
824 // drop the temporary slot we made.
825 match (dest, opt_llretslot, ret_ty) {
826 (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
827 // drop the value if it is not being saved.
828 bcx = glue::drop_ty(bcx, llretslot, ret_ty, call_info);
829 call_lifetime_end(bcx, llretslot);
834 if ret_ty == ty::FnDiverging {
838 Result::new(bcx, llresult)
841 pub enum CallArgs<'a, 'tcx> {
842 // Supply value of arguments as a list of expressions that must be
843 // translated. This is used in the common case of `foo(bar, qux)`.
844 ArgExprs(&'a [P<ast::Expr>]),
846 // Supply value of arguments as a list of LLVM value refs; frequently
847 // used with lang items and so forth, when the argument is an internal
849 ArgVals(&'a [ValueRef]),
851 // For overloaded operators: `(lhs, Vec(rhs, rhs_id), autoref)`. `lhs`
852 // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
853 // the right-hand-side arguments (if any). `autoref` indicates whether the `rhs`
854 // arguments should be auto-referenced
855 ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
857 // Supply value of arguments as a list of expressions that must be
858 // translated, for overloaded call operators.
859 ArgOverloadedCall(Vec<&'a ast::Expr>),
862 fn trans_args_under_call_abi<'blk, 'tcx>(
863 mut bcx: Block<'blk, 'tcx>,
864 arg_exprs: &[P<ast::Expr>],
866 llargs: &mut Vec<ValueRef>,
867 arg_cleanup_scope: cleanup::ScopeId,
872 ty::erase_late_bound_regions(
873 bcx.tcx(), &ty::ty_fn_args(fn_ty));
875 // Translate the `self` argument first.
877 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
878 llargs.push(unpack_result!(bcx, {
887 // Now untuple the rest of the arguments.
888 let tuple_expr = &arg_exprs[1];
889 let tuple_type = node_id_type(bcx, tuple_expr.id);
891 match tuple_type.sty {
892 ty::ty_tup(ref field_types) => {
893 let tuple_datum = unpack_datum!(bcx,
894 expr::trans(bcx, &**tuple_expr));
895 let tuple_lvalue_datum =
897 tuple_datum.to_lvalue_datum(bcx,
900 let repr = adt::represent_type(bcx.ccx(), tuple_type);
901 let repr_ptr = &*repr;
902 for i in range(0, field_types.len()) {
903 let arg_datum = tuple_lvalue_datum.get_element(
907 adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
909 let arg_datum = arg_datum.to_expr_datum();
911 unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
913 unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx));
914 llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope));
918 bcx.sess().span_bug(tuple_expr.span,
919 "argument to `.call()` wasn't a tuple?!")
926 fn trans_overloaded_call_args<'blk, 'tcx>(
927 mut bcx: Block<'blk, 'tcx>,
928 arg_exprs: Vec<&ast::Expr>,
930 llargs: &mut Vec<ValueRef>,
931 arg_cleanup_scope: cleanup::ScopeId,
933 -> Block<'blk, 'tcx> {
934 // Translate the `self` argument first.
935 let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(fn_ty));
937 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
938 llargs.push(unpack_result!(bcx, {
947 // Now untuple the rest of the arguments.
948 let tuple_type = arg_tys[1];
949 match tuple_type.sty {
950 ty::ty_tup(ref field_types) => {
951 for (i, &field_type) in field_types.iter().enumerate() {
953 unpack_datum!(bcx, expr::trans(bcx, arg_exprs[i + 1]));
954 llargs.push(unpack_result!(bcx, {
964 bcx.sess().span_bug(arg_exprs[0].span,
965 "argument to `.call()` wasn't a tuple?!")
972 pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
973 args: CallArgs<'a, 'tcx>,
975 llargs: &mut Vec<ValueRef>,
976 arg_cleanup_scope: cleanup::ScopeId,
979 -> Block<'blk, 'tcx> {
980 debug!("trans_args(abi={})", abi);
982 let _icx = push_ctxt("trans_args");
983 let arg_tys = ty::erase_late_bound_regions(cx.tcx(), &ty::ty_fn_args(fn_ty));
984 let variadic = ty::fn_is_variadic(fn_ty);
988 // First we figure out the caller's view of the types of the arguments.
989 // This will be needed if this is a generic call, because the callee has
990 // to cast her view of the arguments to the caller's view.
992 ArgExprs(arg_exprs) => {
993 if abi == synabi::RustCall {
994 // This is only used for direct calls to the `call`,
995 // `call_mut` or `call_once` functions.
996 return trans_args_under_call_abi(cx,
1004 let num_formal_args = arg_tys.len();
1005 for (i, arg_expr) in arg_exprs.iter().enumerate() {
1006 if i == 0 && ignore_self {
1009 let arg_ty = if i >= num_formal_args {
1011 expr_ty_adjusted(cx, &**arg_expr)
1016 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &**arg_expr));
1017 llargs.push(unpack_result!(bcx, {
1018 trans_arg_datum(bcx, arg_ty, arg_datum,
1024 ArgOverloadedCall(arg_exprs) => {
1025 return trans_overloaded_call_args(cx,
1032 ArgOverloadedOp(lhs, rhs, autoref) => {
1035 llargs.push(unpack_result!(bcx, {
1036 trans_arg_datum(bcx, arg_tys[0], lhs,
1041 assert_eq!(arg_tys.len(), 1 + rhs.len());
1042 for (rhs, rhs_id) in rhs.into_iter() {
1043 llargs.push(unpack_result!(bcx, {
1044 trans_arg_datum(bcx, arg_tys[1], rhs,
1046 if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg })
1051 llargs.push_all(vs);
1059 pub enum AutorefArg {
1061 DoAutorefArg(ast::NodeId)
1064 pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1065 formal_arg_ty: Ty<'tcx>,
1066 arg_datum: Datum<'tcx, Expr>,
1067 arg_cleanup_scope: cleanup::ScopeId,
1068 autoref_arg: AutorefArg)
1069 -> Result<'blk, 'tcx> {
1070 let _icx = push_ctxt("trans_arg_datum");
1072 let ccx = bcx.ccx();
1074 debug!("trans_arg_datum({})",
1075 formal_arg_ty.repr(bcx.tcx()));
1077 let arg_datum_ty = arg_datum.ty;
1079 debug!(" arg datum: {}", arg_datum.to_string(bcx.ccx()));
1082 // FIXME(#3548) use the adjustments table
1084 DoAutorefArg(arg_id) => {
1085 // We will pass argument by reference
1086 // We want an lvalue, so that we can pass by reference and
1087 let arg_datum = unpack_datum!(
1088 bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
1089 val = arg_datum.val;
1092 // Make this an rvalue, since we are going to be
1093 // passing ownership.
1094 let arg_datum = unpack_datum!(
1095 bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
1097 // Now that arg_datum is owned, get it into the appropriate
1098 // mode (ref vs value).
1099 let arg_datum = unpack_datum!(
1100 bcx, arg_datum.to_appropriate_datum(bcx));
1102 // Technically, ownership of val passes to the callee.
1103 // However, we must cleanup should we panic before the
1104 // callee is actually invoked.
1105 val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
1109 if formal_arg_ty != arg_datum_ty {
1110 // this could happen due to e.g. subtyping
1111 let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
1112 debug!("casting actual type ({}) to match formal ({})",
1113 bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
1114 debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
1115 ty_to_string(bcx.tcx(), formal_arg_ty));
1116 val = PointerCast(bcx, val, llformal_arg_ty);
1119 debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
1120 Result::new(bcx, val)