3
3
//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
4
4
//! types computed here.
5
5
6
- use crate :: expr_use_visitor:: { self , ExprUseVisitor } ;
7
-
8
- use self :: drop_ranges:: DropRanges ;
9
-
6
+ use self :: drop_ranges:: { DropRangeVisitor , DropRanges , ExprUseDelegate } ;
10
7
use super :: FnCtxt ;
11
- use hir :: { HirIdMap , Node } ;
8
+ use crate :: expr_use_visitor :: ExprUseVisitor ;
12
9
use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
13
10
use rustc_errors:: pluralize;
14
11
use rustc_hir as hir;
@@ -17,8 +14,6 @@ use rustc_hir::def_id::DefId;
17
14
use rustc_hir:: hir_id:: HirIdSet ;
18
15
use rustc_hir:: intravisit:: { self , Visitor } ;
19
16
use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
20
- use rustc_middle:: hir:: map:: Map ;
21
- use rustc_middle:: hir:: place:: { Place , PlaceBase } ;
22
17
use rustc_middle:: middle:: region:: { self , YieldData } ;
23
18
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
24
19
use rustc_span:: symbol:: sym;
@@ -194,11 +189,7 @@ pub fn resolve_interior<'a, 'tcx>(
194
189
let body = fcx. tcx . hir ( ) . body ( body_id) ;
195
190
196
191
let mut visitor = {
197
- let mut expr_use_visitor = ExprUseDelegate {
198
- hir : fcx. tcx . hir ( ) ,
199
- consumed_places : <_ >:: default ( ) ,
200
- borrowed_places : <_ >:: default ( ) ,
201
- } ;
192
+ let mut expr_use_visitor = ExprUseDelegate :: new ( fcx. tcx . hir ( ) ) ;
202
193
203
194
// Run ExprUseVisitor to find where values are consumed.
204
195
ExprUseVisitor :: new (
@@ -211,14 +202,14 @@ pub fn resolve_interior<'a, 'tcx>(
211
202
. consume_body ( body) ;
212
203
213
204
let region_scope_tree = fcx. tcx . region_scope_tree ( def_id) ;
214
-
215
- let mut drop_range_visitor = DropRangeVisitor :: from (
205
+ let mut drop_range_visitor = DropRangeVisitor :: from_uses (
216
206
expr_use_visitor,
217
207
region_scope_tree. body_expr_count ( body. id ( ) ) . unwrap_or ( 0 ) ,
218
208
) ;
219
209
intravisit:: walk_body ( & mut drop_range_visitor, body) ;
220
210
221
- drop_range_visitor. drop_ranges . propagate_to_fixpoint ( ) ;
211
+ let mut drop_ranges = drop_range_visitor. into_drop_ranges ( ) ;
212
+ drop_ranges. propagate_to_fixpoint ( ) ;
222
213
223
214
InteriorVisitor {
224
215
fcx,
@@ -230,7 +221,7 @@ pub fn resolve_interior<'a, 'tcx>(
230
221
guard_bindings : <_ >:: default ( ) ,
231
222
guard_bindings_set : <_ >:: default ( ) ,
232
223
linted_values : <_ >:: default ( ) ,
233
- drop_ranges : drop_range_visitor . drop_ranges ,
224
+ drop_ranges : drop_ranges,
234
225
}
235
226
} ;
236
227
intravisit:: walk_body ( & mut visitor, body) ;
@@ -377,7 +368,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
377
368
self . expr_count += 1 ;
378
369
379
370
// Record the rest of the call expression normally.
380
- for arg in args. iter ( ) {
371
+ for arg in * args {
381
372
self . visit_expr ( arg) ;
382
373
}
383
374
}
@@ -664,266 +655,3 @@ fn check_must_not_suspend_def(
664
655
}
665
656
false
666
657
}
667
-
668
- // The following structs and impls are used for drop range analysis.
669
- //
670
- // Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
671
- // (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
672
- // generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
673
- //
674
- // There are three phases to this analysis:
675
- // 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
676
- // 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
677
- // and also build a control flow graph.
678
- // 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
679
- // the CFG and find the exact points where we know a value is definitely dropped.
680
- //
681
- // The end result is a data structure that maps the post-order index of each node in the HIR tree
682
- // to a set of values that are known to be dropped at that location.
683
-
684
- /// Works with ExprUseVisitor to find interesting values for the drop range analysis.
685
- ///
686
- /// Interesting values are those that are either dropped or borrowed. For dropped values, we also
687
- /// record the parent expression, which is the point where the drop actually takes place.
688
- struct ExprUseDelegate < ' tcx > {
689
- hir : Map < ' tcx > ,
690
- /// Maps a HirId to a set of HirIds that are dropped by that node.
691
- consumed_places : HirIdMap < HirIdSet > ,
692
- borrowed_places : HirIdSet ,
693
- }
694
-
695
- impl < ' tcx > ExprUseDelegate < ' tcx > {
696
- fn mark_consumed ( & mut self , consumer : HirId , target : HirId ) {
697
- if !self . consumed_places . contains_key ( & consumer) {
698
- self . consumed_places . insert ( consumer, <_ >:: default ( ) ) ;
699
- }
700
- self . consumed_places . get_mut ( & consumer) . map ( |places| places. insert ( target) ) ;
701
- }
702
- }
703
-
704
- impl < ' tcx > expr_use_visitor:: Delegate < ' tcx > for ExprUseDelegate < ' tcx > {
705
- fn consume (
706
- & mut self ,
707
- place_with_id : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
708
- diag_expr_id : hir:: HirId ,
709
- ) {
710
- let parent = match self . hir . find_parent_node ( place_with_id. hir_id ) {
711
- Some ( parent) => parent,
712
- None => place_with_id. hir_id ,
713
- } ;
714
- debug ! (
715
- "consume {:?}; diag_expr_id={:?}, using parent {:?}" ,
716
- place_with_id, diag_expr_id, parent
717
- ) ;
718
- self . mark_consumed ( parent, place_with_id. hir_id ) ;
719
- place_hir_id ( & place_with_id. place ) . map ( |place| self . mark_consumed ( parent, place) ) ;
720
- }
721
-
722
- fn borrow (
723
- & mut self ,
724
- place_with_id : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
725
- _diag_expr_id : hir:: HirId ,
726
- _bk : rustc_middle:: ty:: BorrowKind ,
727
- ) {
728
- place_hir_id ( & place_with_id. place ) . map ( |place| self . borrowed_places . insert ( place) ) ;
729
- }
730
-
731
- fn mutate (
732
- & mut self ,
733
- _assignee_place : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
734
- _diag_expr_id : hir:: HirId ,
735
- ) {
736
- }
737
-
738
- fn fake_read (
739
- & mut self ,
740
- _place : expr_use_visitor:: Place < ' tcx > ,
741
- _cause : rustc_middle:: mir:: FakeReadCause ,
742
- _diag_expr_id : hir:: HirId ,
743
- ) {
744
- }
745
- }
746
-
747
- /// Gives the hir_id associated with a place if one exists. This is the hir_id that we want to
748
- /// track for a value in the drop range analysis.
749
- fn place_hir_id ( place : & Place < ' _ > ) -> Option < HirId > {
750
- match place. base {
751
- PlaceBase :: Rvalue | PlaceBase :: StaticItem => None ,
752
- PlaceBase :: Local ( hir_id)
753
- | PlaceBase :: Upvar ( ty:: UpvarId { var_path : ty:: UpvarPath { hir_id } , .. } ) => Some ( hir_id) ,
754
- }
755
- }
756
-
757
- /// This struct is used to gather the information for `DropRanges` to determine the regions of the
758
- /// HIR tree for which a value is dropped.
759
- ///
760
- /// We are interested in points where a variables is dropped or initialized, and the control flow
761
- /// of the code. We identify locations in code by their post-order traversal index, so it is
762
- /// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
763
- struct DropRangeVisitor < ' tcx > {
764
- hir : Map < ' tcx > ,
765
- /// Maps a HirId to a set of HirIds that are dropped by that node.
766
- consumed_places : HirIdMap < HirIdSet > ,
767
- borrowed_places : HirIdSet ,
768
- drop_ranges : DropRanges ,
769
- expr_count : usize ,
770
- }
771
-
772
- impl < ' tcx > DropRangeVisitor < ' tcx > {
773
- fn from ( uses : ExprUseDelegate < ' tcx > , num_exprs : usize ) -> Self {
774
- debug ! ( "consumed_places: {:?}" , uses. consumed_places) ;
775
- let drop_ranges = DropRanges :: new (
776
- uses. consumed_places . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
777
- & uses. hir ,
778
- num_exprs,
779
- ) ;
780
- Self {
781
- hir : uses. hir ,
782
- consumed_places : uses. consumed_places ,
783
- borrowed_places : uses. borrowed_places ,
784
- drop_ranges,
785
- expr_count : 0 ,
786
- }
787
- }
788
-
789
- fn record_drop ( & mut self , hir_id : HirId ) {
790
- if self . borrowed_places . contains ( & hir_id) {
791
- debug ! ( "not marking {:?} as dropped because it is borrowed at some point" , hir_id) ;
792
- } else {
793
- debug ! ( "marking {:?} as dropped at {}" , hir_id, self . expr_count) ;
794
- let count = self . expr_count ;
795
- self . drop_ranges . drop_at ( hir_id, count) ;
796
- }
797
- }
798
-
799
- /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
800
- /// expressions. This method consumes a little deeper into the expression when needed.
801
- fn consume_expr ( & mut self , expr : & hir:: Expr < ' _ > ) {
802
- debug ! ( "consuming expr {:?}, count={}" , expr. hir_id, self . expr_count) ;
803
- let places = self
804
- . consumed_places
805
- . get ( & expr. hir_id )
806
- . map_or ( vec ! [ ] , |places| places. iter ( ) . cloned ( ) . collect ( ) ) ;
807
- for place in places {
808
- for_each_consumable ( place, self . hir . find ( place) , |hir_id| self . record_drop ( hir_id) ) ;
809
- }
810
- }
811
-
812
- fn reinit_expr ( & mut self , expr : & hir:: Expr < ' _ > ) {
813
- if let ExprKind :: Path ( hir:: QPath :: Resolved (
814
- _,
815
- hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } ,
816
- ) ) = expr. kind
817
- {
818
- let location = self . expr_count ;
819
- debug ! ( "reinitializing {:?} at {}" , hir_id, location) ;
820
- self . drop_ranges . reinit_at ( * hir_id, location) ;
821
- } else {
822
- debug ! ( "reinitializing {:?} is not supported" , expr) ;
823
- }
824
- }
825
- }
826
-
827
- /// Applies `f` to consumable portion of a HIR node.
828
- ///
829
- /// The `node` parameter should be the result of calling `Map::find(place)`.
830
- fn for_each_consumable ( place : HirId , node : Option < Node < ' _ > > , mut f : impl FnMut ( HirId ) ) {
831
- f ( place) ;
832
- if let Some ( Node :: Expr ( expr) ) = node {
833
- match expr. kind {
834
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
835
- _,
836
- hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } ,
837
- ) ) => {
838
- f ( * hir_id) ;
839
- }
840
- _ => ( ) ,
841
- }
842
- }
843
- }
844
-
845
- impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' tcx > {
846
- type Map = intravisit:: ErasedMap < ' tcx > ;
847
-
848
- fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
849
- NestedVisitorMap :: None
850
- }
851
-
852
- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
853
- let mut reinit = None ;
854
- match expr. kind {
855
- ExprKind :: If ( test, if_true, if_false) => {
856
- self . visit_expr ( test) ;
857
-
858
- let fork = self . expr_count ;
859
-
860
- self . drop_ranges . add_control_edge ( fork, self . expr_count + 1 ) ;
861
- self . visit_expr ( if_true) ;
862
- let true_end = self . expr_count ;
863
-
864
- self . drop_ranges . add_control_edge ( fork, self . expr_count + 1 ) ;
865
- if let Some ( if_false) = if_false {
866
- self . visit_expr ( if_false) ;
867
- }
868
-
869
- self . drop_ranges . add_control_edge ( true_end, self . expr_count + 1 ) ;
870
- }
871
- ExprKind :: Assign ( lhs, rhs, _) => {
872
- self . visit_expr ( lhs) ;
873
- self . visit_expr ( rhs) ;
874
-
875
- reinit = Some ( lhs) ;
876
- }
877
- ExprKind :: Loop ( body, ..) => {
878
- let loop_begin = self . expr_count + 1 ;
879
- self . visit_block ( body) ;
880
- self . drop_ranges . add_control_edge ( self . expr_count , loop_begin) ;
881
- }
882
- ExprKind :: Match ( scrutinee, arms, ..) => {
883
- self . visit_expr ( scrutinee) ;
884
-
885
- let fork = self . expr_count ;
886
- let arm_end_ids = arms
887
- . iter ( )
888
- . map ( |Arm { pat, body, guard, .. } | {
889
- self . drop_ranges . add_control_edge ( fork, self . expr_count + 1 ) ;
890
- self . visit_pat ( pat) ;
891
- match guard {
892
- Some ( Guard :: If ( expr) ) => self . visit_expr ( expr) ,
893
- Some ( Guard :: IfLet ( pat, expr) ) => {
894
- self . visit_pat ( pat) ;
895
- self . visit_expr ( expr) ;
896
- }
897
- None => ( ) ,
898
- }
899
- self . visit_expr ( body) ;
900
- self . expr_count
901
- } )
902
- . collect :: < Vec < _ > > ( ) ;
903
- arm_end_ids. into_iter ( ) . for_each ( |arm_end| {
904
- self . drop_ranges . add_control_edge ( arm_end, self . expr_count + 1 )
905
- } ) ;
906
- }
907
- ExprKind :: Break ( hir:: Destination { target_id : Ok ( target) , .. } , ..)
908
- | ExprKind :: Continue ( hir:: Destination { target_id : Ok ( target) , .. } , ..) => {
909
- self . drop_ranges . add_control_edge_hir_id ( self . expr_count , target) ;
910
- }
911
-
912
- _ => intravisit:: walk_expr ( self , expr) ,
913
- }
914
-
915
- self . expr_count += 1 ;
916
- self . drop_ranges . add_node_mapping ( expr. hir_id , self . expr_count ) ;
917
- self . consume_expr ( expr) ;
918
- if let Some ( expr) = reinit {
919
- self . reinit_expr ( expr) ;
920
- }
921
- }
922
-
923
- fn visit_pat ( & mut self , pat : & ' tcx Pat < ' tcx > ) {
924
- intravisit:: walk_pat ( self , pat) ;
925
-
926
- // Increment expr_count here to match what InteriorVisitor expects.
927
- self . expr_count += 1 ;
928
- }
929
- }
0 commit comments