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
;
24 use llvm
::{self, ValueRef, get_params}
;
25 use metadata
::cstore
::LOCAL_CRATE
;
27 use middle
::def_id
::DefId
;
28 use middle
::infer
::normalize_associated_type
;
30 use middle
::subst
::{Substs}
;
31 use rustc
::front
::map
as hir_map
;
38 use trans
::cleanup
::CleanupMethods
;
39 use trans
::common
::{self, Block
, Result
, NodeIdAndSpan
, ExprId
, CrateContext
,
40 ExprOrMethodCall
, FunctionContext
, MethodCallKey
};
43 use trans
::debuginfo
::{DebugLoc, ToDebugLoc}
;
51 use trans
::monomorphize
;
52 use trans
::type_
::Type
;
54 use middle
::ty
::{self, Ty, HasTypeFlags, RegionEscape}
;
55 use middle
::ty
::MethodCall
;
58 use syntax
::abi
as synabi
;
62 #[derive(Copy, Clone)]
63 pub struct MethodData
{
68 pub enum CalleeData
<'tcx
> {
69 // Constructor for enum variant/tuple-like-struct
71 NamedTupleConstructor(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
>,
89 fn trans
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, expr
: &hir
::Expr
)
90 -> Callee
<'blk
, 'tcx
> {
91 let _icx
= push_ctxt("trans_callee");
92 debug
!("callee::trans(expr={:?})", expr
);
94 // pick out special kinds of expressions that can be called:
96 hir
::ExprPath(..) => {
97 return trans_def(bcx
, bcx
.def(expr
.id
), expr
);
102 // any other expressions are closures:
103 return datum_callee(bcx
, expr
);
105 fn datum_callee
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, expr
: &hir
::Expr
)
106 -> Callee
<'blk
, 'tcx
> {
107 let DatumBlock { bcx, datum, .. }
= expr
::trans(bcx
, expr
);
109 ty
::TyBareFn(..) => {
113 data
: Fn(datum
.to_llscalarish(bcx
))
117 bcx
.tcx().sess
.span_bug(
119 &format
!("type of callee is neither bare-fn nor closure: {}",
125 fn fn_callee
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, datum
: Datum
<'tcx
, Rvalue
>)
126 -> Callee
<'blk
, 'tcx
> {
134 fn trans_def
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
136 ref_expr
: &hir
::Expr
)
137 -> Callee
<'blk
, 'tcx
> {
138 debug
!("trans_def(def={:?}, ref_expr={:?})", def
, ref_expr
);
139 let expr_ty
= common
::node_id_type(bcx
, ref_expr
.id
);
141 def
::DefFn(did
, _
) if {
142 let maybe_def_id
= inline
::get_local_instance(bcx
.ccx(), did
);
143 let maybe_ast_node
= maybe_def_id
.and_then(|def_id
| {
144 let node_id
= bcx
.tcx().map
.as_local_node_id(def_id
).unwrap();
145 bcx
.tcx().map
.find(node_id
)
147 match maybe_ast_node
{
148 Some(hir_map
::NodeStructCtor(_
)) => true,
154 data
: NamedTupleConstructor(0),
158 def
::DefFn(did
, _
) if match expr_ty
.sty
{
159 ty
::TyBareFn(_
, ref f
) => f
.abi
== synabi
::RustIntrinsic
||
160 f
.abi
== synabi
::PlatformIntrinsic
,
163 let substs
= common
::node_id_substs(bcx
.ccx(),
165 bcx
.fcx
.param_substs
);
166 let def_id
= inline
::maybe_instantiate_inline(bcx
.ccx(), did
);
167 let node_id
= bcx
.tcx().map
.as_local_node_id(def_id
).unwrap();
168 Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
170 def
::DefFn(did
, _
) => {
171 fn_callee(bcx
, trans_fn_ref(bcx
.ccx(), did
, ExprId(ref_expr
.id
),
172 bcx
.fcx
.param_substs
))
174 def
::DefMethod(meth_did
) => {
175 let method_item
= bcx
.tcx().impl_or_trait_item(meth_did
);
176 let fn_datum
= match method_item
.container() {
177 ty
::ImplContainer(_
) => {
178 trans_fn_ref(bcx
.ccx(), meth_did
,
180 bcx
.fcx
.param_substs
)
182 ty
::TraitContainer(trait_did
) => {
183 meth
::trans_static_method_callee(bcx
.ccx(),
187 bcx
.fcx
.param_substs
)
190 fn_callee(bcx
, fn_datum
)
192 def
::DefVariant(tid
, vid
, _
) => {
193 let vinfo
= bcx
.tcx().lookup_adt_def(tid
).variant_with_id(vid
);
194 assert_eq
!(vinfo
.kind(), ty
::VariantKind
::Tuple
);
198 data
: NamedTupleConstructor(vinfo
.disr_val
),
202 def
::DefStruct(_
) => {
205 data
: NamedTupleConstructor(0),
211 def
::DefAssociatedConst(..) |
213 def
::DefUpvar(..) => {
214 datum_callee(bcx
, ref_expr
)
216 def
::DefMod(..) | def
::DefForeignMod(..) | def
::DefTrait(..) |
217 def
::DefTy(..) | def
::DefPrimTy(..) | def
::DefAssociatedTy(..) |
218 def
::DefUse(..) | def
::DefLabel(..) | def
::DefTyParam(..) |
219 def
::DefSelfTy(..) => {
220 bcx
.tcx().sess
.span_bug(
222 &format
!("cannot translate def {:?} \
223 to a callable thing!", def
));
229 /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
230 /// pointer. This may require monomorphization or inlining.
231 pub fn trans_fn_ref
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
233 node
: ExprOrMethodCall
,
234 param_substs
: &'tcx subst
::Substs
<'tcx
>)
235 -> Datum
<'tcx
, Rvalue
> {
236 let _icx
= push_ctxt("trans_fn_ref");
238 let substs
= common
::node_id_substs(ccx
, node
, param_substs
);
239 debug
!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
243 trans_fn_ref_with_substs(ccx
, def_id
, node
, param_substs
, substs
)
246 /// Translates an adapter that implements the `Fn` trait for a fn
247 /// pointer. This is basically the equivalent of something like:
250 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
251 /// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
257 /// but for the bare function type given.
258 pub fn trans_fn_pointer_shim
<'a
, 'tcx
>(
259 ccx
: &'a CrateContext
<'a
, 'tcx
>,
260 closure_kind
: ty
::ClosureKind
,
261 bare_fn_ty
: Ty
<'tcx
>)
264 let _icx
= push_ctxt("trans_fn_pointer_shim");
267 // Normalize the type for better caching.
268 let bare_fn_ty
= tcx
.erase_regions(&bare_fn_ty
);
270 // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
271 let is_by_ref
= match closure_kind
{
272 ty
::FnClosureKind
| ty
::FnMutClosureKind
=> true,
273 ty
::FnOnceClosureKind
=> false,
275 let bare_fn_ty_maybe_ref
= if is_by_ref
{
276 tcx
.mk_imm_ref(tcx
.mk_region(ty
::ReStatic
), bare_fn_ty
)
281 // Check if we already trans'd this shim.
282 match ccx
.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref
) {
283 Some(&llval
) => { return llval; }
287 debug
!("trans_fn_pointer_shim(bare_fn_ty={:?})",
290 // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
291 // which is the fn pointer, and `args`, which is the arguments tuple.
292 let (opt_def_id
, sig
) =
293 match bare_fn_ty
.sty
{
294 ty
::TyBareFn(opt_def_id
,
295 &ty
::BareFnTy
{ unsafety
: hir
::Unsafety
::Normal
,
302 tcx
.sess
.bug(&format
!("trans_fn_pointer_shim invoked on invalid type: {}",
306 let sig
= tcx
.erase_late_bound_regions(sig
);
307 let tuple_input_ty
= tcx
.mk_tup(sig
.inputs
.to_vec());
308 let tuple_fn_ty
= tcx
.mk_fn(opt_def_id
,
309 tcx
.mk_bare_fn(ty
::BareFnTy
{
310 unsafety
: hir
::Unsafety
::Normal
,
311 abi
: synabi
::RustCall
,
312 sig
: ty
::Binder(ty
::FnSig
{
313 inputs
: vec
![bare_fn_ty_maybe_ref
,
318 debug
!("tuple_fn_ty: {:?}", tuple_fn_ty
);
321 let function_name
= link
::mangle_internal_name_by_type_and_seq(ccx
, bare_fn_ty
,
323 let llfn
= declare
::declare_internal_rust_fn(ccx
, &function_name
[..], tuple_fn_ty
);
326 let empty_substs
= tcx
.mk_substs(Substs
::trans_empty());
327 let (block_arena
, fcx
): (TypedArena
<_
>, FunctionContext
);
328 block_arena
= TypedArena
::new();
329 fcx
= new_fn_ctxt(ccx
,
337 let mut bcx
= init_function(&fcx
, false, sig
.output
);
339 let llargs
= get_params(fcx
.llfn
);
341 let self_idx
= fcx
.arg_offset();
342 // the first argument (`self`) will be ptr to the fn pointer
343 let llfnpointer
= if is_by_ref
{
344 Load(bcx
, llargs
[self_idx
])
349 assert
!(!fcx
.needs_ret_allocas
);
351 let dest
= fcx
.llretslotptr
.get().map(|_
|
352 expr
::SaveIn(fcx
.get_ret_slot(bcx
, sig
.output
, "ret_slot"))
355 bcx
= trans_call_inner(bcx
, DebugLoc
::None
, |bcx
, _
| {
358 data
: Fn(llfnpointer
),
361 }, ArgVals(&llargs
[(self_idx
+ 1)..]), dest
).bcx
;
363 finish_fn(&fcx
, bcx
, sig
.output
, DebugLoc
::None
);
365 ccx
.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref
, llfn
);
370 /// Translates a reference to a fn/method item, monomorphizing and
371 /// inlining as it goes.
375 /// - `ccx`: the crate context
376 /// - `def_id`: def id of the fn or method item being referenced
377 /// - `node`: node id of the reference to the fn/method, if applicable.
378 /// This parameter may be zero; but, if so, the resulting value may not
379 /// have the right type, so it must be cast before being used.
380 /// - `param_substs`: if the `node` is in a polymorphic function, these
381 /// are the substitutions required to monomorphize its type
382 /// - `substs`: values for each of the fn/method's parameters
383 pub fn trans_fn_ref_with_substs
<'a
, 'tcx
>(
384 ccx
: &CrateContext
<'a
, 'tcx
>,
386 node
: ExprOrMethodCall
,
387 param_substs
: &'tcx subst
::Substs
<'tcx
>,
388 substs
: subst
::Substs
<'tcx
>)
389 -> Datum
<'tcx
, Rvalue
>
391 let _icx
= push_ctxt("trans_fn_ref_with_substs");
394 debug
!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
395 param_substs={:?}, substs={:?})",
401 assert
!(!substs
.types
.needs_infer());
402 assert
!(!substs
.types
.has_escaping_regions());
403 let substs
= substs
.erase_regions();
405 // Check whether this fn has an inlined copy and, if so, redirect
406 // def_id to the local id of the inlined copy.
407 let def_id
= inline
::maybe_instantiate_inline(ccx
, def_id
);
409 fn is_named_tuple_constructor(tcx
: &ty
::ctxt
, def_id
: DefId
) -> bool
{
410 let node_id
= match tcx
.map
.as_local_node_id(def_id
) {
412 None
=> { return false; }
414 let map_node
= session
::expect(
416 tcx
.map
.find(node_id
),
417 || "local item should be in ast map".to_string());
420 hir_map
::NodeVariant(v
) => {
421 v
.node
.data
.is_tuple()
423 hir_map
::NodeStructCtor(_
) => true,
427 let must_monomorphise
=
428 !substs
.types
.is_empty() || is_named_tuple_constructor(tcx
, def_id
);
430 debug
!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
431 def_id
, must_monomorphise
);
433 // Create a monomorphic version of generic functions
434 if must_monomorphise
{
435 // Should be either intra-crate or inlined.
436 assert_eq
!(def_id
.krate
, LOCAL_CRATE
);
438 let opt_ref_id
= match node
{
439 ExprId(id
) => if id
!= 0 { Some(id) }
else { None }
,
440 MethodCallKey(_
) => None
,
443 let substs
= tcx
.mk_substs(substs
);
444 let (val
, fn_ty
, must_cast
) =
445 monomorphize
::monomorphic_fn(ccx
, def_id
, substs
, opt_ref_id
);
446 if must_cast
&& node
!= ExprId(0) {
447 // Monotype of the REFERENCE to the function (type params
449 let ref_ty
= match node
{
450 ExprId(id
) => tcx
.node_id_to_type(id
),
451 MethodCallKey(method_call
) => {
452 tcx
.tables
.borrow().method_map
[&method_call
].ty
455 let ref_ty
= monomorphize
::apply_param_substs(tcx
,
458 let llptrty
= type_of
::type_of_fn_from_ty(ccx
, ref_ty
).ptr_to();
459 if llptrty
!= common
::val_ty(val
) {
460 let val
= consts
::ptrcast(val
, llptrty
);
461 return Datum
::new(val
, ref_ty
, Rvalue
::new(ByValue
));
464 return Datum
::new(val
, fn_ty
, Rvalue
::new(ByValue
));
467 // Type scheme of the function item (may have type params)
468 let fn_type_scheme
= tcx
.lookup_item_type(def_id
);
469 let fn_type
= normalize_associated_type(tcx
, &fn_type_scheme
.ty
);
471 // Find the actual function pointer.
473 if let Some(node_id
) = ccx
.tcx().map
.as_local_node_id(def_id
) {
474 // Internal reference.
475 get_item_val(ccx
, node_id
)
477 // External reference.
478 trans_external_path(ccx
, def_id
, fn_type
)
482 // This is subtle and surprising, but sometimes we have to bitcast
483 // the resulting fn pointer. The reason has to do with external
484 // functions. If you have two crates that both bind the same C
485 // library, they may not use precisely the same types: for
486 // example, they will probably each declare their own structs,
487 // which are distinct types from LLVM's point of view (nominal
490 // Now, if those two crates are linked into an application, and
491 // they contain inlined code, you can wind up with a situation
492 // where both of those functions wind up being loaded into this
493 // application simultaneously. In that case, the same function
494 // (from LLVM's point of view) requires two types. But of course
495 // LLVM won't allow one function to have two types.
497 // What we currently do, therefore, is declare the function with
498 // one of the two types (whichever happens to come first) and then
499 // bitcast as needed when the function is referenced to make sure
500 // it has the type we expect.
502 // This can occur on either a crate-local or crate-external
503 // reference. It also occurs when testing libcore and in some
504 // other weird situations. Annoying.
505 let llty
= type_of
::type_of_fn_from_ty(ccx
, fn_type
);
506 let llptrty
= llty
.ptr_to();
507 if common
::val_ty(val
) != llptrty
{
508 debug
!("trans_fn_ref_with_substs(): casting pointer!");
509 val
= consts
::ptrcast(val
, llptrty
);
511 debug
!("trans_fn_ref_with_substs(): not casting pointer!");
514 Datum
::new(val
, fn_type
, Rvalue
::new(ByValue
))
517 // ______________________________________________________________________
520 pub fn trans_call
<'a
, 'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
521 call_expr
: &hir
::Expr
,
523 args
: CallArgs
<'a
, 'tcx
>,
525 -> Block
<'blk
, 'tcx
> {
526 let _icx
= push_ctxt("trans_call");
527 trans_call_inner(bcx
,
528 call_expr
.debug_loc(),
529 |bcx
, _
| trans(bcx
, f
),
534 pub fn trans_method_call
<'a
, 'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
535 call_expr
: &hir
::Expr
,
537 args
: CallArgs
<'a
, 'tcx
>,
539 -> Block
<'blk
, 'tcx
> {
540 let _icx
= push_ctxt("trans_method_call");
541 debug
!("trans_method_call(call_expr={:?})", call_expr
);
542 let method_call
= MethodCall
::expr(call_expr
.id
);
545 call_expr
.debug_loc(),
546 |cx
, arg_cleanup_scope
| {
547 meth
::trans_method_callee(cx
, method_call
, Some(rcvr
), arg_cleanup_scope
)
553 pub fn trans_lang_call
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
556 dest
: Option
<expr
::Dest
>,
558 -> Result
<'blk
, 'tcx
> {
559 callee
::trans_call_inner(bcx
, debug_loc
, |bcx
, _
| {
560 let datum
= trans_fn_ref_with_substs(bcx
.ccx(),
563 bcx
.fcx
.param_substs
,
564 subst
::Substs
::trans_empty());
570 }, ArgVals(args
), dest
)
573 /// This behemoth of a function translates function calls. Unfortunately, in
574 /// order to generate more efficient LLVM output at -O0, it has quite a complex
575 /// signature (refactoring this into two functions seems like a good idea).
577 /// In particular, for lang items, it is invoked with a dest of None, and in
578 /// that case the return value contains the result of the fn. The lang item must
579 /// not return a structural type or else all heck breaks loose.
581 /// For non-lang items, `dest` is always Some, and hence the result is written
582 /// into memory somewhere. Nonetheless we return the actual return value of the
584 pub fn trans_call_inner
<'a
, 'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
587 args
: CallArgs
<'a
, 'tcx
>,
588 dest
: Option
<expr
::Dest
>)
589 -> Result
<'blk
, 'tcx
> where
590 F
: FnOnce(Block
<'blk
, 'tcx
>, cleanup
::ScopeId
) -> Callee
<'blk
, 'tcx
>,
592 // Introduce a temporary cleanup scope that will contain cleanups
593 // for the arguments while they are being evaluated. The purpose
594 // this cleanup is to ensure that, should a panic occur while
595 // evaluating argument N, the values for arguments 0...N-1 are all
596 // cleaned up. If no panic occurs, the values are handed off to
597 // the callee, and hence none of the cleanups in this temporary
598 // scope will ever execute.
601 let arg_cleanup_scope
= fcx
.push_custom_cleanup_scope();
603 let callee
= get_callee(bcx
, cleanup
::CustomScope(arg_cleanup_scope
));
604 let mut bcx
= callee
.bcx
;
606 let (abi
, ret_ty
) = match callee
.ty
.sty
{
607 ty
::TyBareFn(_
, ref f
) => {
608 let output
= bcx
.tcx().erase_late_bound_regions(&f
.sig
.output());
611 _
=> panic
!("expected bare rust fn or closure in trans_call_inner")
614 let (llfn
, llself
) = match callee
.data
{
619 (d
.llfn
, Some(d
.llself
))
621 Intrinsic(node
, substs
) => {
622 assert
!(abi
== synabi
::RustIntrinsic
|| abi
== synabi
::PlatformIntrinsic
);
623 assert
!(dest
.is_some());
625 let call_info
= match debug_loc
{
626 DebugLoc
::At(id
, span
) => NodeIdAndSpan { id: id, span: span }
,
628 bcx
.sess().bug("No call info for intrinsic call?")
632 return intrinsic
::trans_intrinsic_call(bcx
, node
, callee
.ty
,
633 arg_cleanup_scope
, args
,
634 dest
.unwrap(), substs
,
637 NamedTupleConstructor(disr
) => {
638 assert
!(dest
.is_some());
639 fcx
.pop_custom_cleanup_scope(arg_cleanup_scope
);
641 return base
::trans_named_tuple_constructor(bcx
,
650 // Intrinsics should not become actual functions.
651 // We trans them in place in `trans_intrinsic_call`
652 assert
!(abi
!= synabi
::RustIntrinsic
&& abi
!= synabi
::PlatformIntrinsic
);
654 let is_rust_fn
= abi
== synabi
::Rust
|| abi
== synabi
::RustCall
;
656 // Generate a location to store the result. If the user does
657 // not care about the result, just make a stack slot.
658 let opt_llretslot
= dest
.and_then(|dest
| match dest
{
659 expr
::SaveIn(dst
) => Some(dst
),
661 let ret_ty
= match ret_ty
{
662 ty
::FnConverging(ret_ty
) => ret_ty
,
663 ty
::FnDiverging
=> ccx
.tcx().mk_nil()
666 type_of
::return_uses_outptr(ccx
, ret_ty
) ||
667 bcx
.fcx
.type_needs_drop(ret_ty
) {
668 // Push the out-pointer if we use an out-pointer for this
669 // return type, otherwise push "undef".
670 if common
::type_is_zero_size(ccx
, ret_ty
) {
671 let llty
= type_of
::type_of(ccx
, ret_ty
);
672 Some(common
::C_undef(llty
.ptr_to()))
674 let llresult
= alloc_ty(bcx
, ret_ty
, "__llret");
675 call_lifetime_start(bcx
, llresult
);
684 let mut llresult
= unsafe {
685 llvm
::LLVMGetUndef(Type
::nil(ccx
).ptr_to().to_ref())
688 // The code below invokes the function, using either the Rust
689 // conventions (if it is a rust fn) or the native conventions
690 // (otherwise). The important part is that, when all is said
691 // and done, either the return value of the function will have been
692 // written in opt_llretslot (if it is Some) or `llresult` will be
693 // set appropriately (otherwise).
695 let mut llargs
= Vec
::new();
697 if let (ty
::FnConverging(ret_ty
), Some(mut llretslot
)) = (ret_ty
, opt_llretslot
) {
698 if type_of
::return_uses_outptr(ccx
, ret_ty
) {
699 let llformal_ret_ty
= type_of
::type_of(ccx
, ret_ty
).ptr_to();
700 let llret_ty
= common
::val_ty(llretslot
);
701 if llformal_ret_ty
!= llret_ty
{
702 // this could happen due to e.g. subtyping
703 debug
!("casting actual return type ({}) to match formal ({})",
704 bcx
.llty_str(llret_ty
), bcx
.llty_str(llformal_ret_ty
));
705 llretslot
= PointerCast(bcx
, llretslot
, llformal_ret_ty
);
707 llargs
.push(llretslot
);
711 // Push a trait object's self.
712 if let Some(llself
) = llself
{
716 // Push the arguments.
717 bcx
= trans_args(bcx
,
721 cleanup
::CustomScope(arg_cleanup_scope
),
725 fcx
.scopes
.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
727 // Invoke the actual rust fn and update bcx/llresult.
728 let (llret
, b
) = base
::invoke(bcx
,
736 // If the Rust convention for this type is return via
737 // the return value, copy it into llretslot.
738 match (opt_llretslot
, ret_ty
) {
739 (Some(llretslot
), ty
::FnConverging(ret_ty
)) => {
740 if !type_of
::return_uses_outptr(bcx
.ccx(), ret_ty
) &&
741 !common
::type_is_zero_size(bcx
.ccx(), ret_ty
)
743 store_ty(bcx
, llret
, llretslot
, ret_ty
)
749 // Lang items are the only case where dest is None, and
750 // they are always Rust fns.
751 assert
!(dest
.is_some());
753 let mut llargs
= Vec
::new();
754 let arg_tys
= match args
{
755 ArgExprs(a
) => a
.iter().map(|x
| common
::expr_ty_adjusted(bcx
, &**x
)).collect(),
756 _
=> panic
!("expected arg exprs.")
758 bcx
= trans_args(bcx
,
762 cleanup
::CustomScope(arg_cleanup_scope
),
765 fcx
.scopes
.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
767 bcx
= foreign
::trans_native_call(bcx
,
770 opt_llretslot
.unwrap(),
776 fcx
.pop_and_trans_custom_cleanup_scope(bcx
, arg_cleanup_scope
);
778 // If the caller doesn't care about the result of this fn call,
779 // drop the temporary slot we made.
780 match (dest
, opt_llretslot
, ret_ty
) {
781 (Some(expr
::Ignore
), Some(llretslot
), ty
::FnConverging(ret_ty
)) => {
782 // drop the value if it is not being saved.
783 bcx
= glue
::drop_ty(bcx
,
787 call_lifetime_end(bcx
, llretslot
);
792 if ret_ty
== ty
::FnDiverging
{
796 Result
::new(bcx
, llresult
)
799 pub enum CallArgs
<'a
, 'tcx
> {
800 // Supply value of arguments as a list of expressions that must be
801 // translated. This is used in the common case of `foo(bar, qux)`.
802 ArgExprs(&'a
[P
<hir
::Expr
>]),
804 // Supply value of arguments as a list of LLVM value refs; frequently
805 // used with lang items and so forth, when the argument is an internal
807 ArgVals(&'a
[ValueRef
]),
809 // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
810 // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
811 // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
812 // arguments should be auto-referenced
813 ArgOverloadedOp(Datum
<'tcx
, Expr
>, Option
<(Datum
<'tcx
, Expr
>, ast
::NodeId
)>, bool
),
815 // Supply value of arguments as a list of expressions that must be
816 // translated, for overloaded call operators.
817 ArgOverloadedCall(Vec
<&'a hir
::Expr
>),
820 fn trans_args_under_call_abi
<'blk
, 'tcx
>(
821 mut bcx
: Block
<'blk
, 'tcx
>,
822 arg_exprs
: &[P
<hir
::Expr
>],
824 llargs
: &mut Vec
<ValueRef
>,
825 arg_cleanup_scope
: cleanup
::ScopeId
,
829 let args
= bcx
.tcx().erase_late_bound_regions(&fn_ty
.fn_args());
831 // Translate the `self` argument first.
833 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, &*arg_exprs
[0]));
834 bcx
= trans_arg_datum(bcx
,
842 // Now untuple the rest of the arguments.
843 let tuple_expr
= &arg_exprs
[1];
844 let tuple_type
= common
::node_id_type(bcx
, tuple_expr
.id
);
846 match tuple_type
.sty
{
847 ty
::TyTuple(ref field_types
) => {
848 let tuple_datum
= unpack_datum
!(bcx
,
849 expr
::trans(bcx
, &**tuple_expr
));
850 let tuple_lvalue_datum
=
852 tuple_datum
.to_lvalue_datum(bcx
,
855 let repr
= adt
::represent_type(bcx
.ccx(), tuple_type
);
856 let repr_ptr
= &*repr
;
857 for (i
, field_type
) in field_types
.iter().enumerate() {
858 let arg_datum
= tuple_lvalue_datum
.get_element(
862 adt
::trans_field_ptr(bcx
, repr_ptr
, srcval
, 0, i
)
864 bcx
= trans_arg_datum(bcx
,
873 bcx
.sess().span_bug(tuple_expr
.span
,
874 "argument to `.call()` wasn't a tuple?!")
881 fn trans_overloaded_call_args
<'blk
, 'tcx
>(
882 mut bcx
: Block
<'blk
, 'tcx
>,
883 arg_exprs
: Vec
<&hir
::Expr
>,
885 llargs
: &mut Vec
<ValueRef
>,
886 arg_cleanup_scope
: cleanup
::ScopeId
,
888 -> Block
<'blk
, 'tcx
> {
889 // Translate the `self` argument first.
890 let arg_tys
= bcx
.tcx().erase_late_bound_regions( &fn_ty
.fn_args());
892 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, arg_exprs
[0]));
893 bcx
= trans_arg_datum(bcx
,
901 // Now untuple the rest of the arguments.
902 let tuple_type
= arg_tys
[1];
903 match tuple_type
.sty
{
904 ty
::TyTuple(ref field_types
) => {
905 for (i
, &field_type
) in field_types
.iter().enumerate() {
907 unpack_datum
!(bcx
, expr
::trans(bcx
, arg_exprs
[i
+ 1]));
908 bcx
= trans_arg_datum(bcx
,
917 bcx
.sess().span_bug(arg_exprs
[0].span
,
918 "argument to `.call()` wasn't a tuple?!")
925 pub fn trans_args
<'a
, 'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
926 args
: CallArgs
<'a
, 'tcx
>,
928 llargs
: &mut Vec
<ValueRef
>,
929 arg_cleanup_scope
: cleanup
::ScopeId
,
932 -> Block
<'blk
, 'tcx
> {
933 debug
!("trans_args(abi={})", abi
);
935 let _icx
= push_ctxt("trans_args");
936 let arg_tys
= cx
.tcx().erase_late_bound_regions(&fn_ty
.fn_args());
937 let variadic
= fn_ty
.fn_sig().0.variadic
;
941 // First we figure out the caller's view of the types of the arguments.
942 // This will be needed if this is a generic call, because the callee has
943 // to cast her view of the arguments to the caller's view.
945 ArgExprs(arg_exprs
) => {
946 if abi
== synabi
::RustCall
{
947 // This is only used for direct calls to the `call`,
948 // `call_mut` or `call_once` functions.
949 return trans_args_under_call_abi(cx
,
957 let num_formal_args
= arg_tys
.len();
958 for (i
, arg_expr
) in arg_exprs
.iter().enumerate() {
959 if i
== 0 && ignore_self
{
962 let arg_ty
= if i
>= num_formal_args
{
964 common
::expr_ty_adjusted(cx
, &**arg_expr
)
969 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, &**arg_expr
));
970 bcx
= trans_arg_datum(bcx
, arg_ty
, arg_datum
,
976 ArgOverloadedCall(arg_exprs
) => {
977 return trans_overloaded_call_args(cx
,
984 ArgOverloadedOp(lhs
, rhs
, autoref
) => {
987 bcx
= trans_arg_datum(bcx
, arg_tys
[0], lhs
,
992 if let Some((rhs
, rhs_id
)) = rhs
{
993 assert_eq
!(arg_tys
.len(), 2);
994 bcx
= trans_arg_datum(bcx
, arg_tys
[1], rhs
,
996 if autoref { DoAutorefArg(rhs_id) }
else { DontAutorefArg }
,
999 assert_eq
!(arg_tys
.len(), 1);
1003 llargs
.push_all(vs
);
1010 #[derive(Copy, Clone)]
1011 pub enum AutorefArg
{
1013 DoAutorefArg(ast
::NodeId
)
1016 pub fn trans_arg_datum
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
1017 formal_arg_ty
: Ty
<'tcx
>,
1018 arg_datum
: Datum
<'tcx
, Expr
>,
1019 arg_cleanup_scope
: cleanup
::ScopeId
,
1020 autoref_arg
: AutorefArg
,
1021 llargs
: &mut Vec
<ValueRef
>)
1022 -> Block
<'blk
, 'tcx
> {
1023 let _icx
= push_ctxt("trans_arg_datum");
1025 let ccx
= bcx
.ccx();
1027 debug
!("trans_arg_datum({:?})",
1030 let arg_datum_ty
= arg_datum
.ty
;
1032 debug
!(" arg datum: {}", arg_datum
.to_string(bcx
.ccx()));
1035 // FIXME(#3548) use the adjustments table
1037 DoAutorefArg(arg_id
) => {
1038 // We will pass argument by reference
1039 // We want an lvalue, so that we can pass by reference and
1040 let arg_datum
= unpack_datum
!(
1041 bcx
, arg_datum
.to_lvalue_datum(bcx
, "arg", arg_id
));
1042 val
= arg_datum
.val
;
1044 DontAutorefArg
if common
::type_is_fat_ptr(bcx
.tcx(), arg_datum_ty
) &&
1045 !bcx
.fcx
.type_needs_drop(arg_datum_ty
) => {
1049 // Make this an rvalue, since we are going to be
1050 // passing ownership.
1051 let arg_datum
= unpack_datum
!(
1052 bcx
, arg_datum
.to_rvalue_datum(bcx
, "arg"));
1054 // Now that arg_datum is owned, get it into the appropriate
1055 // mode (ref vs value).
1056 let arg_datum
= unpack_datum
!(
1057 bcx
, arg_datum
.to_appropriate_datum(bcx
));
1059 // Technically, ownership of val passes to the callee.
1060 // However, we must cleanup should we panic before the
1061 // callee is actually invoked.
1062 val
= arg_datum
.add_clean(bcx
.fcx
, arg_cleanup_scope
);
1066 if type_of
::arg_is_indirect(ccx
, formal_arg_ty
) && formal_arg_ty
!= arg_datum_ty
{
1067 // this could happen due to e.g. subtyping
1068 let llformal_arg_ty
= type_of
::type_of_explicit_arg(ccx
, formal_arg_ty
);
1069 debug
!("casting actual type ({}) to match formal ({})",
1070 bcx
.val_to_string(val
), bcx
.llty_str(llformal_arg_ty
));
1071 debug
!("Rust types: {:?}; {:?}", arg_datum_ty
,
1073 val
= PointerCast(bcx
, val
, llformal_arg_ty
);
1076 debug
!("--- trans_arg_datum passing {}", bcx
.val_to_string(val
));
1078 if common
::type_is_fat_ptr(bcx
.tcx(), formal_arg_ty
) {
1079 llargs
.push(Load(bcx
, expr
::get_dataptr(bcx
, val
)));
1080 llargs
.push(Load(bcx
, expr
::get_meta(bcx
, val
)));