1 // Copyright 2012-2014 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 use arena
::TypedArena
;
12 use llvm
::{self, ValueRef, get_params}
;
13 use rustc
::hir
::def_id
::DefId
;
14 use abi
::{Abi, FnType}
;
17 use callee
::{self, Callee}
;
19 use debuginfo
::{DebugLoc}
;
21 use monomorphize
::{Instance}
;
23 use rustc
::ty
::{self, Ty, TyCtxt}
;
27 fn get_self_type
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
31 match tcx
.closure_kind(closure_id
) {
32 ty
::ClosureKind
::Fn
=> {
33 tcx
.mk_imm_ref(tcx
.mk_region(ty
::ReErased
), fn_ty
)
35 ty
::ClosureKind
::FnMut
=> {
36 tcx
.mk_mut_ref(tcx
.mk_region(ty
::ReErased
), fn_ty
)
38 ty
::ClosureKind
::FnOnce
=> fn_ty
,
42 /// Returns the LLVM function declaration for a closure, creating it if
43 /// necessary. If the ID does not correspond to a closure ID, returns None.
44 fn get_or_create_closure_declaration
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
46 substs
: ty
::ClosureSubsts
<'tcx
>)
48 // Normalize type so differences in regions and typedefs don't cause
49 // duplicate declarations
51 let substs
= tcx
.erase_regions(&substs
);
52 let instance
= Instance
::new(closure_id
, substs
.func_substs
);
54 if let Some(&llfn
) = ccx
.instances().borrow().get(&instance
) {
55 debug
!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
56 instance
, Value(llfn
));
60 let symbol
= instance
.symbol_name(ccx
.shared());
62 // Compute the rust-call form of the closure call method.
63 let sig
= &tcx
.closure_type(closure_id
, substs
).sig
;
64 let sig
= tcx
.erase_late_bound_regions_and_normalize(sig
);
65 let closure_type
= tcx
.mk_closure_from_closure_substs(closure_id
, substs
);
66 let function_type
= tcx
.mk_fn_ptr(tcx
.mk_bare_fn(ty
::BareFnTy
{
67 unsafety
: hir
::Unsafety
::Normal
,
69 sig
: ty
::Binder(ty
::FnSig
{
70 inputs
: Some(get_self_type(tcx
, closure_id
, closure_type
))
71 .into_iter().chain(sig
.inputs
).collect(),
76 let llfn
= declare
::declare_fn(ccx
, &symbol
, function_type
);
78 attributes
::set_frame_pointer_elimination(ccx
, llfn
);
80 debug
!("get_or_create_declaration_if_closure(): inserting new \
82 instance
, Value(llfn
));
84 // NOTE: We do *not* store llfn in the ccx.instances() map here,
85 // that is only done, when the closures body is translated.
90 pub fn trans_closure_body_via_mir
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
91 closure_def_id
: DefId
,
92 closure_substs
: ty
::ClosureSubsts
<'tcx
>) {
93 // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
94 // defid of the closure in its original crate, whereas `id` will be the id of the local
96 debug
!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})",
97 closure_def_id
, closure_substs
);
100 let _icx
= push_ctxt("closure::trans_closure_expr");
102 let param_substs
= closure_substs
.func_substs
;
103 let instance
= Instance
::new(closure_def_id
, param_substs
);
105 // If we have not done so yet, translate this closure's body
106 if !ccx
.instances().borrow().contains_key(&instance
) {
107 let llfn
= get_or_create_closure_declaration(ccx
, closure_def_id
, closure_substs
);
110 if ccx
.sess().target
.target
.options
.allows_weak_linkage
{
111 llvm
::LLVMRustSetLinkage(llfn
, llvm
::Linkage
::WeakODRLinkage
);
112 llvm
::SetUniqueComdat(ccx
.llmod(), llfn
);
114 llvm
::LLVMRustSetLinkage(llfn
, llvm
::Linkage
::InternalLinkage
);
118 // set an inline hint for all closures
119 attributes
::inline(llfn
, attributes
::InlineAttr
::Hint
);
121 // Get the type of this closure. Use the current `param_substs` as
122 // the closure substitutions. This makes sense because the closure
123 // takes the same set of type arguments as the enclosing fn, and
124 // this function (`trans_closure`) is invoked at the point
125 // of the closure expression.
127 let sig
= &tcx
.closure_type(closure_def_id
, closure_substs
).sig
;
128 let sig
= tcx
.erase_late_bound_regions_and_normalize(sig
);
130 let closure_type
= tcx
.mk_closure_from_closure_substs(closure_def_id
,
132 let sig
= ty
::FnSig
{
133 inputs
: Some(get_self_type(tcx
, closure_def_id
, closure_type
))
134 .into_iter().chain(sig
.inputs
).collect(),
141 Instance
::new(closure_def_id
, param_substs
),
145 ccx
.instances().borrow_mut().insert(instance
, llfn
);
149 pub fn trans_closure_method
<'a
, 'tcx
>(ccx
: &'a CrateContext
<'a
, 'tcx
>,
150 closure_def_id
: DefId
,
151 substs
: ty
::ClosureSubsts
<'tcx
>,
152 method_instance
: Instance
<'tcx
>,
153 trait_closure_kind
: ty
::ClosureKind
)
156 // If this is a closure, redirect to it.
157 let llfn
= get_or_create_closure_declaration(ccx
, closure_def_id
, substs
);
159 // If weak linkage is not allowed, we have to make sure that a local,
160 // private copy of the closure is available in this codegen unit
161 if !ccx
.sess().target
.target
.options
.allows_weak_linkage
&&
162 !ccx
.sess().opts
.single_codegen_unit() {
164 trans_closure_body_via_mir(ccx
, closure_def_id
, substs
);
167 // If the closure is a Fn closure, but a FnOnce is needed (etc),
168 // then adapt the self type
169 let llfn_closure_kind
= ccx
.tcx().closure_kind(closure_def_id
);
171 let _icx
= push_ctxt("trans_closure_adapter_shim");
173 debug
!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
174 trait_closure_kind={:?}, llfn={:?})",
175 llfn_closure_kind
, trait_closure_kind
, Value(llfn
));
177 match (llfn_closure_kind
, trait_closure_kind
) {
178 (ty
::ClosureKind
::Fn
, ty
::ClosureKind
::Fn
) |
179 (ty
::ClosureKind
::FnMut
, ty
::ClosureKind
::FnMut
) |
180 (ty
::ClosureKind
::FnOnce
, ty
::ClosureKind
::FnOnce
) => {
181 // No adapter needed.
184 (ty
::ClosureKind
::Fn
, ty
::ClosureKind
::FnMut
) => {
185 // The closure fn `llfn` is a `fn(&self, ...)`. We want a
186 // `fn(&mut self, ...)`. In fact, at trans time, these are
187 // basically the same thing, so we can just return llfn.
190 (ty
::ClosureKind
::Fn
, ty
::ClosureKind
::FnOnce
) |
191 (ty
::ClosureKind
::FnMut
, ty
::ClosureKind
::FnOnce
) => {
192 // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
193 // self, ...)`. We want a `fn(self, ...)`. We can produce
194 // this by doing something like:
196 // fn call_once(self, ...) { call_mut(&self, ...) }
197 // fn call_once(mut self, ...) { call_mut(&mut self, ...) }
199 // These are both the same at trans time.
200 trans_fn_once_adapter_shim(ccx
, closure_def_id
, substs
, method_instance
, llfn
)
203 bug
!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
210 fn trans_fn_once_adapter_shim
<'a
, 'tcx
>(
211 ccx
: &'a CrateContext
<'a
, 'tcx
>,
212 closure_def_id
: DefId
,
213 substs
: ty
::ClosureSubsts
<'tcx
>,
214 method_instance
: Instance
<'tcx
>,
218 if let Some(&llfn
) = ccx
.instances().borrow().get(&method_instance
) {
222 debug
!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
223 closure_def_id
, substs
, Value(llreffn
));
227 // Find a version of the closure type. Substitute static for the
228 // region since it doesn't really matter.
229 let closure_ty
= tcx
.mk_closure_from_closure_substs(closure_def_id
, substs
);
230 let ref_closure_ty
= tcx
.mk_imm_ref(tcx
.mk_region(ty
::ReErased
), closure_ty
);
232 // Make a version with the type of by-ref closure.
233 let ty
::ClosureTy { unsafety, abi, mut sig }
=
234 tcx
.closure_type(closure_def_id
, substs
);
235 sig
.0.inputs
.insert(0, ref_closure_ty
); // sig has no self type as of yet
236 let llref_fn_ty
= tcx
.mk_fn_ptr(tcx
.mk_bare_fn(ty
::BareFnTy
{
241 debug
!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
245 // Make a version of the closure type with the same arguments, but
246 // with argument #0 being by value.
247 assert_eq
!(abi
, Abi
::RustCall
);
248 sig
.0.inputs
[0] = closure_ty
;
250 let sig
= tcx
.erase_late_bound_regions_and_normalize(&sig
);
251 let fn_ty
= FnType
::new(ccx
, abi
, &sig
, &[]);
253 let llonce_fn_ty
= tcx
.mk_fn_ptr(tcx
.mk_bare_fn(ty
::BareFnTy
{
259 // Create the by-value helper.
260 let function_name
= method_instance
.symbol_name(ccx
.shared());
261 let lloncefn
= declare
::define_internal_fn(ccx
, &function_name
, llonce_fn_ty
);
262 attributes
::set_frame_pointer_elimination(ccx
, lloncefn
);
264 let (block_arena
, fcx
): (TypedArena
<_
>, FunctionContext
);
265 block_arena
= TypedArena
::new();
266 fcx
= FunctionContext
::new(ccx
, lloncefn
, fn_ty
, None
, &block_arena
);
267 let mut bcx
= fcx
.init(false);
270 // the first argument (`self`) will be the (by value) closure env.
272 let mut llargs
= get_params(fcx
.llfn
);
273 let mut self_idx
= fcx
.fn_ty
.ret
.is_indirect() as usize;
274 let env_arg
= &fcx
.fn_ty
.args
[0];
275 let llenv
= if env_arg
.is_indirect() {
278 let scratch
= alloc_ty(bcx
, closure_ty
, "self");
279 let mut llarg_idx
= self_idx
;
280 env_arg
.store_fn_arg(&bcx
.build(), &mut llarg_idx
, scratch
);
284 debug
!("trans_fn_once_adapter_shim: env={:?}", Value(llenv
));
285 // Adjust llargs such that llargs[self_idx..] has the call arguments.
286 // For zero-sized closures that means sneaking in a new argument.
287 if env_arg
.is_ignore() {
290 llargs
[self_idx
] = llenv
;
292 llargs
.insert(0, llenv
);
295 llargs
[self_idx
] = llenv
;
298 let dest
= fcx
.llretslotptr
.get();
300 let callee
= Callee
{
301 data
: callee
::Fn(llreffn
),
305 // Call the by-ref closure body with `self` in a cleanup scope,
306 // to drop `self` when the body returns, or in case it unwinds.
307 let self_scope
= fcx
.push_custom_cleanup_scope();
308 fcx
.schedule_drop_mem(self_scope
, llenv
, closure_ty
);
310 bcx
= callee
.call(bcx
, DebugLoc
::None
, &llargs
[self_idx
..], dest
).bcx
;
312 fcx
.pop_and_trans_custom_cleanup_scope(bcx
, self_scope
);
314 fcx
.finish(bcx
, DebugLoc
::None
);
316 ccx
.instances().borrow_mut().insert(method_instance
, lloncefn
);