@@ -26,11 +26,11 @@ use attributes;
26
26
use base;
27
27
use base:: * ;
28
28
use build:: * ;
29
- use closure;
30
29
use common:: { self , Block , Result , CrateContext , FunctionContext , SharedCrateContext } ;
31
30
use consts;
32
31
use debuginfo:: DebugLoc ;
33
32
use declare;
33
+ use value:: Value ;
34
34
use meth;
35
35
use monomorphize:: { self , Instance } ;
36
36
use trans_item:: TransItem ;
@@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> {
147
147
// after passing through fulfill_obligation
148
148
let trait_closure_kind = tcx. lang_items . fn_trait_kind ( trait_id) . unwrap ( ) ;
149
149
let instance = Instance :: new ( def_id, substs) ;
150
- let llfn = closure:: trans_closure_method ( ccx,
151
- vtable_closure. closure_def_id ,
152
- vtable_closure. substs ,
153
- instance,
154
- trait_closure_kind) ;
150
+ let llfn = trans_closure_method (
151
+ ccx,
152
+ vtable_closure. closure_def_id ,
153
+ vtable_closure. substs ,
154
+ instance,
155
+ trait_closure_kind) ;
155
156
156
157
let method_ty = def_ty ( ccx. shared ( ) , def_id, substs) ;
157
158
Callee :: ptr ( llfn, method_ty)
@@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
250
251
monomorphize:: apply_param_substs ( shared, substs, & ty)
251
252
}
252
253
254
+
255
+ fn trans_closure_method < ' a , ' tcx > ( ccx : & ' a CrateContext < ' a , ' tcx > ,
256
+ def_id : DefId ,
257
+ substs : ty:: ClosureSubsts < ' tcx > ,
258
+ method_instance : Instance < ' tcx > ,
259
+ trait_closure_kind : ty:: ClosureKind )
260
+ -> ValueRef
261
+ {
262
+ // If this is a closure, redirect to it.
263
+ let ( llfn, _) = get_fn ( ccx, def_id, substs. substs ) ;
264
+
265
+ // If the closure is a Fn closure, but a FnOnce is needed (etc),
266
+ // then adapt the self type
267
+ let llfn_closure_kind = ccx. tcx ( ) . closure_kind ( def_id) ;
268
+
269
+ let _icx = push_ctxt ( "trans_closure_adapter_shim" ) ;
270
+
271
+ debug ! ( "trans_closure_adapter_shim(llfn_closure_kind={:?}, \
272
+ trait_closure_kind={:?}, llfn={:?})",
273
+ llfn_closure_kind, trait_closure_kind, Value ( llfn) ) ;
274
+
275
+ match ( llfn_closure_kind, trait_closure_kind) {
276
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: Fn ) |
277
+ ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnMut ) |
278
+ ( ty:: ClosureKind :: FnOnce , ty:: ClosureKind :: FnOnce ) => {
279
+ // No adapter needed.
280
+ llfn
281
+ }
282
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnMut ) => {
283
+ // The closure fn `llfn` is a `fn(&self, ...)`. We want a
284
+ // `fn(&mut self, ...)`. In fact, at trans time, these are
285
+ // basically the same thing, so we can just return llfn.
286
+ llfn
287
+ }
288
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnOnce ) |
289
+ ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnOnce ) => {
290
+ // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
291
+ // self, ...)`. We want a `fn(self, ...)`. We can produce
292
+ // this by doing something like:
293
+ //
294
+ // fn call_once(self, ...) { call_mut(&self, ...) }
295
+ // fn call_once(mut self, ...) { call_mut(&mut self, ...) }
296
+ //
297
+ // These are both the same at trans time.
298
+ trans_fn_once_adapter_shim ( ccx, def_id, substs, method_instance, llfn)
299
+ }
300
+ _ => {
301
+ bug ! ( "trans_closure_adapter_shim: cannot convert {:?} to {:?}" ,
302
+ llfn_closure_kind,
303
+ trait_closure_kind) ;
304
+ }
305
+ }
306
+ }
307
+
308
+ fn trans_fn_once_adapter_shim < ' a , ' tcx > (
309
+ ccx : & ' a CrateContext < ' a , ' tcx > ,
310
+ def_id : DefId ,
311
+ substs : ty:: ClosureSubsts < ' tcx > ,
312
+ method_instance : Instance < ' tcx > ,
313
+ llreffn : ValueRef )
314
+ -> ValueRef
315
+ {
316
+ if let Some ( & llfn) = ccx. instances ( ) . borrow ( ) . get ( & method_instance) {
317
+ return llfn;
318
+ }
319
+
320
+ debug ! ( "trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})" ,
321
+ def_id, substs, Value ( llreffn) ) ;
322
+
323
+ let tcx = ccx. tcx ( ) ;
324
+
325
+ // Find a version of the closure type. Substitute static for the
326
+ // region since it doesn't really matter.
327
+ let closure_ty = tcx. mk_closure_from_closure_substs ( def_id, substs) ;
328
+ let ref_closure_ty = tcx. mk_imm_ref ( tcx. mk_region ( ty:: ReErased ) , closure_ty) ;
329
+
330
+ // Make a version with the type of by-ref closure.
331
+ let ty:: ClosureTy { unsafety, abi, mut sig } = tcx. closure_type ( def_id, substs) ;
332
+ sig. 0 . inputs . insert ( 0 , ref_closure_ty) ; // sig has no self type as of yet
333
+ let llref_fn_ty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
334
+ unsafety : unsafety,
335
+ abi : abi,
336
+ sig : sig. clone ( )
337
+ } ) ) ;
338
+ debug ! ( "trans_fn_once_adapter_shim: llref_fn_ty={:?}" ,
339
+ llref_fn_ty) ;
340
+
341
+
342
+ // Make a version of the closure type with the same arguments, but
343
+ // with argument #0 being by value.
344
+ assert_eq ! ( abi, Abi :: RustCall ) ;
345
+ sig. 0 . inputs [ 0 ] = closure_ty;
346
+
347
+ let sig = tcx. erase_late_bound_regions_and_normalize ( & sig) ;
348
+ let fn_ty = FnType :: new ( ccx, abi, & sig, & [ ] ) ;
349
+
350
+ let llonce_fn_ty = tcx. mk_fn_ptr ( tcx. mk_bare_fn ( ty:: BareFnTy {
351
+ unsafety : unsafety,
352
+ abi : abi,
353
+ sig : ty:: Binder ( sig)
354
+ } ) ) ;
355
+
356
+ // Create the by-value helper.
357
+ let function_name = method_instance. symbol_name ( ccx. shared ( ) ) ;
358
+ let lloncefn = declare:: define_internal_fn ( ccx, & function_name, llonce_fn_ty) ;
359
+ attributes:: set_frame_pointer_elimination ( ccx, lloncefn) ;
360
+
361
+ let ( block_arena, fcx) : ( TypedArena < _ > , FunctionContext ) ;
362
+ block_arena = TypedArena :: new ( ) ;
363
+ fcx = FunctionContext :: new ( ccx, lloncefn, fn_ty, None , & block_arena) ;
364
+ let mut bcx = fcx. init ( false ) ;
365
+
366
+
367
+ // the first argument (`self`) will be the (by value) closure env.
368
+
369
+ let mut llargs = get_params ( fcx. llfn ) ;
370
+ let mut self_idx = fcx. fn_ty . ret . is_indirect ( ) as usize ;
371
+ let env_arg = & fcx. fn_ty . args [ 0 ] ;
372
+ let llenv = if env_arg. is_indirect ( ) {
373
+ llargs[ self_idx]
374
+ } else {
375
+ let scratch = alloc_ty ( bcx, closure_ty, "self" ) ;
376
+ let mut llarg_idx = self_idx;
377
+ env_arg. store_fn_arg ( & bcx. build ( ) , & mut llarg_idx, scratch) ;
378
+ scratch
379
+ } ;
380
+
381
+ debug ! ( "trans_fn_once_adapter_shim: env={:?}" , Value ( llenv) ) ;
382
+ // Adjust llargs such that llargs[self_idx..] has the call arguments.
383
+ // For zero-sized closures that means sneaking in a new argument.
384
+ if env_arg. is_ignore ( ) {
385
+ if self_idx > 0 {
386
+ self_idx -= 1 ;
387
+ llargs[ self_idx] = llenv;
388
+ } else {
389
+ llargs. insert ( 0 , llenv) ;
390
+ }
391
+ } else {
392
+ llargs[ self_idx] = llenv;
393
+ }
394
+
395
+ let dest = fcx. llretslotptr . get ( ) ;
396
+
397
+ let callee = Callee {
398
+ data : Fn ( llreffn) ,
399
+ ty : llref_fn_ty
400
+ } ;
401
+
402
+ // Call the by-ref closure body with `self` in a cleanup scope,
403
+ // to drop `self` when the body returns, or in case it unwinds.
404
+ let self_scope = fcx. push_custom_cleanup_scope ( ) ;
405
+ fcx. schedule_drop_mem ( self_scope, llenv, closure_ty) ;
406
+
407
+ bcx = callee. call ( bcx, DebugLoc :: None , & llargs[ self_idx..] , dest) . bcx ;
408
+
409
+ fcx. pop_and_trans_custom_cleanup_scope ( bcx, self_scope) ;
410
+
411
+ fcx. finish ( bcx, DebugLoc :: None ) ;
412
+
413
+ ccx. instances ( ) . borrow_mut ( ) . insert ( method_instance, lloncefn) ;
414
+
415
+ lloncefn
416
+ }
417
+
253
418
/// Translates an adapter that implements the `Fn` trait for a fn
254
419
/// pointer. This is basically the equivalent of something like:
255
420
///
0 commit comments