@@ -205,6 +205,7 @@ use rustc::mir::visit::Visitor as MirVisitor;
205
205
use syntax:: abi:: Abi ;
206
206
use syntax_pos:: DUMMY_SP ;
207
207
use base:: custom_coerce_unsize_info;
208
+ use callee:: needs_fn_once_adapter_shim;
208
209
use context:: SharedCrateContext ;
209
210
use common:: fulfill_obligation;
210
211
use glue:: { self , DropGlueKind } ;
@@ -568,7 +569,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
568
569
callee_substs,
569
570
self . param_substs ) ;
570
571
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 {
572
577
// if we have a concrete impl (which we might not have
573
578
// in the case of something compiler generated like an
574
579
// object shim or a closure that is handled differently),
@@ -581,6 +586,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
581
586
callee_substs,
582
587
self . param_substs ) ;
583
588
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
+ }
584
600
}
585
601
}
586
602
}
@@ -793,15 +809,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
793
809
bug ! ( "encountered unexpected type" ) ;
794
810
}
795
811
}
796
-
797
-
798
812
}
799
813
800
814
fn do_static_dispatch < ' a , ' tcx > ( scx : & SharedCrateContext < ' a , ' tcx > ,
801
815
fn_def_id : DefId ,
802
816
fn_substs : & ' tcx Substs < ' tcx > ,
803
817
param_substs : & ' tcx Substs < ' tcx > )
804
- -> Option < ( DefId , & ' tcx Substs < ' tcx > ) > {
818
+ -> StaticDispatchResult < ' tcx > {
805
819
debug ! ( "do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})" ,
806
820
def_id_to_string( scx. tcx( ) , fn_def_id) ,
807
821
fn_substs,
@@ -818,18 +832,38 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
818
832
debug ! ( " => regular function" ) ;
819
833
// The function is not part of an impl or trait, no dispatching
820
834
// 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
+ }
822
840
}
823
841
}
824
842
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
+
825
859
// Given a trait-method and substitution information, find out the actual
826
860
// implementation of the trait method.
827
861
fn do_static_trait_method_dispatch < ' a , ' tcx > ( scx : & SharedCrateContext < ' a , ' tcx > ,
828
862
trait_method : & ty:: AssociatedItem ,
829
863
trait_id : DefId ,
830
864
callee_substs : & ' tcx Substs < ' tcx > ,
831
865
param_substs : & ' tcx Substs < ' tcx > )
832
- -> Option < ( DefId , & ' tcx Substs < ' tcx > ) > {
866
+ -> StaticDispatchResult < ' tcx > {
833
867
let tcx = scx. tcx ( ) ;
834
868
debug ! ( "do_static_trait_method_dispatch(trait_method={}, \
835
869
trait_id={}, \
@@ -850,17 +884,56 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
850
884
// the actual function:
851
885
match vtbl {
852
886
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
+ }
854
896
}
855
897
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
+ }
857
921
}
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.
862
935
traits:: VtableObject ( ..) => {
863
- None
936
+ StaticDispatchResult :: Unknown
864
937
}
865
938
_ => {
866
939
bug ! ( "static call to invalid vtable: {:?}" , vtbl)
@@ -994,8 +1067,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
994
1067
// Walk all methods of the trait, including those of its supertraits
995
1068
let methods = traits:: get_vtable_methods ( scx. tcx ( ) , poly_trait_ref) ;
996
1069
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
+ } )
999
1083
. filter ( |& ( def_id, _) | can_have_local_instance ( scx. tcx ( ) , def_id) )
1000
1084
. map ( |( def_id, substs) | create_fn_trans_item ( scx, def_id, substs, param_substs) ) ;
1001
1085
output. extend ( methods) ;
0 commit comments