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
;
23 use llvm
::{self, ValueRef, get_params}
;
24 use middle
::cstore
::LOCAL_CRATE
;
26 use middle
::def_id
::DefId
;
29 use middle
::subst
::{Substs}
;
30 use rustc
::front
::map
as hir_map
;
37 use trans
::cleanup
::CleanupMethods
;
38 use trans
::common
::{self, Block
, Result
, NodeIdAndSpan
, ExprId
, CrateContext
,
39 ExprOrMethodCall
, FunctionContext
, MethodCallKey
};
42 use trans
::debuginfo
::{DebugLoc, ToDebugLoc}
;
50 use trans
::monomorphize
;
51 use trans
::type_
::Type
;
54 use middle
::ty
::{self, Ty, TypeFoldable}
;
55 use middle
::ty
::MethodCall
;
63 #[derive(Copy, Clone)]
64 pub struct MethodData
{
69 pub enum CalleeData
<'tcx
> {
70 // Constructor for enum variant/tuple-like-struct
72 NamedTupleConstructor(Disr
),
74 // Represents a (possibly monomorphized) top-level fn item or method
75 // item. Note that this is just the fn-ptr and is not a Rust closure
76 // value (which is a pair).
77 Fn(/* llfn */ ValueRef
),
79 Intrinsic(ast
::NodeId
, subst
::Substs
<'tcx
>),
84 pub struct Callee
<'blk
, 'tcx
: 'blk
> {
85 pub bcx
: Block
<'blk
, 'tcx
>,
86 pub data
: CalleeData
<'tcx
>,
90 fn trans
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, expr
: &hir
::Expr
)
91 -> Callee
<'blk
, 'tcx
> {
92 let _icx
= push_ctxt("trans_callee");
93 debug
!("callee::trans(expr={:?})", expr
);
95 // pick out special kinds of expressions that can be called:
97 hir
::ExprPath(..) => {
98 return trans_def(bcx
, bcx
.def(expr
.id
), expr
);
103 // any other expressions are closures:
104 return datum_callee(bcx
, expr
);
106 fn datum_callee
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, expr
: &hir
::Expr
)
107 -> Callee
<'blk
, 'tcx
> {
108 let DatumBlock { bcx, datum, .. }
= expr
::trans(bcx
, expr
);
110 ty
::TyBareFn(..) => {
114 data
: Fn(datum
.to_llscalarish(bcx
))
118 bcx
.tcx().sess
.span_bug(
120 &format
!("type of callee is neither bare-fn nor closure: {}",
126 fn fn_callee
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, datum
: Datum
<'tcx
, Rvalue
>)
127 -> Callee
<'blk
, 'tcx
> {
135 fn trans_def
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
137 ref_expr
: &hir
::Expr
)
138 -> Callee
<'blk
, 'tcx
> {
139 debug
!("trans_def(def={:?}, ref_expr={:?})", def
, ref_expr
);
140 let expr_ty
= common
::node_id_type(bcx
, ref_expr
.id
);
143 let maybe_def_id
= inline
::get_local_instance(bcx
.ccx(), did
);
144 let maybe_ast_node
= maybe_def_id
.and_then(|def_id
| {
145 let node_id
= bcx
.tcx().map
.as_local_node_id(def_id
).unwrap();
146 bcx
.tcx().map
.find(node_id
)
148 match maybe_ast_node
{
149 Some(hir_map
::NodeStructCtor(_
)) => true,
155 data
: NamedTupleConstructor(Disr(0)),
159 Def
::Fn(did
) if match expr_ty
.sty
{
160 ty
::TyBareFn(_
, ref f
) => f
.abi
== Abi
::RustIntrinsic
||
161 f
.abi
== Abi
::PlatformIntrinsic
,
164 let substs
= common
::node_id_substs(bcx
.ccx(),
166 bcx
.fcx
.param_substs
);
167 let def_id
= inline
::maybe_instantiate_inline(bcx
.ccx(), did
);
168 let node_id
= bcx
.tcx().map
.as_local_node_id(def_id
).unwrap();
169 Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
172 fn_callee(bcx
, trans_fn_ref(bcx
.ccx(), did
, ExprId(ref_expr
.id
),
173 bcx
.fcx
.param_substs
))
175 Def
::Method(meth_did
) => {
176 let method_item
= bcx
.tcx().impl_or_trait_item(meth_did
);
177 let fn_datum
= match method_item
.container() {
178 ty
::ImplContainer(_
) => {
179 trans_fn_ref(bcx
.ccx(), meth_did
,
181 bcx
.fcx
.param_substs
)
183 ty
::TraitContainer(trait_did
) => {
184 meth
::trans_static_method_callee(bcx
.ccx(),
188 bcx
.fcx
.param_substs
)
191 fn_callee(bcx
, fn_datum
)
193 Def
::Variant(tid
, vid
) => {
194 let vinfo
= bcx
.tcx().lookup_adt_def(tid
).variant_with_id(vid
);
195 assert_eq
!(vinfo
.kind(), ty
::VariantKind
::Tuple
);
199 data
: NamedTupleConstructor(Disr
::from(vinfo
.disr_val
)),
206 data
: NamedTupleConstructor(Disr(0)),
212 Def
::AssociatedConst(..) |
215 datum_callee(bcx
, ref_expr
)
217 Def
::Mod(..) | Def
::ForeignMod(..) | Def
::Trait(..) |
218 Def
::Enum(..) | Def
::TyAlias(..) | Def
::PrimTy(..) |
219 Def
::AssociatedTy(..) | Def
::Label(..) | Def
::TyParam(..) |
220 Def
::SelfTy(..) | Def
::Err
=> {
221 bcx
.tcx().sess
.span_bug(
223 &format
!("cannot translate def {:?} \
224 to a callable thing!", def
));
230 /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
231 /// pointer. This may require monomorphization or inlining.
232 pub fn trans_fn_ref
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
234 node
: ExprOrMethodCall
,
235 param_substs
: &'tcx subst
::Substs
<'tcx
>)
236 -> Datum
<'tcx
, Rvalue
> {
237 let _icx
= push_ctxt("trans_fn_ref");
239 let substs
= common
::node_id_substs(ccx
, node
, param_substs
);
240 debug
!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
244 trans_fn_ref_with_substs(ccx
, def_id
, node
, param_substs
, substs
)
247 /// Translates an adapter that implements the `Fn` trait for a fn
248 /// pointer. This is basically the equivalent of something like:
251 /// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
252 /// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
258 /// but for the bare function type given.
259 pub fn trans_fn_pointer_shim
<'a
, 'tcx
>(
260 ccx
: &'a CrateContext
<'a
, 'tcx
>,
261 closure_kind
: ty
::ClosureKind
,
262 bare_fn_ty
: Ty
<'tcx
>)
265 let _icx
= push_ctxt("trans_fn_pointer_shim");
268 // Normalize the type for better caching.
269 let bare_fn_ty
= tcx
.erase_regions(&bare_fn_ty
);
271 // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
272 let is_by_ref
= match closure_kind
{
273 ty
::FnClosureKind
| ty
::FnMutClosureKind
=> true,
274 ty
::FnOnceClosureKind
=> false,
276 let bare_fn_ty_maybe_ref
= if is_by_ref
{
277 tcx
.mk_imm_ref(tcx
.mk_region(ty
::ReStatic
), bare_fn_ty
)
282 // Check if we already trans'd this shim.
283 match ccx
.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref
) {
284 Some(&llval
) => { return llval; }
288 debug
!("trans_fn_pointer_shim(bare_fn_ty={:?})",
291 // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
292 // which is the fn pointer, and `args`, which is the arguments tuple.
293 let (opt_def_id
, sig
) =
294 match bare_fn_ty
.sty
{
295 ty
::TyBareFn(opt_def_id
,
296 &ty
::BareFnTy
{ unsafety
: hir
::Unsafety
::Normal
,
303 tcx
.sess
.bug(&format
!("trans_fn_pointer_shim invoked on invalid type: {}",
307 let sig
= tcx
.erase_late_bound_regions(sig
);
308 let sig
= infer
::normalize_associated_type(ccx
.tcx(), &sig
);
309 let tuple_input_ty
= tcx
.mk_tup(sig
.inputs
.to_vec());
310 let tuple_fn_ty
= tcx
.mk_fn(opt_def_id
,
311 tcx
.mk_bare_fn(ty
::BareFnTy
{
312 unsafety
: hir
::Unsafety
::Normal
,
314 sig
: ty
::Binder(ty
::FnSig
{
315 inputs
: vec
![bare_fn_ty_maybe_ref
,
320 debug
!("tuple_fn_ty: {:?}", tuple_fn_ty
);
323 let function_name
= link
::mangle_internal_name_by_type_and_seq(ccx
, bare_fn_ty
,
325 let llfn
= declare
::declare_internal_rust_fn(ccx
, &function_name
[..], tuple_fn_ty
);
328 let empty_substs
= tcx
.mk_substs(Substs
::trans_empty());
329 let (block_arena
, fcx
): (TypedArena
<_
>, FunctionContext
);
330 block_arena
= TypedArena
::new();
331 fcx
= new_fn_ctxt(ccx
,
339 let mut bcx
= init_function(&fcx
, false, sig
.output
);
341 let llargs
= get_params(fcx
.llfn
);
343 let self_idx
= fcx
.arg_offset();
344 // the first argument (`self`) will be ptr to the fn pointer
345 let llfnpointer
= if is_by_ref
{
346 Load(bcx
, llargs
[self_idx
])
351 assert
!(!fcx
.needs_ret_allocas
);
353 let dest
= fcx
.llretslotptr
.get().map(|_
|
354 expr
::SaveIn(fcx
.get_ret_slot(bcx
, sig
.output
, "ret_slot"))
357 bcx
= trans_call_inner(bcx
, DebugLoc
::None
, |bcx
, _
| {
360 data
: Fn(llfnpointer
),
363 }, ArgVals(&llargs
[(self_idx
+ 1)..]), dest
).bcx
;
365 finish_fn(&fcx
, bcx
, sig
.output
, DebugLoc
::None
);
367 ccx
.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref
, llfn
);
372 /// Translates a reference to a fn/method item, monomorphizing and
373 /// inlining as it goes.
377 /// - `ccx`: the crate context
378 /// - `def_id`: def id of the fn or method item being referenced
379 /// - `node`: node id of the reference to the fn/method, if applicable.
380 /// This parameter may be zero; but, if so, the resulting value may not
381 /// have the right type, so it must be cast before being used.
382 /// - `param_substs`: if the `node` is in a polymorphic function, these
383 /// are the substitutions required to monomorphize its type
384 /// - `substs`: values for each of the fn/method's parameters
385 pub fn trans_fn_ref_with_substs
<'a
, 'tcx
>(
386 ccx
: &CrateContext
<'a
, 'tcx
>,
388 node
: ExprOrMethodCall
,
389 param_substs
: &'tcx subst
::Substs
<'tcx
>,
390 substs
: subst
::Substs
<'tcx
>)
391 -> Datum
<'tcx
, Rvalue
>
393 let _icx
= push_ctxt("trans_fn_ref_with_substs");
396 debug
!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
397 param_substs={:?}, substs={:?})",
403 assert
!(!substs
.types
.needs_infer());
404 assert
!(!substs
.types
.has_escaping_regions());
405 let substs
= substs
.erase_regions();
407 // Check whether this fn has an inlined copy and, if so, redirect
408 // def_id to the local id of the inlined copy.
409 let def_id
= inline
::maybe_instantiate_inline(ccx
, def_id
);
411 fn is_named_tuple_constructor(tcx
: &ty
::ctxt
, def_id
: DefId
) -> bool
{
412 let node_id
= match tcx
.map
.as_local_node_id(def_id
) {
414 None
=> { return false; }
416 let map_node
= errors
::expect(
417 &tcx
.sess
.diagnostic(),
418 tcx
.map
.find(node_id
),
419 || "local item should be in ast map".to_string());
422 hir_map
::NodeVariant(v
) => {
423 v
.node
.data
.is_tuple()
425 hir_map
::NodeStructCtor(_
) => true,
429 let must_monomorphise
=
430 !substs
.types
.is_empty() || is_named_tuple_constructor(tcx
, def_id
);
432 debug
!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
433 def_id
, must_monomorphise
);
435 // Create a monomorphic version of generic functions
436 if must_monomorphise
{
437 // Should be either intra-crate or inlined.
438 assert_eq
!(def_id
.krate
, LOCAL_CRATE
);
440 let opt_ref_id
= match node
{
441 ExprId(id
) => if id
!= 0 { Some(id) }
else { None }
,
442 MethodCallKey(_
) => None
,
445 let substs
= tcx
.mk_substs(substs
);
446 let (val
, fn_ty
, must_cast
) =
447 monomorphize
::monomorphic_fn(ccx
, def_id
, substs
, opt_ref_id
);
448 if must_cast
&& node
!= ExprId(0) {
449 // Monotype of the REFERENCE to the function (type params
451 let ref_ty
= match node
{
452 ExprId(id
) => tcx
.node_id_to_type(id
),
453 MethodCallKey(method_call
) => {
454 tcx
.tables
.borrow().method_map
[&method_call
].ty
457 let ref_ty
= monomorphize
::apply_param_substs(tcx
,
460 let llptrty
= type_of
::type_of_fn_from_ty(ccx
, ref_ty
).ptr_to();
461 if llptrty
!= common
::val_ty(val
) {
462 let val
= consts
::ptrcast(val
, llptrty
);
463 return Datum
::new(val
, ref_ty
, Rvalue
::new(ByValue
));
466 return Datum
::new(val
, fn_ty
, Rvalue
::new(ByValue
));
469 // Type scheme of the function item (may have type params)
470 let fn_type_scheme
= tcx
.lookup_item_type(def_id
);
471 let fn_type
= infer
::normalize_associated_type(tcx
, &fn_type_scheme
.ty
);
473 // Find the actual function pointer.
475 if let Some(node_id
) = ccx
.tcx().map
.as_local_node_id(def_id
) {
476 // Internal reference.
477 get_item_val(ccx
, node_id
)
479 // External reference.
480 trans_external_path(ccx
, def_id
, fn_type
)
484 // This is subtle and surprising, but sometimes we have to bitcast
485 // the resulting fn pointer. The reason has to do with external
486 // functions. If you have two crates that both bind the same C
487 // library, they may not use precisely the same types: for
488 // example, they will probably each declare their own structs,
489 // which are distinct types from LLVM's point of view (nominal
492 // Now, if those two crates are linked into an application, and
493 // they contain inlined code, you can wind up with a situation
494 // where both of those functions wind up being loaded into this
495 // application simultaneously. In that case, the same function
496 // (from LLVM's point of view) requires two types. But of course
497 // LLVM won't allow one function to have two types.
499 // What we currently do, therefore, is declare the function with
500 // one of the two types (whichever happens to come first) and then
501 // bitcast as needed when the function is referenced to make sure
502 // it has the type we expect.
504 // This can occur on either a crate-local or crate-external
505 // reference. It also occurs when testing libcore and in some
506 // other weird situations. Annoying.
507 let llty
= type_of
::type_of_fn_from_ty(ccx
, fn_type
);
508 let llptrty
= llty
.ptr_to();
509 if common
::val_ty(val
) != llptrty
{
510 debug
!("trans_fn_ref_with_substs(): casting pointer!");
511 val
= consts
::ptrcast(val
, llptrty
);
513 debug
!("trans_fn_ref_with_substs(): not casting pointer!");
516 Datum
::new(val
, fn_type
, Rvalue
::new(ByValue
))
519 // ______________________________________________________________________
522 pub fn trans_call
<'a
, 'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
523 call_expr
: &hir
::Expr
,
525 args
: CallArgs
<'a
, 'tcx
>,
527 -> Block
<'blk
, 'tcx
> {
528 let _icx
= push_ctxt("trans_call");
529 trans_call_inner(bcx
,
530 call_expr
.debug_loc(),
531 |bcx
, _
| trans(bcx
, f
),
536 pub fn trans_method_call
<'a
, 'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
537 call_expr
: &hir
::Expr
,
539 args
: CallArgs
<'a
, 'tcx
>,
541 -> Block
<'blk
, 'tcx
> {
542 let _icx
= push_ctxt("trans_method_call");
543 debug
!("trans_method_call(call_expr={:?})", call_expr
);
544 let method_call
= MethodCall
::expr(call_expr
.id
);
547 call_expr
.debug_loc(),
548 |cx
, arg_cleanup_scope
| {
549 meth
::trans_method_callee(cx
, method_call
, Some(rcvr
), arg_cleanup_scope
)
555 pub fn trans_lang_call
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
558 dest
: Option
<expr
::Dest
>,
560 -> Result
<'blk
, 'tcx
> {
561 callee
::trans_call_inner(bcx
, debug_loc
, |bcx
, _
| {
562 let datum
= trans_fn_ref_with_substs(bcx
.ccx(),
565 bcx
.fcx
.param_substs
,
566 subst
::Substs
::trans_empty());
572 }, ArgVals(args
), dest
)
575 /// This behemoth of a function translates function calls. Unfortunately, in
576 /// order to generate more efficient LLVM output at -O0, it has quite a complex
577 /// signature (refactoring this into two functions seems like a good idea).
579 /// In particular, for lang items, it is invoked with a dest of None, and in
580 /// that case the return value contains the result of the fn. The lang item must
581 /// not return a structural type or else all heck breaks loose.
583 /// For non-lang items, `dest` is always Some, and hence the result is written
584 /// into memory somewhere. Nonetheless we return the actual return value of the
586 pub fn trans_call_inner
<'a
, 'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
589 args
: CallArgs
<'a
, 'tcx
>,
590 dest
: Option
<expr
::Dest
>)
591 -> Result
<'blk
, 'tcx
> where
592 F
: FnOnce(Block
<'blk
, 'tcx
>, cleanup
::ScopeId
) -> Callee
<'blk
, 'tcx
>,
594 // Introduce a temporary cleanup scope that will contain cleanups
595 // for the arguments while they are being evaluated. The purpose
596 // this cleanup is to ensure that, should a panic occur while
597 // evaluating argument N, the values for arguments 0...N-1 are all
598 // cleaned up. If no panic occurs, the values are handed off to
599 // the callee, and hence none of the cleanups in this temporary
600 // scope will ever execute.
603 let arg_cleanup_scope
= fcx
.push_custom_cleanup_scope();
605 let callee
= get_callee(bcx
, cleanup
::CustomScope(arg_cleanup_scope
));
606 let mut bcx
= callee
.bcx
;
608 let (abi
, ret_ty
) = match callee
.ty
.sty
{
609 ty
::TyBareFn(_
, ref f
) => {
610 let sig
= bcx
.tcx().erase_late_bound_regions(&f
.sig
);
611 let sig
= infer
::normalize_associated_type(bcx
.tcx(), &sig
);
614 _
=> panic
!("expected bare rust fn or closure in trans_call_inner")
617 let (llfn
, llself
) = match callee
.data
{
622 (d
.llfn
, Some(d
.llself
))
624 Intrinsic(node
, substs
) => {
625 assert
!(abi
== Abi
::RustIntrinsic
|| abi
== Abi
::PlatformIntrinsic
);
626 assert
!(dest
.is_some());
628 let call_info
= match debug_loc
{
629 DebugLoc
::At(id
, span
) => NodeIdAndSpan { id: id, span: span }
,
631 bcx
.sess().bug("No call info for intrinsic call?")
635 return intrinsic
::trans_intrinsic_call(bcx
, node
, callee
.ty
,
636 arg_cleanup_scope
, args
,
637 dest
.unwrap(), substs
,
640 NamedTupleConstructor(disr
) => {
641 assert
!(dest
.is_some());
642 fcx
.pop_custom_cleanup_scope(arg_cleanup_scope
);
644 return base
::trans_named_tuple_constructor(bcx
,
653 // Intrinsics should not become actual functions.
654 // We trans them in place in `trans_intrinsic_call`
655 assert
!(abi
!= Abi
::RustIntrinsic
&& abi
!= Abi
::PlatformIntrinsic
);
657 let is_rust_fn
= abi
== Abi
::Rust
|| abi
== Abi
::RustCall
;
659 // Generate a location to store the result. If the user does
660 // not care about the result, just make a stack slot.
661 let opt_llretslot
= dest
.and_then(|dest
| match dest
{
662 expr
::SaveIn(dst
) => Some(dst
),
664 let ret_ty
= match ret_ty
{
665 ty
::FnConverging(ret_ty
) => ret_ty
,
666 ty
::FnDiverging
=> ccx
.tcx().mk_nil()
669 type_of
::return_uses_outptr(ccx
, ret_ty
) ||
670 bcx
.fcx
.type_needs_drop(ret_ty
) {
671 // Push the out-pointer if we use an out-pointer for this
672 // return type, otherwise push "undef".
673 if common
::type_is_zero_size(ccx
, ret_ty
) {
674 let llty
= type_of
::type_of(ccx
, ret_ty
);
675 Some(common
::C_undef(llty
.ptr_to()))
677 let llresult
= alloc_ty(bcx
, ret_ty
, "__llret");
678 call_lifetime_start(bcx
, llresult
);
687 let mut llresult
= unsafe {
688 llvm
::LLVMGetUndef(Type
::nil(ccx
).ptr_to().to_ref())
691 // The code below invokes the function, using either the Rust
692 // conventions (if it is a rust fn) or the native conventions
693 // (otherwise). The important part is that, when all is said
694 // and done, either the return value of the function will have been
695 // written in opt_llretslot (if it is Some) or `llresult` will be
696 // set appropriately (otherwise).
698 let mut llargs
= Vec
::new();
700 if let (ty
::FnConverging(ret_ty
), Some(mut llretslot
)) = (ret_ty
, opt_llretslot
) {
701 if type_of
::return_uses_outptr(ccx
, ret_ty
) {
702 let llformal_ret_ty
= type_of
::type_of(ccx
, ret_ty
).ptr_to();
703 let llret_ty
= common
::val_ty(llretslot
);
704 if llformal_ret_ty
!= llret_ty
{
705 // this could happen due to e.g. subtyping
706 debug
!("casting actual return type ({}) to match formal ({})",
707 bcx
.llty_str(llret_ty
), bcx
.llty_str(llformal_ret_ty
));
708 llretslot
= PointerCast(bcx
, llretslot
, llformal_ret_ty
);
710 llargs
.push(llretslot
);
714 // Push a trait object's self.
715 if let Some(llself
) = llself
{
719 // Push the arguments.
720 bcx
= trans_args(bcx
,
724 cleanup
::CustomScope(arg_cleanup_scope
),
728 fcx
.scopes
.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
730 // Invoke the actual rust fn and update bcx/llresult.
731 let (llret
, b
) = base
::invoke(bcx
,
739 // If the Rust convention for this type is return via
740 // the return value, copy it into llretslot.
741 match (opt_llretslot
, ret_ty
) {
742 (Some(llretslot
), ty
::FnConverging(ret_ty
)) => {
743 if !type_of
::return_uses_outptr(bcx
.ccx(), ret_ty
) &&
744 !common
::type_is_zero_size(bcx
.ccx(), ret_ty
)
746 store_ty(bcx
, llret
, llretslot
, ret_ty
)
752 // Lang items are the only case where dest is None, and
753 // they are always Rust fns.
754 assert
!(dest
.is_some());
756 let mut llargs
= Vec
::new();
757 let arg_tys
= match args
{
758 ArgExprs(a
) => a
.iter().map(|x
| common
::expr_ty_adjusted(bcx
, &x
)).collect(),
759 _
=> panic
!("expected arg exprs.")
761 bcx
= trans_args(bcx
,
765 cleanup
::CustomScope(arg_cleanup_scope
),
768 fcx
.scopes
.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
770 bcx
= foreign
::trans_native_call(bcx
,
773 opt_llretslot
.unwrap(),
779 fcx
.pop_and_trans_custom_cleanup_scope(bcx
, arg_cleanup_scope
);
781 // If the caller doesn't care about the result of this fn call,
782 // drop the temporary slot we made.
783 match (dest
, opt_llretslot
, ret_ty
) {
784 (Some(expr
::Ignore
), Some(llretslot
), ty
::FnConverging(ret_ty
)) => {
785 // drop the value if it is not being saved.
786 bcx
= glue
::drop_ty(bcx
,
790 call_lifetime_end(bcx
, llretslot
);
795 if ret_ty
== ty
::FnDiverging
{
799 Result
::new(bcx
, llresult
)
802 pub enum CallArgs
<'a
, 'tcx
> {
803 // Supply value of arguments as a list of expressions that must be
804 // translated. This is used in the common case of `foo(bar, qux)`.
805 ArgExprs(&'a
[P
<hir
::Expr
>]),
807 // Supply value of arguments as a list of LLVM value refs; frequently
808 // used with lang items and so forth, when the argument is an internal
810 ArgVals(&'a
[ValueRef
]),
812 // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
813 // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
814 // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
815 // arguments should be auto-referenced
816 ArgOverloadedOp(Datum
<'tcx
, Expr
>, Option
<(Datum
<'tcx
, Expr
>, ast
::NodeId
)>, bool
),
818 // Supply value of arguments as a list of expressions that must be
819 // translated, for overloaded call operators.
820 ArgOverloadedCall(Vec
<&'a hir
::Expr
>),
823 fn trans_args_under_call_abi
<'blk
, 'tcx
>(
824 mut bcx
: Block
<'blk
, 'tcx
>,
825 arg_exprs
: &[P
<hir
::Expr
>],
827 llargs
: &mut Vec
<ValueRef
>,
828 arg_cleanup_scope
: cleanup
::ScopeId
,
832 let sig
= bcx
.tcx().erase_late_bound_regions(&fn_ty
.fn_sig());
833 let sig
= infer
::normalize_associated_type(bcx
.tcx(), &sig
);
834 let args
= sig
.inputs
;
836 // Translate the `self` argument first.
838 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, &arg_exprs
[0]));
839 bcx
= trans_arg_datum(bcx
,
847 // Now untuple the rest of the arguments.
848 let tuple_expr
= &arg_exprs
[1];
849 let tuple_type
= common
::node_id_type(bcx
, tuple_expr
.id
);
851 match tuple_type
.sty
{
852 ty
::TyTuple(ref field_types
) => {
853 let tuple_datum
= unpack_datum
!(bcx
,
854 expr
::trans(bcx
, &tuple_expr
));
855 let tuple_lvalue_datum
=
857 tuple_datum
.to_lvalue_datum(bcx
,
860 let repr
= adt
::represent_type(bcx
.ccx(), tuple_type
);
861 let repr_ptr
= &repr
;
862 for (i
, field_type
) in field_types
.iter().enumerate() {
863 let arg_datum
= tuple_lvalue_datum
.get_element(
867 adt
::trans_field_ptr(bcx
, repr_ptr
, srcval
, Disr(0), i
)
869 bcx
= trans_arg_datum(bcx
,
878 bcx
.sess().span_bug(tuple_expr
.span
,
879 "argument to `.call()` wasn't a tuple?!")
886 fn trans_overloaded_call_args
<'blk
, 'tcx
>(
887 mut bcx
: Block
<'blk
, 'tcx
>,
888 arg_exprs
: Vec
<&hir
::Expr
>,
890 llargs
: &mut Vec
<ValueRef
>,
891 arg_cleanup_scope
: cleanup
::ScopeId
,
893 -> Block
<'blk
, 'tcx
> {
894 // Translate the `self` argument first.
895 let sig
= bcx
.tcx().erase_late_bound_regions(&fn_ty
.fn_sig());
896 let sig
= infer
::normalize_associated_type(bcx
.tcx(), &sig
);
897 let arg_tys
= sig
.inputs
;
900 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, arg_exprs
[0]));
901 bcx
= trans_arg_datum(bcx
,
909 // Now untuple the rest of the arguments.
910 let tuple_type
= arg_tys
[1];
911 match tuple_type
.sty
{
912 ty
::TyTuple(ref field_types
) => {
913 for (i
, &field_type
) in field_types
.iter().enumerate() {
915 unpack_datum
!(bcx
, expr
::trans(bcx
, arg_exprs
[i
+ 1]));
916 bcx
= trans_arg_datum(bcx
,
925 bcx
.sess().span_bug(arg_exprs
[0].span
,
926 "argument to `.call()` wasn't a tuple?!")
933 pub fn trans_args
<'a
, 'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
934 args
: CallArgs
<'a
, 'tcx
>,
936 llargs
: &mut Vec
<ValueRef
>,
937 arg_cleanup_scope
: cleanup
::ScopeId
,
940 -> Block
<'blk
, 'tcx
> {
941 debug
!("trans_args(abi={})", abi
);
943 let _icx
= push_ctxt("trans_args");
944 let sig
= cx
.tcx().erase_late_bound_regions(&fn_ty
.fn_sig());
945 let sig
= infer
::normalize_associated_type(cx
.tcx(), &sig
);
946 let arg_tys
= sig
.inputs
;
947 let variadic
= sig
.variadic
;
951 // First we figure out the caller's view of the types of the arguments.
952 // This will be needed if this is a generic call, because the callee has
953 // to cast her view of the arguments to the caller's view.
955 ArgExprs(arg_exprs
) => {
956 if abi
== Abi
::RustCall
{
957 // This is only used for direct calls to the `call`,
958 // `call_mut` or `call_once` functions.
959 return trans_args_under_call_abi(cx
,
967 let num_formal_args
= arg_tys
.len();
968 for (i
, arg_expr
) in arg_exprs
.iter().enumerate() {
969 if i
== 0 && ignore_self
{
972 let arg_ty
= if i
>= num_formal_args
{
974 common
::expr_ty_adjusted(cx
, &arg_expr
)
979 let arg_datum
= unpack_datum
!(bcx
, expr
::trans(bcx
, &arg_expr
));
980 bcx
= trans_arg_datum(bcx
, arg_ty
, arg_datum
,
986 ArgOverloadedCall(arg_exprs
) => {
987 return trans_overloaded_call_args(cx
,
994 ArgOverloadedOp(lhs
, rhs
, autoref
) => {
997 bcx
= trans_arg_datum(bcx
, arg_tys
[0], lhs
,
1002 if let Some((rhs
, rhs_id
)) = rhs
{
1003 assert_eq
!(arg_tys
.len(), 2);
1004 bcx
= trans_arg_datum(bcx
, arg_tys
[1], rhs
,
1006 if autoref { DoAutorefArg(rhs_id) }
else { DontAutorefArg }
,
1009 assert_eq
!(arg_tys
.len(), 1);
1013 llargs
.extend_from_slice(vs
);
1020 #[derive(Copy, Clone)]
1021 pub enum AutorefArg
{
1023 DoAutorefArg(ast
::NodeId
)
1026 pub fn trans_arg_datum
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
1027 formal_arg_ty
: Ty
<'tcx
>,
1028 arg_datum
: Datum
<'tcx
, Expr
>,
1029 arg_cleanup_scope
: cleanup
::ScopeId
,
1030 autoref_arg
: AutorefArg
,
1031 llargs
: &mut Vec
<ValueRef
>)
1032 -> Block
<'blk
, 'tcx
> {
1033 let _icx
= push_ctxt("trans_arg_datum");
1035 let ccx
= bcx
.ccx();
1037 debug
!("trans_arg_datum({:?})",
1040 let arg_datum_ty
= arg_datum
.ty
;
1042 debug
!(" arg datum: {}", arg_datum
.to_string(bcx
.ccx()));
1045 // FIXME(#3548) use the adjustments table
1047 DoAutorefArg(arg_id
) => {
1048 // We will pass argument by reference
1049 // We want an lvalue, so that we can pass by reference and
1050 let arg_datum
= unpack_datum
!(
1051 bcx
, arg_datum
.to_lvalue_datum(bcx
, "arg", arg_id
));
1052 val
= arg_datum
.val
;
1054 DontAutorefArg
if common
::type_is_fat_ptr(bcx
.tcx(), arg_datum_ty
) &&
1055 !bcx
.fcx
.type_needs_drop(arg_datum_ty
) => {
1059 // Make this an rvalue, since we are going to be
1060 // passing ownership.
1061 let arg_datum
= unpack_datum
!(
1062 bcx
, arg_datum
.to_rvalue_datum(bcx
, "arg"));
1064 // Now that arg_datum is owned, get it into the appropriate
1065 // mode (ref vs value).
1066 let arg_datum
= unpack_datum
!(
1067 bcx
, arg_datum
.to_appropriate_datum(bcx
));
1069 // Technically, ownership of val passes to the callee.
1070 // However, we must cleanup should we panic before the
1071 // callee is actually invoked.
1072 val
= arg_datum
.add_clean(bcx
.fcx
, arg_cleanup_scope
);
1076 if type_of
::arg_is_indirect(ccx
, formal_arg_ty
) && formal_arg_ty
!= arg_datum_ty
{
1077 // this could happen due to e.g. subtyping
1078 let llformal_arg_ty
= type_of
::type_of_explicit_arg(ccx
, formal_arg_ty
);
1079 debug
!("casting actual type ({}) to match formal ({})",
1080 bcx
.val_to_string(val
), bcx
.llty_str(llformal_arg_ty
));
1081 debug
!("Rust types: {:?}; {:?}", arg_datum_ty
,
1083 val
= PointerCast(bcx
, val
, llformal_arg_ty
);
1086 debug
!("--- trans_arg_datum passing {}", bcx
.val_to_string(val
));
1088 if common
::type_is_fat_ptr(bcx
.tcx(), formal_arg_ty
) {
1089 llargs
.push(Load(bcx
, expr
::get_dataptr(bcx
, val
)));
1090 llargs
.push(Load(bcx
, expr
::get_meta(bcx
, val
)));