2014-05-28 14:36:05 -05:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2015-02-15 14:09:26 -06:00
|
|
|
use arena::TypedArena;
|
2016-08-16 09:41:38 -05:00
|
|
|
use llvm::{self, ValueRef, get_params};
|
2016-03-29 04:54:26 -05:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-03-22 12:23:36 -05:00
|
|
|
use abi::{Abi, FnType};
|
|
|
|
use attributes;
|
|
|
|
use base::*;
|
2016-08-16 09:41:38 -05:00
|
|
|
use callee::{self, Callee};
|
2016-03-22 12:23:36 -05:00
|
|
|
use common::*;
|
2016-08-16 09:41:38 -05:00
|
|
|
use debuginfo::{DebugLoc};
|
2016-03-22 12:23:36 -05:00
|
|
|
use declare;
|
|
|
|
use monomorphize::{Instance};
|
|
|
|
use value::Value;
|
2016-03-22 10:30:57 -05:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt};
|
2011-12-14 15:57:10 -06:00
|
|
|
|
2016-03-29 00:50:44 -05:00
|
|
|
use rustc::hir;
|
2015-07-31 02:04:06 -05:00
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2016-05-02 20:56:42 -05:00
|
|
|
closure_id: DefId,
|
|
|
|
fn_ty: Ty<'tcx>)
|
|
|
|
-> Ty<'tcx> {
|
2016-02-23 17:16:27 -06:00
|
|
|
match tcx.closure_kind(closure_id) {
|
|
|
|
ty::ClosureKind::Fn => {
|
2016-06-01 07:10:44 -05:00
|
|
|
tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty)
|
2016-02-23 17:16:27 -06:00
|
|
|
}
|
|
|
|
ty::ClosureKind::FnMut => {
|
2016-06-01 07:10:44 -05:00
|
|
|
tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty)
|
2016-02-23 17:16:27 -06:00
|
|
|
}
|
|
|
|
ty::ClosureKind::FnOnce => fn_ty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 14:15:08 -06:00
|
|
|
/// Returns the LLVM function declaration for a closure, creating it if
|
|
|
|
/// necessary. If the ID does not correspond to a closure ID, returns None.
|
2016-03-06 08:30:21 -06:00
|
|
|
fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
closure_id: DefId,
|
2016-04-29 00:30:54 -05:00
|
|
|
substs: ty::ClosureSubsts<'tcx>)
|
2016-03-06 08:30:21 -06:00
|
|
|
-> ValueRef {
|
2014-11-06 01:50:10 -06:00
|
|
|
// Normalize type so differences in regions and typedefs don't cause
|
|
|
|
// duplicate declarations
|
2016-02-23 17:16:27 -06:00
|
|
|
let tcx = ccx.tcx();
|
2016-04-29 00:30:54 -05:00
|
|
|
let substs = tcx.erase_regions(&substs);
|
|
|
|
let instance = Instance::new(closure_id, substs.func_substs);
|
2014-10-18 12:46:57 -05:00
|
|
|
|
2016-02-23 17:16:27 -06:00
|
|
|
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
|
2015-07-23 20:08:29 -05:00
|
|
|
debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
|
2016-02-23 17:16:27 -06:00
|
|
|
instance, Value(llfn));
|
2015-07-16 08:46:35 -05:00
|
|
|
return llfn;
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
|
|
|
|
2016-05-12 11:52:38 -05:00
|
|
|
let symbol = instance.symbol_name(ccx.shared());
|
2014-05-29 00:26:56 -05:00
|
|
|
|
2016-02-23 17:16:27 -06:00
|
|
|
// Compute the rust-call form of the closure call method.
|
2016-05-10 20:14:41 -05:00
|
|
|
let sig = &tcx.closure_type(closure_id, substs).sig;
|
2016-02-23 17:16:27 -06:00
|
|
|
let sig = tcx.erase_late_bound_regions(sig);
|
2016-03-10 18:33:20 -06:00
|
|
|
let sig = tcx.normalize_associated_type(&sig);
|
2016-04-29 00:30:54 -05:00
|
|
|
let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
|
|
|
|
let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
2016-02-23 17:16:27 -06:00
|
|
|
unsafety: hir::Unsafety::Normal,
|
|
|
|
abi: Abi::RustCall,
|
|
|
|
sig: ty::Binder(ty::FnSig {
|
|
|
|
inputs: Some(get_self_type(tcx, closure_id, closure_type))
|
|
|
|
.into_iter().chain(sig.inputs).collect(),
|
|
|
|
output: sig.output,
|
|
|
|
variadic: false
|
|
|
|
})
|
2016-04-29 00:30:54 -05:00
|
|
|
}));
|
2016-05-13 12:41:42 -05:00
|
|
|
let llfn = declare::declare_fn(ccx, &symbol, function_type);
|
2014-05-29 00:26:56 -05:00
|
|
|
|
2016-05-27 12:27:56 -05:00
|
|
|
attributes::set_frame_pointer_elimination(ccx, llfn);
|
2014-05-29 00:26:56 -05:00
|
|
|
|
2015-01-24 14:00:03 -06:00
|
|
|
debug!("get_or_create_declaration_if_closure(): inserting new \
|
2016-02-18 11:49:45 -06:00
|
|
|
closure {:?}: {:?}",
|
2016-02-23 17:16:27 -06:00
|
|
|
instance, Value(llfn));
|
2016-07-08 19:24:46 -05:00
|
|
|
|
|
|
|
// NOTE: We do *not* store llfn in the ccx.instances() map here,
|
|
|
|
// that is only done, when the closures body is translated.
|
2014-05-29 00:26:56 -05:00
|
|
|
|
2015-07-16 08:46:35 -05:00
|
|
|
llfn
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
|
|
|
|
2016-07-13 16:03:02 -05:00
|
|
|
pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
closure_def_id: DefId,
|
|
|
|
closure_substs: ty::ClosureSubsts<'tcx>) {
|
2015-09-17 13:29:59 -05:00
|
|
|
// (*) Note that in the case of inlined functions, the `closure_def_id` will be the
|
|
|
|
// defid of the closure in its original crate, whereas `id` will be the id of the local
|
|
|
|
// inlined copy.
|
2016-08-16 09:41:38 -05:00
|
|
|
debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})",
|
|
|
|
closure_def_id, closure_substs);
|
2015-07-16 08:46:35 -05:00
|
|
|
|
2015-01-29 06:03:34 -06:00
|
|
|
let tcx = ccx.tcx();
|
2015-06-02 18:31:23 -05:00
|
|
|
let _icx = push_ctxt("closure::trans_closure_expr");
|
2014-05-29 00:26:56 -05:00
|
|
|
|
2016-07-08 19:24:46 -05:00
|
|
|
let param_substs = closure_substs.func_substs;
|
|
|
|
let instance = Instance::new(closure_def_id, param_substs);
|
|
|
|
|
|
|
|
// If we have not done so yet, translate this closure's body
|
|
|
|
if !ccx.instances().borrow().contains_key(&instance) {
|
|
|
|
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
|
2016-07-13 16:03:02 -05:00
|
|
|
|
2016-08-02 16:25:19 -05:00
|
|
|
unsafe {
|
|
|
|
if ccx.sess().target.target.options.allows_weak_linkage {
|
2016-09-01 13:52:33 -05:00
|
|
|
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage);
|
2016-08-02 16:25:19 -05:00
|
|
|
llvm::SetUniqueComdat(ccx.llmod(), llfn);
|
|
|
|
} else {
|
2016-09-01 13:52:33 -05:00
|
|
|
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage);
|
2016-08-02 16:25:19 -05:00
|
|
|
}
|
2016-07-13 16:03:02 -05:00
|
|
|
}
|
2016-07-08 19:24:46 -05:00
|
|
|
|
|
|
|
// set an inline hint for all closures
|
|
|
|
attributes::inline(llfn, attributes::InlineAttr::Hint);
|
|
|
|
|
|
|
|
// Get the type of this closure. Use the current `param_substs` as
|
|
|
|
// the closure substitutions. This makes sense because the closure
|
|
|
|
// takes the same set of type arguments as the enclosing fn, and
|
|
|
|
// this function (`trans_closure`) is invoked at the point
|
|
|
|
// of the closure expression.
|
|
|
|
|
|
|
|
let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
|
|
|
|
let sig = tcx.erase_late_bound_regions(sig);
|
|
|
|
let sig = tcx.normalize_associated_type(&sig);
|
|
|
|
|
|
|
|
let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
|
|
|
|
closure_substs);
|
|
|
|
let sig = ty::FnSig {
|
|
|
|
inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
|
|
|
|
.into_iter().chain(sig.inputs).collect(),
|
|
|
|
output: sig.output,
|
|
|
|
variadic: false
|
|
|
|
};
|
|
|
|
|
|
|
|
trans_closure(ccx,
|
|
|
|
llfn,
|
|
|
|
Instance::new(closure_def_id, param_substs),
|
|
|
|
&sig,
|
2016-08-16 09:41:38 -05:00
|
|
|
Abi::RustCall);
|
2016-07-08 19:24:46 -05:00
|
|
|
|
|
|
|
ccx.instances().borrow_mut().insert(instance, llfn);
|
|
|
|
}
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
2015-08-16 05:32:28 -05:00
|
|
|
closure_def_id: DefId,
|
2015-07-16 08:46:35 -05:00
|
|
|
substs: ty::ClosureSubsts<'tcx>,
|
2016-09-19 04:47:47 -05:00
|
|
|
method_instance: Instance<'tcx>,
|
2015-02-15 14:09:26 -06:00
|
|
|
trait_closure_kind: ty::ClosureKind)
|
|
|
|
-> ValueRef
|
|
|
|
{
|
2015-07-16 08:46:35 -05:00
|
|
|
// If this is a closure, redirect to it.
|
2016-04-29 00:30:54 -05:00
|
|
|
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2016-07-13 16:03:02 -05:00
|
|
|
// If weak linkage is not allowed, we have to make sure that a local,
|
|
|
|
// private copy of the closure is available in this codegen unit
|
|
|
|
if !ccx.sess().target.target.options.allows_weak_linkage &&
|
|
|
|
!ccx.sess().opts.single_codegen_unit() {
|
|
|
|
|
2016-08-16 09:41:38 -05:00
|
|
|
trans_closure_body_via_mir(ccx, closure_def_id, substs);
|
2016-07-13 16:03:02 -05:00
|
|
|
}
|
|
|
|
|
2015-02-15 14:09:26 -06:00
|
|
|
// If the closure is a Fn closure, but a FnOnce is needed (etc),
|
|
|
|
// then adapt the self type
|
2016-03-06 09:32:47 -06:00
|
|
|
let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
let _icx = push_ctxt("trans_closure_adapter_shim");
|
|
|
|
|
|
|
|
debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
|
2016-02-18 11:49:45 -06:00
|
|
|
trait_closure_kind={:?}, llfn={:?})",
|
|
|
|
llfn_closure_kind, trait_closure_kind, Value(llfn));
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
match (llfn_closure_kind, trait_closure_kind) {
|
2016-02-12 09:44:27 -06:00
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
|
|
|
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
|
|
|
|
(ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
// No adapter needed.
|
|
|
|
llfn
|
|
|
|
}
|
2016-02-12 09:44:27 -06:00
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
// 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
|
|
|
|
}
|
2016-02-12 09:44:27 -06:00
|
|
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
|
|
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
// 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.
|
2016-09-19 04:47:47 -05:00
|
|
|
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
|
2015-02-15 14:09:26 -06:00
|
|
|
}
|
|
|
|
_ => {
|
2016-03-28 18:46:02 -05:00
|
|
|
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
|
|
|
|
llfn_closure_kind,
|
|
|
|
trait_closure_kind);
|
2015-02-15 14:09:26 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|
|
|
ccx: &'a CrateContext<'a, 'tcx>,
|
2015-08-16 05:32:28 -05:00
|
|
|
closure_def_id: DefId,
|
2015-07-16 08:46:35 -05:00
|
|
|
substs: ty::ClosureSubsts<'tcx>,
|
2016-09-19 04:47:47 -05:00
|
|
|
method_instance: Instance<'tcx>,
|
2015-02-15 14:09:26 -06:00
|
|
|
llreffn: ValueRef)
|
|
|
|
-> ValueRef
|
|
|
|
{
|
2016-02-18 11:49:45 -06:00
|
|
|
debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
|
|
|
|
closure_def_id, substs, Value(llreffn));
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
let tcx = ccx.tcx();
|
|
|
|
|
|
|
|
// Find a version of the closure type. Substitute static for the
|
|
|
|
// region since it doesn't really matter.
|
2016-04-29 00:30:54 -05:00
|
|
|
let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs);
|
2016-06-01 07:10:44 -05:00
|
|
|
let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
// Make a version with the type of by-ref closure.
|
2016-03-24 22:22:44 -05:00
|
|
|
let ty::ClosureTy { unsafety, abi, mut sig } =
|
2016-05-10 20:14:41 -05:00
|
|
|
tcx.closure_type(closure_def_id, substs);
|
2015-02-15 14:09:26 -06:00
|
|
|
sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
|
2016-04-29 00:30:54 -05:00
|
|
|
let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
2015-06-13 15:15:03 -05:00
|
|
|
unsafety: unsafety,
|
|
|
|
abi: abi,
|
|
|
|
sig: sig.clone()
|
2016-04-29 00:30:54 -05:00
|
|
|
}));
|
2015-06-18 12:25:05 -05:00
|
|
|
debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
|
|
|
|
llref_fn_ty);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2015-06-13 15:15:03 -05:00
|
|
|
|
2015-02-15 14:09:26 -06:00
|
|
|
// Make a version of the closure type with the same arguments, but
|
|
|
|
// with argument #0 being by value.
|
2016-02-23 17:16:27 -06:00
|
|
|
assert_eq!(abi, Abi::RustCall);
|
2015-02-15 14:09:26 -06:00
|
|
|
sig.0.inputs[0] = closure_ty;
|
2016-03-06 08:30:21 -06:00
|
|
|
|
|
|
|
let sig = tcx.erase_late_bound_regions(&sig);
|
2016-03-24 22:22:44 -05:00
|
|
|
let sig = tcx.normalize_associated_type(&sig);
|
2016-03-06 08:30:21 -06:00
|
|
|
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
|
|
|
|
|
2016-04-29 00:30:54 -05:00
|
|
|
let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
2015-06-13 15:15:03 -05:00
|
|
|
unsafety: unsafety,
|
|
|
|
abi: abi,
|
2016-03-06 08:30:21 -06:00
|
|
|
sig: ty::Binder(sig)
|
2016-04-29 00:30:54 -05:00
|
|
|
}));
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
// Create the by-value helper.
|
2016-09-19 04:47:47 -05:00
|
|
|
let function_name = method_instance.symbol_name(ccx.shared());
|
2016-05-13 12:41:42 -05:00
|
|
|
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
|
2016-05-27 12:27:56 -05:00
|
|
|
attributes::set_frame_pointer_elimination(ccx, lloncefn);
|
2015-11-14 14:12:12 -06:00
|
|
|
|
2015-02-15 14:09:26 -06:00
|
|
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
|
|
|
block_arena = TypedArena::new();
|
2016-04-06 00:34:03 -05:00
|
|
|
fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
|
2016-08-16 09:41:38 -05:00
|
|
|
let mut bcx = fcx.init(false);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2015-06-18 13:07:36 -05:00
|
|
|
|
2015-02-15 14:09:26 -06:00
|
|
|
// the first argument (`self`) will be the (by value) closure env.
|
2016-03-06 08:30:21 -06:00
|
|
|
|
|
|
|
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() {
|
2016-08-16 09:41:38 -05:00
|
|
|
llargs[self_idx]
|
2016-03-06 08:30:21 -06:00
|
|
|
} else {
|
2016-08-16 09:41:38 -05:00
|
|
|
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
|
2016-03-06 08:30:21 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2016-08-16 09:41:38 -05:00
|
|
|
let dest = fcx.llretslotptr.get();
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2016-03-06 09:32:47 -06:00
|
|
|
let callee = Callee {
|
|
|
|
data: callee::Fn(llreffn),
|
|
|
|
ty: llref_fn_ty
|
|
|
|
};
|
2016-08-16 09:41:38 -05:00
|
|
|
|
|
|
|
// 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;
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2016-02-07 05:35:39 -06:00
|
|
|
fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
2016-03-06 08:30:21 -06:00
|
|
|
fcx.finish(bcx, DebugLoc::None);
|
2015-02-15 14:09:26 -06:00
|
|
|
|
|
|
|
lloncefn
|
|
|
|
}
|