2012-12-04 00:48:01 +00:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-26 02:17:11 +00:00
|
|
|
//! Handles translation of callees as well as other call-related
|
|
|
|
//! things. Callees are a superset of normal rust values and sometimes
|
|
|
|
//! have different representations. In particular, top-level fn items
|
|
|
|
//! and methods are represented as just a fn ptr and not a full
|
|
|
|
//! closure.
|
2012-08-28 22:54:45 +00:00
|
|
|
|
2014-11-06 08:05:53 +00:00
|
|
|
pub use self::CalleeData::*;
|
|
|
|
|
2014-06-28 19:55:17 +00:00
|
|
|
use arena::TypedArena;
|
2016-08-17 19:50:55 +00:00
|
|
|
use llvm::{self, ValueRef, get_params};
|
2016-03-29 09:54:26 +00:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-08-08 20:39:49 +00:00
|
|
|
use rustc::ty::subst::Substs;
|
2016-03-22 15:30:57 +00:00
|
|
|
use rustc::traits;
|
2016-03-22 17:23:36 +00:00
|
|
|
use abi::{Abi, FnType};
|
|
|
|
use attributes;
|
|
|
|
use base;
|
|
|
|
use base::*;
|
|
|
|
use build::*;
|
2016-08-09 00:50:19 +00:00
|
|
|
use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
|
2016-03-22 17:23:36 +00:00
|
|
|
use consts;
|
|
|
|
use debuginfo::DebugLoc;
|
|
|
|
use declare;
|
2016-11-09 21:09:28 +00:00
|
|
|
use value::Value;
|
2016-03-22 17:23:36 +00:00
|
|
|
use meth;
|
|
|
|
use monomorphize::{self, Instance};
|
2016-05-26 12:59:58 +00:00
|
|
|
use trans_item::TransItem;
|
2016-03-22 17:23:36 +00:00
|
|
|
use type_of;
|
|
|
|
use Disr;
|
2016-08-09 00:50:19 +00:00
|
|
|
use rustc::ty::{self, Ty, TypeFoldable};
|
2016-03-29 05:50:44 +00:00
|
|
|
use rustc::hir;
|
2012-12-13 21:05:22 +00:00
|
|
|
|
2016-06-21 22:08:13 +00:00
|
|
|
use syntax_pos::DUMMY_SP;
|
2012-08-28 22:54:45 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
#[derive(Debug)]
|
2016-02-23 20:00:59 +00:00
|
|
|
pub enum CalleeData {
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Constructor for enum variant/tuple-like-struct.
|
2016-01-16 15:03:09 +00:00
|
|
|
NamedTupleConstructor(Disr),
|
2014-07-10 06:42:08 +00:00
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Function pointer.
|
|
|
|
Fn(ValueRef),
|
2014-01-27 12:18:36 +00:00
|
|
|
|
2016-02-23 20:00:59 +00:00
|
|
|
Intrinsic,
|
2014-07-09 22:31:45 +00:00
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Trait object found in the vtable at that index.
|
|
|
|
Virtual(usize)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
#[derive(Debug)]
|
2016-03-06 15:32:47 +00:00
|
|
|
pub struct Callee<'tcx> {
|
2016-02-23 20:00:59 +00:00
|
|
|
pub data: CalleeData,
|
2015-07-03 02:22:54 +00:00
|
|
|
pub ty: Ty<'tcx>
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
impl<'tcx> Callee<'tcx> {
|
|
|
|
/// Function pointer.
|
2016-08-16 14:41:38 +00:00
|
|
|
pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
|
2016-03-06 15:32:47 +00:00
|
|
|
Callee {
|
2016-08-16 14:41:38 +00:00
|
|
|
data: Fn(llfn),
|
|
|
|
ty: ty
|
2015-01-13 04:02:56 +00:00
|
|
|
}
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Trait or impl method call.
|
|
|
|
pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
|
|
|
|
method_call: ty::MethodCall)
|
|
|
|
-> Callee<'tcx> {
|
2016-10-27 01:52:10 +00:00
|
|
|
let method = bcx.tcx().tables().method_map[&method_call];
|
2016-03-06 15:32:47 +00:00
|
|
|
Callee::method(bcx, method)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Trait or impl method.
|
|
|
|
pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
|
|
|
|
method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
|
2016-04-29 05:30:54 +00:00
|
|
|
let substs = bcx.fcx.monomorphize(&method.substs);
|
2016-02-23 19:21:50 +00:00
|
|
|
Callee::def(bcx.ccx(), method.def_id, substs)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
/// Function or method definition.
|
|
|
|
pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
def_id: DefId,
|
2016-08-08 20:39:49 +00:00
|
|
|
substs: &'tcx Substs<'tcx>)
|
2016-03-06 15:32:47 +00:00
|
|
|
-> Callee<'tcx> {
|
|
|
|
let tcx = ccx.tcx();
|
|
|
|
|
2016-08-08 20:39:49 +00:00
|
|
|
if let Some(trait_id) = tcx.trait_of_item(def_id) {
|
|
|
|
return Callee::trait_method(ccx, trait_id, def_id, substs);
|
2016-03-06 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
2016-08-09 00:50:19 +00:00
|
|
|
let fn_ty = def_ty(ccx.shared(), def_id, substs);
|
2016-08-26 16:23:42 +00:00
|
|
|
if let ty::TyFnDef(.., f) = fn_ty.sty {
|
2016-08-17 19:50:55 +00:00
|
|
|
if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
|
|
|
|
return Callee {
|
|
|
|
data: Intrinsic,
|
|
|
|
ty: fn_ty
|
|
|
|
};
|
2016-08-16 14:41:38 +00:00
|
|
|
}
|
2016-08-17 19:50:55 +00:00
|
|
|
}
|
2016-02-23 19:21:50 +00:00
|
|
|
|
2016-08-17 19:50:55 +00:00
|
|
|
// FIXME(eddyb) Detect ADT constructors more efficiently.
|
|
|
|
if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
|
|
|
|
if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
|
|
|
|
return Callee {
|
|
|
|
data: NamedTupleConstructor(Disr::from(v.disr_val)),
|
|
|
|
ty: fn_ty
|
|
|
|
};
|
|
|
|
}
|
2016-02-23 19:21:50 +00:00
|
|
|
}
|
2016-08-17 19:50:55 +00:00
|
|
|
|
|
|
|
let (llfn, ty) = get_fn(ccx, def_id, substs);
|
|
|
|
Callee::ptr(llfn, ty)
|
2016-02-23 19:21:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait method, which has to be resolved to an impl method.
|
|
|
|
pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
|
2016-08-08 20:39:49 +00:00
|
|
|
trait_id: DefId,
|
2016-02-23 19:21:50 +00:00
|
|
|
def_id: DefId,
|
2016-08-08 20:39:49 +00:00
|
|
|
substs: &'tcx Substs<'tcx>)
|
2016-02-23 19:21:50 +00:00
|
|
|
-> Callee<'tcx> {
|
|
|
|
let tcx = ccx.tcx();
|
2014-07-10 06:42:08 +00:00
|
|
|
|
2016-08-08 20:39:49 +00:00
|
|
|
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs);
|
|
|
|
let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
2016-05-06 04:47:28 +00:00
|
|
|
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
|
2016-02-23 19:21:50 +00:00
|
|
|
traits::VtableImpl(vtable_impl) => {
|
2016-09-19 09:47:47 +00:00
|
|
|
let name = tcx.item_name(def_id);
|
|
|
|
let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
|
2016-02-23 19:21:50 +00:00
|
|
|
|
|
|
|
// Translate the function, bypassing Callee::def.
|
|
|
|
// That is because default methods have the same ID as the
|
|
|
|
// trait method used to look up the impl method that ended
|
|
|
|
// up here, so calling Callee::def would infinitely recurse.
|
2016-09-19 09:47:47 +00:00
|
|
|
let (llfn, ty) = get_fn(ccx, def_id, substs);
|
2016-08-16 14:41:38 +00:00
|
|
|
Callee::ptr(llfn, ty)
|
2016-02-23 19:21:50 +00:00
|
|
|
}
|
|
|
|
traits::VtableClosure(vtable_closure) => {
|
|
|
|
// The substitutions should have no type parameters remaining
|
|
|
|
// after passing through fulfill_obligation
|
|
|
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
2016-09-19 09:47:47 +00:00
|
|
|
let instance = Instance::new(def_id, substs);
|
2016-11-09 21:09:28 +00:00
|
|
|
let llfn = trans_closure_method(
|
|
|
|
ccx,
|
|
|
|
vtable_closure.closure_def_id,
|
|
|
|
vtable_closure.substs,
|
|
|
|
instance,
|
|
|
|
trait_closure_kind);
|
2016-02-23 19:21:50 +00:00
|
|
|
|
2016-08-09 00:50:19 +00:00
|
|
|
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
2016-08-17 19:50:55 +00:00
|
|
|
Callee::ptr(llfn, method_ty)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
2016-05-11 21:40:24 +00:00
|
|
|
traits::VtableFnPointer(vtable_fn_pointer) => {
|
2016-02-23 19:21:50 +00:00
|
|
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
2016-09-19 09:47:47 +00:00
|
|
|
let instance = Instance::new(def_id, substs);
|
|
|
|
let llfn = trans_fn_pointer_shim(ccx, instance,
|
|
|
|
trait_closure_kind,
|
|
|
|
vtable_fn_pointer.fn_ty);
|
2016-02-23 19:21:50 +00:00
|
|
|
|
2016-08-09 00:50:19 +00:00
|
|
|
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
2016-08-17 19:50:55 +00:00
|
|
|
Callee::ptr(llfn, method_ty)
|
2016-02-23 19:21:50 +00:00
|
|
|
}
|
|
|
|
traits::VtableObject(ref data) => {
|
|
|
|
Callee {
|
2016-03-16 22:15:31 +00:00
|
|
|
data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
|
2016-08-09 00:50:19 +00:00
|
|
|
ty: def_ty(ccx.shared(), def_id, substs)
|
2014-07-10 07:20:28 +00:00
|
|
|
}
|
2012-10-24 21:36:00 +00:00
|
|
|
}
|
2016-02-23 19:21:50 +00:00
|
|
|
vtable => {
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!("resolved vtable bad vtable {:?} in trans", vtable);
|
2016-02-23 19:21:50 +00:00
|
|
|
}
|
2016-03-06 15:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-06 10:38:46 +00:00
|
|
|
|
|
|
|
/// Get the abi::FnType for a direct call. Mainly deals with the fact
|
|
|
|
/// that a Virtual call doesn't take the vtable, like its shim does.
|
|
|
|
/// The extra argument types are for variadic (extern "C") functions.
|
|
|
|
pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
extra_args: &[Ty<'tcx>]) -> FnType {
|
|
|
|
let abi = self.ty.fn_abi();
|
2016-10-12 21:08:11 +00:00
|
|
|
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
|
2016-03-06 10:38:46 +00:00
|
|
|
let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
|
|
|
|
if let Virtual(_) = self.data {
|
|
|
|
// Don't pass the vtable, it's not an argument of the virtual fn.
|
|
|
|
fn_ty.args[1].ignore();
|
|
|
|
}
|
|
|
|
fn_ty.adjust_for_abi(ccx, abi, &sig);
|
|
|
|
fn_ty
|
|
|
|
}
|
2016-03-06 15:32:47 +00:00
|
|
|
|
|
|
|
/// This behemoth of a function translates function calls. Unfortunately, in
|
|
|
|
/// order to generate more efficient LLVM output at -O0, it has quite a complex
|
|
|
|
/// signature (refactoring this into two functions seems like a good idea).
|
|
|
|
///
|
|
|
|
/// In particular, for lang items, it is invoked with a dest of None, and in
|
|
|
|
/// that case the return value contains the result of the fn. The lang item must
|
|
|
|
/// not return a structural type or else all heck breaks loose.
|
|
|
|
///
|
|
|
|
/// For non-lang items, `dest` is always Some, and hence the result is written
|
|
|
|
/// into memory somewhere. Nonetheless we return the actual return value of the
|
|
|
|
/// function.
|
|
|
|
pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
|
|
|
|
debug_loc: DebugLoc,
|
2016-08-16 14:41:38 +00:00
|
|
|
args: &[ValueRef],
|
|
|
|
dest: Option<ValueRef>)
|
2016-03-06 15:32:47 +00:00
|
|
|
-> Result<'blk, 'tcx> {
|
|
|
|
trans_call_inner(bcx, debug_loc, self, args, dest)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turn the callee into a function pointer.
|
2016-08-16 14:41:38 +00:00
|
|
|
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
2016-03-06 15:32:47 +00:00
|
|
|
match self.data {
|
2016-08-16 14:41:38 +00:00
|
|
|
Fn(llfn) => llfn,
|
2016-09-19 09:47:47 +00:00
|
|
|
Virtual(_) => meth::trans_object_shim(ccx, self),
|
2016-08-17 19:50:55 +00:00
|
|
|
NamedTupleConstructor(disr) => match self.ty.sty {
|
2016-03-06 15:32:47 +00:00
|
|
|
ty::TyFnDef(def_id, substs, _) => {
|
2016-08-17 19:50:55 +00:00
|
|
|
let instance = Instance::new(def_id, substs);
|
|
|
|
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
|
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
|
|
|
|
TransItem::Fn(instance));
|
|
|
|
assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
|
|
|
|
let lldecl = declare::define_internal_fn(ccx, &sym, self.ty);
|
|
|
|
base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl);
|
|
|
|
ccx.instances().borrow_mut().insert(instance, lldecl);
|
|
|
|
|
|
|
|
lldecl
|
2016-03-06 15:32:47 +00:00
|
|
|
}
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("expected fn item type, found {}", self.ty)
|
2016-03-06 15:32:47 +00:00
|
|
|
},
|
2016-03-28 23:46:02 +00:00
|
|
|
Intrinsic => bug!("intrinsic {} getting reified", self.ty)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-23 19:21:50 +00:00
|
|
|
/// Given a DefId and some Substs, produces the monomorphic item type.
|
2016-08-09 00:50:19 +00:00
|
|
|
fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
|
2016-05-03 01:56:42 +00:00
|
|
|
def_id: DefId,
|
2016-08-08 20:39:49 +00:00
|
|
|
substs: &'tcx Substs<'tcx>)
|
2016-05-03 01:56:42 +00:00
|
|
|
-> Ty<'tcx> {
|
2016-11-10 14:49:53 +00:00
|
|
|
let ty = shared.tcx().item_type(def_id);
|
2016-08-09 00:50:19 +00:00
|
|
|
monomorphize::apply_param_substs(shared, substs, &ty)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 21:09:28 +00:00
|
|
|
|
|
|
|
fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|
|
|
def_id: DefId,
|
|
|
|
substs: ty::ClosureSubsts<'tcx>,
|
|
|
|
method_instance: Instance<'tcx>,
|
|
|
|
trait_closure_kind: ty::ClosureKind)
|
|
|
|
-> ValueRef
|
|
|
|
{
|
|
|
|
// If this is a closure, redirect to it.
|
|
|
|
let (llfn, _) = get_fn(ccx, def_id, substs.substs);
|
|
|
|
|
|
|
|
// If the closure is a Fn closure, but a FnOnce is needed (etc),
|
|
|
|
// then adapt the self type
|
|
|
|
let llfn_closure_kind = ccx.tcx().closure_kind(def_id);
|
|
|
|
|
|
|
|
let _icx = push_ctxt("trans_closure_adapter_shim");
|
|
|
|
|
|
|
|
debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
|
|
|
|
trait_closure_kind={:?}, llfn={:?})",
|
|
|
|
llfn_closure_kind, trait_closure_kind, Value(llfn));
|
|
|
|
|
|
|
|
match (llfn_closure_kind, trait_closure_kind) {
|
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
|
|
|
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
|
|
|
|
(ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
|
|
|
|
// No adapter needed.
|
|
|
|
llfn
|
|
|
|
}
|
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
|
|
|
|
// The closure fn `llfn` is a `fn(&self, ...)`. We want a
|
|
|
|
// `fn(&mut self, ...)`. In fact, at trans time, these are
|
|
|
|
// basically the same thing, so we can just return llfn.
|
|
|
|
llfn
|
|
|
|
}
|
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
|
|
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
|
|
|
// The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
|
|
|
|
// self, ...)`. We want a `fn(self, ...)`. We can produce
|
|
|
|
// this by doing something like:
|
|
|
|
//
|
|
|
|
// fn call_once(self, ...) { call_mut(&self, ...) }
|
|
|
|
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
|
|
|
|
//
|
|
|
|
// These are both the same at trans time.
|
|
|
|
trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
|
|
|
|
llfn_closure_kind,
|
|
|
|
trait_closure_kind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|
|
|
ccx: &'a CrateContext<'a, 'tcx>,
|
|
|
|
def_id: DefId,
|
|
|
|
substs: ty::ClosureSubsts<'tcx>,
|
|
|
|
method_instance: Instance<'tcx>,
|
|
|
|
llreffn: ValueRef)
|
|
|
|
-> ValueRef
|
|
|
|
{
|
|
|
|
if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
|
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
|
|
|
|
def_id, substs, Value(llreffn));
|
|
|
|
|
|
|
|
let tcx = ccx.tcx();
|
|
|
|
|
|
|
|
// Find a version of the closure type. Substitute static for the
|
|
|
|
// region since it doesn't really matter.
|
|
|
|
let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs);
|
|
|
|
let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
|
|
|
|
|
|
|
|
// Make a version with the type of by-ref closure.
|
|
|
|
let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
|
|
|
|
sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
|
|
|
|
let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
|
|
|
unsafety: unsafety,
|
|
|
|
abi: abi,
|
|
|
|
sig: sig.clone()
|
|
|
|
}));
|
|
|
|
debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
|
|
|
|
llref_fn_ty);
|
|
|
|
|
|
|
|
|
|
|
|
// Make a version of the closure type with the same arguments, but
|
|
|
|
// with argument #0 being by value.
|
|
|
|
assert_eq!(abi, Abi::RustCall);
|
|
|
|
sig.0.inputs[0] = closure_ty;
|
|
|
|
|
|
|
|
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
|
|
|
|
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
|
|
|
|
|
|
|
|
let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
|
|
|
unsafety: unsafety,
|
|
|
|
abi: abi,
|
|
|
|
sig: ty::Binder(sig)
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Create the by-value helper.
|
|
|
|
let function_name = method_instance.symbol_name(ccx.shared());
|
|
|
|
let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
|
|
|
|
attributes::set_frame_pointer_elimination(ccx, lloncefn);
|
|
|
|
|
|
|
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
|
|
|
block_arena = TypedArena::new();
|
|
|
|
fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
|
|
|
|
let mut bcx = fcx.init(false);
|
|
|
|
|
|
|
|
|
|
|
|
// the first argument (`self`) will be the (by value) closure env.
|
|
|
|
|
|
|
|
let mut llargs = get_params(fcx.llfn);
|
|
|
|
let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
|
|
|
|
let env_arg = &fcx.fn_ty.args[0];
|
|
|
|
let llenv = if env_arg.is_indirect() {
|
|
|
|
llargs[self_idx]
|
|
|
|
} else {
|
|
|
|
let scratch = alloc_ty(bcx, closure_ty, "self");
|
|
|
|
let mut llarg_idx = self_idx;
|
|
|
|
env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
|
|
|
|
scratch
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
|
|
|
|
// Adjust llargs such that llargs[self_idx..] has the call arguments.
|
|
|
|
// For zero-sized closures that means sneaking in a new argument.
|
|
|
|
if env_arg.is_ignore() {
|
|
|
|
if self_idx > 0 {
|
|
|
|
self_idx -= 1;
|
|
|
|
llargs[self_idx] = llenv;
|
|
|
|
} else {
|
|
|
|
llargs.insert(0, llenv);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
llargs[self_idx] = llenv;
|
|
|
|
}
|
|
|
|
|
|
|
|
let dest = fcx.llretslotptr.get();
|
|
|
|
|
|
|
|
let callee = Callee {
|
|
|
|
data: Fn(llreffn),
|
|
|
|
ty: llref_fn_ty
|
|
|
|
};
|
|
|
|
|
|
|
|
// Call the by-ref closure body with `self` in a cleanup scope,
|
|
|
|
// to drop `self` when the body returns, or in case it unwinds.
|
|
|
|
let self_scope = fcx.push_custom_cleanup_scope();
|
|
|
|
fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
|
|
|
|
|
|
|
|
bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
|
|
|
|
|
|
|
|
fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
|
|
|
|
|
|
|
|
fcx.finish(bcx, DebugLoc::None);
|
|
|
|
|
|
|
|
ccx.instances().borrow_mut().insert(method_instance, lloncefn);
|
|
|
|
|
|
|
|
lloncefn
|
|
|
|
}
|
|
|
|
|
2014-12-01 14:23:40 +00:00
|
|
|
/// Translates an adapter that implements the `Fn` trait for a fn
|
|
|
|
/// pointer. This is basically the equivalent of something like:
|
|
|
|
///
|
2015-03-13 02:42:38 +00:00
|
|
|
/// ```
|
2014-12-01 14:23:40 +00:00
|
|
|
/// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
|
|
|
|
/// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
|
|
|
|
/// (*self)(args.0)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// but for the bare function type given.
|
2016-09-19 09:47:47 +00:00
|
|
|
fn trans_fn_pointer_shim<'a, 'tcx>(
|
2014-12-01 14:23:40 +00:00
|
|
|
ccx: &'a CrateContext<'a, 'tcx>,
|
2016-09-19 09:47:47 +00:00
|
|
|
method_instance: Instance<'tcx>,
|
2015-02-15 20:09:26 +00:00
|
|
|
closure_kind: ty::ClosureKind,
|
2014-12-01 14:23:40 +00:00
|
|
|
bare_fn_ty: Ty<'tcx>)
|
|
|
|
-> ValueRef
|
|
|
|
{
|
|
|
|
let _icx = push_ctxt("trans_fn_pointer_shim");
|
|
|
|
let tcx = ccx.tcx();
|
|
|
|
|
2015-02-15 20:09:26 +00:00
|
|
|
// Normalize the type for better caching.
|
2016-06-08 01:12:40 +00:00
|
|
|
let bare_fn_ty = tcx.normalize_associated_type(&bare_fn_ty);
|
2015-02-15 20:09:26 +00:00
|
|
|
|
|
|
|
// If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
|
|
|
|
let is_by_ref = match closure_kind {
|
2016-02-12 15:44:27 +00:00
|
|
|
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true,
|
|
|
|
ty::ClosureKind::FnOnce => false,
|
2015-02-15 20:09:26 +00:00
|
|
|
};
|
2016-03-06 14:30:21 +00:00
|
|
|
|
|
|
|
let llfnpointer = match bare_fn_ty.sty {
|
|
|
|
ty::TyFnDef(def_id, substs, _) => {
|
|
|
|
// Function definitions have to be turned into a pointer.
|
2016-08-16 14:41:38 +00:00
|
|
|
let llfn = Callee::def(ccx, def_id, substs).reify(ccx);
|
2016-03-06 14:30:21 +00:00
|
|
|
if !is_by_ref {
|
|
|
|
// A by-value fn item is ignored, so the shim has
|
|
|
|
// the same signature as the original function.
|
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
Some(llfn)
|
|
|
|
}
|
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
2015-02-15 20:09:26 +00:00
|
|
|
let bare_fn_ty_maybe_ref = if is_by_ref {
|
2016-06-01 12:10:44 +00:00
|
|
|
tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty)
|
2015-02-15 20:09:26 +00:00
|
|
|
} else {
|
|
|
|
bare_fn_ty
|
|
|
|
};
|
|
|
|
|
|
|
|
// Check if we already trans'd this shim.
|
2016-10-18 02:00:20 +00:00
|
|
|
if let Some(&llval) = ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
|
|
|
|
return llval;
|
2014-12-04 01:23:15 +00:00
|
|
|
}
|
|
|
|
|
2015-06-18 17:25:05 +00:00
|
|
|
debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
|
|
|
|
bare_fn_ty);
|
2014-12-01 14:23:40 +00:00
|
|
|
|
|
|
|
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
|
|
|
|
// which is the fn pointer, and `args`, which is the arguments tuple.
|
2016-03-06 15:32:47 +00:00
|
|
|
let sig = match bare_fn_ty.sty {
|
2016-08-26 16:23:42 +00:00
|
|
|
ty::TyFnDef(..,
|
2016-03-06 15:32:47 +00:00
|
|
|
&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
|
|
|
|
abi: Abi::Rust,
|
|
|
|
ref sig }) |
|
|
|
|
ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
|
|
|
|
abi: Abi::Rust,
|
|
|
|
ref sig }) => sig,
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
_ => {
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!("trans_fn_pointer_shim invoked on invalid type: {}",
|
|
|
|
bare_fn_ty);
|
2016-03-06 15:32:47 +00:00
|
|
|
}
|
|
|
|
};
|
2016-10-12 21:08:11 +00:00
|
|
|
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
|
2016-10-25 00:23:29 +00:00
|
|
|
let tuple_input_ty = tcx.intern_tup(&sig.inputs[..]);
|
2016-03-06 14:30:21 +00:00
|
|
|
let sig = ty::FnSig {
|
|
|
|
inputs: vec![bare_fn_ty_maybe_ref,
|
|
|
|
tuple_input_ty],
|
|
|
|
output: sig.output,
|
|
|
|
variadic: false
|
|
|
|
};
|
|
|
|
let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
|
2016-04-29 05:30:54 +00:00
|
|
|
let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
2015-06-13 20:15:03 +00:00
|
|
|
unsafety: hir::Unsafety::Normal,
|
|
|
|
abi: Abi::RustCall,
|
2016-03-06 14:30:21 +00:00
|
|
|
sig: ty::Binder(sig)
|
2016-04-29 05:30:54 +00:00
|
|
|
}));
|
2015-06-18 17:25:05 +00:00
|
|
|
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
|
2014-12-01 14:23:40 +00:00
|
|
|
|
|
|
|
//
|
2016-09-19 09:47:47 +00:00
|
|
|
let function_name = method_instance.symbol_name(ccx.shared());
|
2016-02-23 19:57:22 +00:00
|
|
|
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
|
2016-05-27 17:27:56 +00:00
|
|
|
attributes::set_frame_pointer_elimination(ccx, llfn);
|
2014-12-01 14:23:40 +00:00
|
|
|
//
|
2015-01-26 12:38:33 +00:00
|
|
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
|
|
|
block_arena = TypedArena::new();
|
2016-04-06 05:34:03 +00:00
|
|
|
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
|
2016-08-16 14:41:38 +00:00
|
|
|
let mut bcx = fcx.init(false);
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2015-06-18 18:07:36 +00:00
|
|
|
let llargs = get_params(fcx.llfn);
|
|
|
|
|
2016-03-06 14:30:21 +00:00
|
|
|
let self_idx = fcx.fn_ty.ret.is_indirect() as usize;
|
|
|
|
let llfnpointer = llfnpointer.unwrap_or_else(|| {
|
2016-03-06 15:32:47 +00:00
|
|
|
// the first argument (`self`) will be ptr to the fn pointer
|
2016-03-06 14:30:21 +00:00
|
|
|
if is_by_ref {
|
2016-03-06 15:32:47 +00:00
|
|
|
Load(bcx, llargs[self_idx])
|
|
|
|
} else {
|
|
|
|
llargs[self_idx]
|
|
|
|
}
|
2016-03-06 14:30:21 +00:00
|
|
|
});
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
let dest = fcx.llretslotptr.get();
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2016-03-06 15:32:47 +00:00
|
|
|
let callee = Callee {
|
|
|
|
data: Fn(llfnpointer),
|
|
|
|
ty: bare_fn_ty
|
|
|
|
};
|
2016-08-16 14:41:38 +00:00
|
|
|
bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2016-03-06 14:30:21 +00:00
|
|
|
fcx.finish(bcx, DebugLoc::None);
|
2014-12-01 14:23:40 +00:00
|
|
|
|
2015-02-15 20:09:26 +00:00
|
|
|
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
|
2014-12-04 01:23:15 +00:00
|
|
|
|
2014-12-01 14:23:40 +00:00
|
|
|
llfn
|
|
|
|
}
|
|
|
|
|
2014-11-26 02:17:11 +00:00
|
|
|
/// Translates a reference to a fn/method item, monomorphizing and
|
|
|
|
/// inlining as it goes.
|
|
|
|
///
|
|
|
|
/// # Parameters
|
|
|
|
///
|
2015-01-04 16:47:58 +00:00
|
|
|
/// - `ccx`: the crate context
|
2014-11-26 02:17:11 +00:00
|
|
|
/// - `def_id`: def id of the fn or method item being referenced
|
|
|
|
/// - `substs`: values for each of the fn/method's parameters
|
2016-02-23 19:21:50 +00:00
|
|
|
fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
def_id: DefId,
|
2016-08-08 20:39:49 +00:00
|
|
|
substs: &'tcx Substs<'tcx>)
|
2016-08-16 14:41:38 +00:00
|
|
|
-> (ValueRef, Ty<'tcx>) {
|
2015-01-04 16:47:58 +00:00
|
|
|
let tcx = ccx.tcx();
|
2012-08-28 22:54:45 +00:00
|
|
|
|
2016-02-23 19:21:50 +00:00
|
|
|
debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
|
2012-09-10 19:25:45 +00:00
|
|
|
|
2016-08-18 05:32:50 +00:00
|
|
|
assert!(!substs.needs_infer());
|
|
|
|
assert!(!substs.has_escaping_regions());
|
|
|
|
assert!(!substs.has_param_types());
|
2013-03-21 12:34:18 +00:00
|
|
|
|
2016-08-17 19:50:55 +00:00
|
|
|
let substs = tcx.normalize_associated_type(&substs);
|
|
|
|
let instance = Instance::new(def_id, substs);
|
2016-11-10 14:49:53 +00:00
|
|
|
let item_ty = ccx.tcx().item_type(def_id);
|
2016-08-09 00:50:19 +00:00
|
|
|
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
|
2016-02-23 20:04:51 +00:00
|
|
|
|
|
|
|
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
|
2016-08-17 19:50:55 +00:00
|
|
|
return (llfn, fn_ty);
|
2016-02-23 20:04:51 +00:00
|
|
|
}
|
|
|
|
|
2016-08-17 19:50:55 +00:00
|
|
|
let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
|
|
|
|
TransItem::Fn(instance));
|
|
|
|
debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
|
2012-08-28 22:54:45 +00:00
|
|
|
|
2013-05-21 19:25:44 +00:00
|
|
|
// This is subtle and surprising, but sometimes we have to bitcast
|
|
|
|
// the resulting fn pointer. The reason has to do with external
|
|
|
|
// functions. If you have two crates that both bind the same C
|
|
|
|
// library, they may not use precisely the same types: for
|
|
|
|
// example, they will probably each declare their own structs,
|
|
|
|
// which are distinct types from LLVM's point of view (nominal
|
|
|
|
// types).
|
|
|
|
//
|
|
|
|
// Now, if those two crates are linked into an application, and
|
|
|
|
// they contain inlined code, you can wind up with a situation
|
|
|
|
// where both of those functions wind up being loaded into this
|
|
|
|
// application simultaneously. In that case, the same function
|
|
|
|
// (from LLVM's point of view) requires two types. But of course
|
|
|
|
// LLVM won't allow one function to have two types.
|
|
|
|
//
|
|
|
|
// What we currently do, therefore, is declare the function with
|
|
|
|
// one of the two types (whichever happens to come first) and then
|
|
|
|
// bitcast as needed when the function is referenced to make sure
|
|
|
|
// it has the type we expect.
|
|
|
|
//
|
|
|
|
// This can occur on either a crate-local or crate-external
|
|
|
|
// reference. It also occurs when testing libcore and in some
|
|
|
|
// other weird situations. Annoying.
|
2016-04-05 10:01:00 +00:00
|
|
|
|
2016-11-14 23:23:07 +00:00
|
|
|
// Create a fn pointer with the substituted signature.
|
|
|
|
let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
|
2016-08-17 19:50:55 +00:00
|
|
|
let llptrty = type_of::type_of(ccx, fn_ptr_ty);
|
2016-05-12 16:52:38 +00:00
|
|
|
|
2016-08-17 19:50:55 +00:00
|
|
|
let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
|
2016-04-05 10:01:00 +00:00
|
|
|
if common::val_ty(llfn) != llptrty {
|
|
|
|
debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
|
|
|
|
consts::ptrcast(llfn, llptrty)
|
|
|
|
} else {
|
|
|
|
debug!("get_fn: not casting pointer!");
|
|
|
|
llfn
|
|
|
|
}
|
2014-05-29 05:26:56 +00:00
|
|
|
} else {
|
2016-08-17 19:50:55 +00:00
|
|
|
let llfn = declare::declare_fn(ccx, &sym, fn_ty);
|
2016-04-05 10:01:00 +00:00
|
|
|
assert_eq!(common::val_ty(llfn), llptrty);
|
2016-02-23 20:04:51 +00:00
|
|
|
debug!("get_fn: not casting pointer!");
|
2016-04-05 10:01:00 +00:00
|
|
|
|
2016-05-12 16:52:38 +00:00
|
|
|
let attrs = ccx.tcx().get_attrs(def_id);
|
|
|
|
attributes::from_fn_attrs(ccx, &attrs, llfn);
|
2016-08-17 19:50:55 +00:00
|
|
|
|
|
|
|
let is_local_def = ccx.shared().translation_items().borrow()
|
|
|
|
.contains(&TransItem::Fn(instance));
|
|
|
|
if is_local_def {
|
2016-04-05 10:01:00 +00:00
|
|
|
// FIXME(eddyb) Doubt all extern fn should allow unwinding.
|
|
|
|
attributes::unwind(llfn, true);
|
2016-08-17 19:50:55 +00:00
|
|
|
unsafe {
|
2016-09-01 18:52:33 +00:00
|
|
|
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
|
2016-08-17 19:50:55 +00:00
|
|
|
}
|
2016-04-05 10:01:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 20:04:51 +00:00
|
|
|
llfn
|
|
|
|
};
|
|
|
|
|
|
|
|
ccx.instances().borrow_mut().insert(instance, llfn);
|
2013-05-21 19:25:44 +00:00
|
|
|
|
2016-08-17 19:50:55 +00:00
|
|
|
(llfn, fn_ty)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ______________________________________________________________________
|
|
|
|
// Translating calls
|
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2016-03-06 15:32:47 +00:00
|
|
|
debug_loc: DebugLoc,
|
|
|
|
callee: Callee<'tcx>,
|
2016-08-16 14:41:38 +00:00
|
|
|
args: &[ValueRef],
|
|
|
|
opt_llretslot: Option<ValueRef>)
|
2016-03-06 15:32:47 +00:00
|
|
|
-> Result<'blk, 'tcx> {
|
2014-01-15 19:39:08 +00:00
|
|
|
// Introduce a temporary cleanup scope that will contain cleanups
|
|
|
|
// for the arguments while they are being evaluated. The purpose
|
2014-10-09 19:17:22 +00:00
|
|
|
// this cleanup is to ensure that, should a panic occur while
|
2014-01-15 19:39:08 +00:00
|
|
|
// evaluating argument N, the values for arguments 0...N-1 are all
|
2014-10-09 19:17:22 +00:00
|
|
|
// cleaned up. If no panic occurs, the values are handed off to
|
2014-01-15 19:39:08 +00:00
|
|
|
// the callee, and hence none of the cleanups in this temporary
|
|
|
|
// scope will ever execute.
|
|
|
|
let fcx = bcx.fcx;
|
|
|
|
let ccx = fcx.ccx;
|
2012-08-28 22:54:45 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
let fn_ret = callee.ty.fn_ret();
|
|
|
|
let fn_ty = callee.direct_fn_type(ccx, &[]);
|
2014-07-09 22:31:45 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
let mut callee = match callee.data {
|
2016-08-16 14:41:38 +00:00
|
|
|
NamedTupleConstructor(_) | Intrinsic => {
|
|
|
|
bug!("{:?} calls should not go through Callee::call", callee);
|
2014-07-10 06:42:08 +00:00
|
|
|
}
|
2016-03-06 11:23:20 +00:00
|
|
|
f => f
|
|
|
|
};
|
2014-07-28 06:23:16 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
// If there no destination, return must be direct, with no cast.
|
|
|
|
if opt_llretslot.is_none() {
|
|
|
|
assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
|
|
|
|
}
|
2013-04-18 22:53:29 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
let mut llargs = Vec::new();
|
2016-03-06 15:32:47 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
if fn_ty.ret.is_indirect() {
|
|
|
|
let mut llretslot = opt_llretslot.unwrap();
|
|
|
|
if let Some(ty) = fn_ty.ret.cast {
|
|
|
|
llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
|
2014-01-15 19:39:08 +00:00
|
|
|
}
|
2016-03-06 11:23:20 +00:00
|
|
|
llargs.push(llretslot);
|
|
|
|
}
|
2013-05-21 19:25:44 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
match callee {
|
|
|
|
Virtual(idx) => {
|
|
|
|
llargs.push(args[0]);
|
|
|
|
|
|
|
|
let fn_ptr = meth::get_virtual_method(bcx, args[1], idx);
|
|
|
|
let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
|
|
|
|
callee = Fn(PointerCast(bcx, fn_ptr, llty));
|
|
|
|
llargs.extend_from_slice(&args[2..]);
|
|
|
|
}
|
|
|
|
_ => llargs.extend_from_slice(args)
|
|
|
|
}
|
2016-02-25 23:10:40 +00:00
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
let llfn = match callee {
|
|
|
|
Fn(f) => f,
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("expected fn pointer callee, found {:?}", callee)
|
2016-03-06 11:23:20 +00:00
|
|
|
};
|
2016-02-25 23:10:40 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
|
2016-03-06 11:23:20 +00:00
|
|
|
if !bcx.unreachable.get() {
|
|
|
|
fn_ty.apply_attrs_callsite(llret);
|
2014-01-15 19:39:08 +00:00
|
|
|
|
2016-06-07 21:35:01 +00:00
|
|
|
// If the function we just called does not use an outpointer,
|
|
|
|
// store the result into the rust outpointer. Cast the outpointer
|
|
|
|
// type to match because some ABIs will use a different type than
|
|
|
|
// the Rust type. e.g., a {u32,u32} struct could be returned as
|
|
|
|
// u64.
|
|
|
|
if !fn_ty.ret.is_indirect() {
|
|
|
|
if let Some(llretslot) = opt_llretslot {
|
|
|
|
fn_ty.ret.store(&bcx.build(), llret, llretslot);
|
2016-03-08 12:29:46 +00:00
|
|
|
}
|
2012-10-27 01:23:45 +00:00
|
|
|
}
|
2014-01-15 19:39:08 +00:00
|
|
|
}
|
2013-04-18 22:53:29 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
if fn_ret.0.is_never() {
|
2014-10-28 17:32:05 +00:00
|
|
|
Unreachable(bcx);
|
2014-01-15 19:39:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 11:23:20 +00:00
|
|
|
Result::new(bcx, llret)
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|