@@ -26,11 +26,11 @@ use attributes;
2626use base;
2727use base:: * ;
2828use build:: * ;
29- use closure;
3029use common:: { self , Block , Result , CrateContext , FunctionContext , SharedCrateContext } ;
3130use consts;
3231use debuginfo:: DebugLoc ;
3332use declare;
33+ use value:: Value ;
3434use meth;
3535use monomorphize:: { self , Instance } ;
3636use trans_item:: TransItem ;
@@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> {
147147 // after passing through fulfill_obligation
148148 let trait_closure_kind = tcx. lang_items . fn_trait_kind ( trait_id) . unwrap ( ) ;
149149 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) ;
155156
156157 let method_ty = def_ty ( ccx. shared ( ) , def_id, substs) ;
157158 Callee :: ptr ( llfn, method_ty)
@@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
250251 monomorphize:: apply_param_substs ( shared, substs, & ty)
251252}
252253
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+
253418/// Translates an adapter that implements the `Fn` trait for a fn
254419/// pointer. This is basically the equivalent of something like:
255420///
0 commit comments