@@ -205,6 +205,7 @@ use rustc::mir::visit::Visitor as MirVisitor;
205205use syntax:: abi:: Abi ;
206206use syntax_pos:: DUMMY_SP ;
207207use base:: custom_coerce_unsize_info;
208+ use callee:: needs_fn_once_adapter_shim;
208209use context:: SharedCrateContext ;
209210use common:: fulfill_obligation;
210211use glue:: { self , DropGlueKind } ;
@@ -568,7 +569,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
568569 callee_substs,
569570 self . param_substs ) ;
570571
571- if let Some ( ( callee_def_id, callee_substs) ) = dispatched {
572+ if let StaticDispatchResult :: Dispatched {
573+ def_id : callee_def_id,
574+ substs : callee_substs,
575+ fn_once_adjustment,
576+ } = dispatched {
572577 // if we have a concrete impl (which we might not have
573578 // in the case of something compiler generated like an
574579 // object shim or a closure that is handled differently),
@@ -581,6 +586,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
581586 callee_substs,
582587 self . param_substs ) ;
583588 self . output . push ( trans_item) ;
589+
590+ // This call will instantiate an FnOnce adapter, which drops
591+ // the closure environment. Therefore we need to make sure
592+ // that we collect the drop-glue for the environment type.
593+ if let Some ( env_ty) = fn_once_adjustment {
594+ let env_ty = glue:: get_drop_glue_type ( self . scx , env_ty) ;
595+ if self . scx . type_needs_drop ( env_ty) {
596+ let dg = DropGlueKind :: Ty ( env_ty) ;
597+ self . output . push ( TransItem :: DropGlue ( dg) ) ;
598+ }
599+ }
584600 }
585601 }
586602 }
@@ -793,15 +809,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
793809 bug ! ( "encountered unexpected type" ) ;
794810 }
795811 }
796-
797-
798812}
799813
800814fn do_static_dispatch < ' a , ' tcx > ( scx : & SharedCrateContext < ' a , ' tcx > ,
801815 fn_def_id : DefId ,
802816 fn_substs : & ' tcx Substs < ' tcx > ,
803817 param_substs : & ' tcx Substs < ' tcx > )
804- -> Option < ( DefId , & ' tcx Substs < ' tcx > ) > {
818+ -> StaticDispatchResult < ' tcx > {
805819 debug ! ( "do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})" ,
806820 def_id_to_string( scx. tcx( ) , fn_def_id) ,
807821 fn_substs,
@@ -818,18 +832,38 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
818832 debug ! ( " => regular function" ) ;
819833 // The function is not part of an impl or trait, no dispatching
820834 // to be done
821- Some ( ( fn_def_id, fn_substs) )
835+ StaticDispatchResult :: Dispatched {
836+ def_id : fn_def_id,
837+ substs : fn_substs,
838+ fn_once_adjustment : None ,
839+ }
822840 }
823841}
824842
843+ enum StaticDispatchResult < ' tcx > {
844+ // The call could be resolved statically as going to the method with
845+ // `def_id` and `substs`.
846+ Dispatched {
847+ def_id : DefId ,
848+ substs : & ' tcx Substs < ' tcx > ,
849+
850+ // If this is a call to a closure that needs an FnOnce adjustment,
851+ // this contains the new self type of the call (= type of the closure
852+ // environment)
853+ fn_once_adjustment : Option < ty:: Ty < ' tcx > > ,
854+ } ,
855+ // This goes to somewhere that we don't know at compile-time
856+ Unknown
857+ }
858+
825859// Given a trait-method and substitution information, find out the actual
826860// implementation of the trait method.
827861fn do_static_trait_method_dispatch < ' a , ' tcx > ( scx : & SharedCrateContext < ' a , ' tcx > ,
828862 trait_method : & ty:: AssociatedItem ,
829863 trait_id : DefId ,
830864 callee_substs : & ' tcx Substs < ' tcx > ,
831865 param_substs : & ' tcx Substs < ' tcx > )
832- -> Option < ( DefId , & ' tcx Substs < ' tcx > ) > {
866+ -> StaticDispatchResult < ' tcx > {
833867 let tcx = scx. tcx ( ) ;
834868 debug ! ( "do_static_trait_method_dispatch(trait_method={}, \
835869 trait_id={}, \
@@ -850,17 +884,56 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
850884 // the actual function:
851885 match vtbl {
852886 traits:: VtableImpl ( impl_data) => {
853- Some ( traits:: find_method ( tcx, trait_method. name , rcvr_substs, & impl_data) )
887+ let ( def_id, substs) = traits:: find_method ( tcx,
888+ trait_method. name ,
889+ rcvr_substs,
890+ & impl_data) ;
891+ StaticDispatchResult :: Dispatched {
892+ def_id : def_id,
893+ substs : substs,
894+ fn_once_adjustment : None ,
895+ }
854896 }
855897 traits:: VtableClosure ( closure_data) => {
856- Some ( ( closure_data. closure_def_id , closure_data. substs . substs ) )
898+ let closure_def_id = closure_data. closure_def_id ;
899+ let trait_closure_kind = tcx. lang_items . fn_trait_kind ( trait_id) . unwrap ( ) ;
900+ let actual_closure_kind = tcx. closure_kind ( closure_def_id) ;
901+
902+ let needs_fn_once_adapter_shim =
903+ match needs_fn_once_adapter_shim ( actual_closure_kind,
904+ trait_closure_kind) {
905+ Ok ( true ) => true ,
906+ _ => false ,
907+ } ;
908+
909+ let fn_once_adjustment = if needs_fn_once_adapter_shim {
910+ Some ( tcx. mk_closure_from_closure_substs ( closure_def_id,
911+ closure_data. substs ) )
912+ } else {
913+ None
914+ } ;
915+
916+ StaticDispatchResult :: Dispatched {
917+ def_id : closure_def_id,
918+ substs : closure_data. substs . substs ,
919+ fn_once_adjustment : fn_once_adjustment,
920+ }
857921 }
858- // Trait object and function pointer shims are always
859- // instantiated in-place, and as they are just an ABI-adjusting
860- // indirect call they do not have any dependencies.
861- traits:: VtableFnPointer ( ..) |
922+ traits:: VtableFnPointer ( ref data) => {
923+ // If we know the destination of this fn-pointer, we'll have to make
924+ // sure that this destination actually gets instantiated.
925+ if let ty:: TyFnDef ( def_id, substs, _) = data. fn_ty . sty {
926+ // The destination of the pointer might be something that needs
927+ // further dispatching, such as a trait method, so we do that.
928+ do_static_dispatch ( scx, def_id, substs, param_substs)
929+ } else {
930+ StaticDispatchResult :: Unknown
931+ }
932+ }
933+ // Trait object shims are always instantiated in-place, and as they are
934+ // just an ABI-adjusting indirect call they do not have any dependencies.
862935 traits:: VtableObject ( ..) => {
863- None
936+ StaticDispatchResult :: Unknown
864937 }
865938 _ => {
866939 bug ! ( "static call to invalid vtable: {:?}" , vtbl)
@@ -994,8 +1067,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
9941067 // Walk all methods of the trait, including those of its supertraits
9951068 let methods = traits:: get_vtable_methods ( scx. tcx ( ) , poly_trait_ref) ;
9961069 let methods = methods. filter_map ( |method| method)
997- . filter_map ( |( def_id, substs) | do_static_dispatch ( scx, def_id, substs,
998- param_substs) )
1070+ . filter_map ( |( def_id, substs) | {
1071+ if let StaticDispatchResult :: Dispatched {
1072+ def_id,
1073+ substs,
1074+ // We already add the drop-glue for the closure env
1075+ // unconditionally below.
1076+ fn_once_adjustment : _ ,
1077+ } = do_static_dispatch ( scx, def_id, substs, param_substs) {
1078+ Some ( ( def_id, substs) )
1079+ } else {
1080+ None
1081+ }
1082+ } )
9991083 . filter ( |& ( def_id, _) | can_have_local_instance ( scx. tcx ( ) , def_id) )
10001084 . map ( |( def_id, substs) | create_fn_trans_item ( scx, def_id, substs, param_substs) ) ;
10011085 output. extend ( methods) ;
0 commit comments