@@ -182,39 +182,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
182
182
}
183
183
}
184
184
}
185
-
186
- fn visit_call (
187
- & mut self ,
188
- call_expr : & ' tcx Expr < ' tcx > ,
189
- callee : & ' tcx Expr < ' tcx > ,
190
- args : & ' tcx [ Expr < ' tcx > ] ,
191
- ) {
192
- match & callee. kind {
193
- ExprKind :: Path ( qpath) => {
194
- let res = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, callee. hir_id ) ;
195
- match res {
196
- // Direct calls never need to keep the callee `ty::FnDef`
197
- // ZST in a temporary, so skip its type, just in case it
198
- // can significantly complicate the generator type.
199
- Res :: Def (
200
- DefKind :: Fn | DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) ,
201
- _,
202
- ) => {
203
- // NOTE(eddyb) this assumes a path expression has
204
- // no nested expressions to keep track of.
205
- self . expr_count += 1 ;
206
-
207
- // Record the rest of the call expression normally.
208
- for arg in args {
209
- self . visit_expr ( arg) ;
210
- }
211
- }
212
- _ => intravisit:: walk_expr ( self , call_expr) ,
213
- }
214
- }
215
- _ => intravisit:: walk_expr ( self , call_expr) ,
216
- }
217
- }
218
185
}
219
186
220
187
pub fn resolve_interior < ' a , ' tcx > (
@@ -252,7 +219,6 @@ pub fn resolve_interior<'a, 'tcx>(
252
219
intravisit:: walk_body ( & mut drop_range_visitor, body) ;
253
220
254
221
drop_range_visitor. drop_ranges . propagate_to_fixpoint ( ) ;
255
- // drop_range_visitor.drop_ranges.save_graph("drop_ranges.dot");
256
222
257
223
InteriorVisitor {
258
224
fcx,
@@ -395,7 +361,31 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
395
361
let mut guard_borrowing_from_pattern = false ;
396
362
397
363
match & expr. kind {
398
- ExprKind :: Call ( callee, args) => self . visit_call ( expr, callee, args) ,
364
+ ExprKind :: Call ( callee, args) => match & callee. kind {
365
+ ExprKind :: Path ( qpath) => {
366
+ let res = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, callee. hir_id ) ;
367
+ match res {
368
+ // Direct calls never need to keep the callee `ty::FnDef`
369
+ // ZST in a temporary, so skip its type, just in case it
370
+ // can significantly complicate the generator type.
371
+ Res :: Def (
372
+ DefKind :: Fn | DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) ,
373
+ _,
374
+ ) => {
375
+ // NOTE(eddyb) this assumes a path expression has
376
+ // no nested expressions to keep track of.
377
+ self . expr_count += 1 ;
378
+
379
+ // Record the rest of the call expression normally.
380
+ for arg in args. iter ( ) {
381
+ self . visit_expr ( arg) ;
382
+ }
383
+ }
384
+ _ => intravisit:: walk_expr ( self , expr) ,
385
+ }
386
+ }
387
+ _ => intravisit:: walk_expr ( self , expr) ,
388
+ } ,
399
389
ExprKind :: Path ( qpath) => {
400
390
intravisit:: walk_expr ( self , expr) ;
401
391
let res = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, expr. hir_id ) ;
@@ -675,6 +665,26 @@ fn check_must_not_suspend_def(
675
665
false
676
666
}
677
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.
678
688
struct ExprUseDelegate < ' tcx > {
679
689
hir : Map < ' tcx > ,
680
690
/// Maps a HirId to a set of HirIds that are dropped by that node.
@@ -691,7 +701,65 @@ impl<'tcx> ExprUseDelegate<'tcx> {
691
701
}
692
702
}
693
703
694
- /// This struct facilitates computing the ranges for which a place is uninitialized.
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`.
695
763
struct DropRangeVisitor < ' tcx > {
696
764
hir : Map < ' tcx > ,
697
765
/// Maps a HirId to a set of HirIds that are dropped by that node.
@@ -756,6 +824,9 @@ impl<'tcx> DropRangeVisitor<'tcx> {
756
824
}
757
825
}
758
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)`.
759
830
fn for_each_consumable ( place : HirId , node : Option < Node < ' _ > > , mut f : impl FnMut ( HirId ) ) {
760
831
f ( place) ;
761
832
if let Some ( Node :: Expr ( expr) ) = node {
@@ -771,57 +842,6 @@ fn for_each_consumable(place: HirId, node: Option<Node<'_>>, mut f: impl FnMut(H
771
842
}
772
843
}
773
844
774
- fn place_hir_id ( place : & Place < ' _ > ) -> Option < HirId > {
775
- match place. base {
776
- PlaceBase :: Rvalue | PlaceBase :: StaticItem => None ,
777
- PlaceBase :: Local ( hir_id)
778
- | PlaceBase :: Upvar ( ty:: UpvarId { var_path : ty:: UpvarPath { hir_id } , .. } ) => Some ( hir_id) ,
779
- }
780
- }
781
-
782
- impl < ' tcx > expr_use_visitor:: Delegate < ' tcx > for ExprUseDelegate < ' tcx > {
783
- fn consume (
784
- & mut self ,
785
- place_with_id : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
786
- diag_expr_id : hir:: HirId ,
787
- ) {
788
- let parent = match self . hir . find_parent_node ( place_with_id. hir_id ) {
789
- Some ( parent) => parent,
790
- None => place_with_id. hir_id ,
791
- } ;
792
- debug ! (
793
- "consume {:?}; diag_expr_id={:?}, using parent {:?}" ,
794
- place_with_id, diag_expr_id, parent
795
- ) ;
796
- self . mark_consumed ( parent, place_with_id. hir_id ) ;
797
- place_hir_id ( & place_with_id. place ) . map ( |place| self . mark_consumed ( parent, place) ) ;
798
- }
799
-
800
- fn borrow (
801
- & mut self ,
802
- place_with_id : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
803
- _diag_expr_id : hir:: HirId ,
804
- _bk : rustc_middle:: ty:: BorrowKind ,
805
- ) {
806
- place_hir_id ( & place_with_id. place ) . map ( |place| self . borrowed_places . insert ( place) ) ;
807
- }
808
-
809
- fn mutate (
810
- & mut self ,
811
- _assignee_place : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
812
- _diag_expr_id : hir:: HirId ,
813
- ) {
814
- }
815
-
816
- fn fake_read (
817
- & mut self ,
818
- _place : expr_use_visitor:: Place < ' tcx > ,
819
- _cause : rustc_middle:: mir:: FakeReadCause ,
820
- _diag_expr_id : hir:: HirId ,
821
- ) {
822
- }
823
- }
824
-
825
845
impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' tcx > {
826
846
type Map = intravisit:: ErasedMap < ' tcx > ;
827
847
@@ -832,26 +852,6 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
832
852
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
833
853
let mut reinit = None ;
834
854
match expr. kind {
835
- // ExprKind::AssignOp(_op, lhs, rhs) => {
836
- // // These operations are weird because their order of evaluation depends on whether
837
- // // the operator is overloaded. In a perfect world, we'd just ask the type checker
838
- // // whether this is a method call, but we also need to match the expression IDs
839
- // // from RegionResolutionVisitor. RegionResolutionVisitor doesn't know the order,
840
- // // so it runs both orders and picks the most conservative. We'll mirror that here.
841
- // let mut old_count = self.expr_count;
842
- // self.visit_expr(lhs);
843
- // self.visit_expr(rhs);
844
-
845
- // let old_drops = self.swap_drop_ranges(<_>::default());
846
- // std::mem::swap(&mut old_count, &mut self.expr_count);
847
- // self.visit_expr(rhs);
848
- // self.visit_expr(lhs);
849
-
850
- // // We should have visited the same number of expressions in either order.
851
- // assert_eq!(old_count, self.expr_count);
852
-
853
- // self.intersect_drop_ranges(old_drops);
854
- // }
855
855
ExprKind :: If ( test, if_true, if_false) => {
856
856
self . visit_expr ( test) ;
857
857
0 commit comments