6
6
use crate :: expr_use_visitor:: { self , ExprUseVisitor } ;
7
7
8
8
use super :: FnCtxt ;
9
- use hir:: HirIdMap ;
9
+ use hir:: { HirIdMap , Node } ;
10
10
use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
11
11
use rustc_errors:: pluralize;
12
12
use rustc_hir as hir;
@@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId;
15
15
use rustc_hir:: hir_id:: HirIdSet ;
16
16
use rustc_hir:: intravisit:: { self , Visitor } ;
17
17
use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
18
+ use rustc_middle:: hir:: map:: Map ;
18
19
use rustc_middle:: hir:: place:: { Place , PlaceBase } ;
19
20
use rustc_middle:: middle:: region:: { self , YieldData } ;
20
21
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
@@ -225,6 +226,7 @@ pub fn resolve_interior<'a, 'tcx>(
225
226
226
227
let mut visitor = {
227
228
let mut drop_range_visitor = DropRangeVisitor {
229
+ hir : fcx. tcx . hir ( ) ,
228
230
consumed_places : <_ >:: default ( ) ,
229
231
borrowed_places : <_ >:: default ( ) ,
230
232
drop_ranges : vec ! [ <_>:: default ( ) ] ,
@@ -664,19 +666,28 @@ fn check_must_not_suspend_def(
664
666
}
665
667
666
668
/// This struct facilitates computing the ranges for which a place is uninitialized.
667
- struct DropRangeVisitor {
668
- consumed_places : HirIdSet ,
669
+ struct DropRangeVisitor < ' tcx > {
670
+ hir : Map < ' tcx > ,
671
+ /// Maps a HirId to a set of HirIds that are dropped by that node.
672
+ consumed_places : HirIdMap < HirIdSet > ,
669
673
borrowed_places : HirIdSet ,
670
674
drop_ranges : Vec < HirIdMap < DropRange > > ,
671
675
expr_count : usize ,
672
676
}
673
677
674
- impl DropRangeVisitor {
678
+ impl DropRangeVisitor < ' tcx > {
679
+ fn mark_consumed ( & mut self , consumer : HirId , target : HirId ) {
680
+ if !self . consumed_places . contains_key ( & consumer) {
681
+ self . consumed_places . insert ( consumer, <_ >:: default ( ) ) ;
682
+ }
683
+ self . consumed_places . get_mut ( & consumer) . map ( |places| places. insert ( target) ) ;
684
+ }
685
+
675
686
fn record_drop ( & mut self , hir_id : HirId ) {
676
687
let drop_ranges = self . drop_ranges . last_mut ( ) . unwrap ( ) ;
677
688
if self . borrowed_places . contains ( & hir_id) {
678
689
debug ! ( "not marking {:?} as dropped because it is borrowed at some point" , hir_id) ;
679
- } else if self . consumed_places . contains ( & hir_id ) {
690
+ } else {
680
691
debug ! ( "marking {:?} as dropped at {}" , hir_id, self . expr_count) ;
681
692
drop_ranges. insert ( hir_id, DropRange { dropped_at : self . expr_count } ) ;
682
693
}
@@ -700,15 +711,24 @@ impl DropRangeVisitor {
700
711
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
701
712
/// expressions. This method consumes a little deeper into the expression when needed.
702
713
fn consume_expr ( & mut self , expr : & hir:: Expr < ' _ > ) {
703
- self . record_drop ( expr. hir_id ) ;
704
- match expr. kind {
705
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
706
- _,
707
- hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } ,
708
- ) ) => {
709
- self . record_drop ( * hir_id) ;
714
+ debug ! ( "consuming expr {:?}, count={}" , expr. hir_id, self . expr_count) ;
715
+ let places = self
716
+ . consumed_places
717
+ . get ( & expr. hir_id )
718
+ . map_or ( vec ! [ ] , |places| places. iter ( ) . cloned ( ) . collect ( ) ) ;
719
+ for place in places {
720
+ self . record_drop ( place) ;
721
+ if let Some ( Node :: Expr ( expr) ) = self . hir . find ( place) {
722
+ match expr. kind {
723
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
724
+ _,
725
+ hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } ,
726
+ ) ) => {
727
+ self . record_drop ( * hir_id) ;
728
+ }
729
+ _ => ( ) ,
730
+ }
710
731
}
711
- _ => ( ) ,
712
732
}
713
733
}
714
734
}
@@ -721,15 +741,19 @@ fn place_hir_id(place: &Place<'_>) -> Option<HirId> {
721
741
}
722
742
}
723
743
724
- impl < ' tcx > expr_use_visitor:: Delegate < ' tcx > for DropRangeVisitor {
744
+ impl < ' tcx > expr_use_visitor:: Delegate < ' tcx > for DropRangeVisitor < ' tcx > {
725
745
fn consume (
726
746
& mut self ,
727
747
place_with_id : & expr_use_visitor:: PlaceWithHirId < ' tcx > ,
728
748
diag_expr_id : hir:: HirId ,
729
749
) {
730
- debug ! ( "consume {:?}; diag_expr_id={:?}" , place_with_id, diag_expr_id) ;
731
- self . consumed_places . insert ( place_with_id. hir_id ) ;
732
- place_hir_id ( & place_with_id. place ) . map ( |place| self . consumed_places . insert ( place) ) ;
750
+ let parent = match self . hir . find_parent_node ( place_with_id. hir_id ) {
751
+ Some ( parent) => parent,
752
+ None => place_with_id. hir_id ,
753
+ } ;
754
+ debug ! ( "consume {:?}; diag_expr_id={:?}, using parent {:?}" , place_with_id, diag_expr_id, parent) ;
755
+ self . mark_consumed ( parent, place_with_id. hir_id ) ;
756
+ place_hir_id ( & place_with_id. place ) . map ( |place| self . mark_consumed ( parent, place) ) ;
733
757
}
734
758
735
759
fn borrow (
@@ -757,7 +781,7 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for DropRangeVisitor {
757
781
}
758
782
}
759
783
760
- impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor {
784
+ impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' tcx > {
761
785
type Map = intravisit:: ErasedMap < ' tcx > ;
762
786
763
787
fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -766,20 +790,20 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor {
766
790
767
791
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
768
792
match expr. kind {
769
- ExprKind :: AssignOp ( _ , lhs, rhs) => {
793
+ ExprKind :: AssignOp ( _op , lhs, rhs) => {
770
794
// These operations are weird because their order of evaluation depends on whether
771
795
// the operator is overloaded. In a perfect world, we'd just ask the type checker
772
796
// whether this is a method call, but we also need to match the expression IDs
773
797
// from RegionResolutionVisitor. RegionResolutionVisitor doesn't know the order,
774
798
// so it runs both orders and picks the most conservative. We'll mirror that here.
775
799
let mut old_count = self . expr_count ;
776
- intravisit :: walk_expr ( self , lhs) ;
777
- intravisit :: walk_expr ( self , rhs) ;
800
+ self . visit_expr ( lhs) ;
801
+ self . visit_expr ( rhs) ;
778
802
779
803
self . push_drop_scope ( ) ;
780
804
std:: mem:: swap ( & mut old_count, & mut self . expr_count ) ;
781
- intravisit :: walk_expr ( self , rhs) ;
782
- intravisit :: walk_expr ( self , lhs) ;
805
+ self . visit_expr ( rhs) ;
806
+ self . visit_expr ( lhs) ;
783
807
784
808
// We should have visited the same number of expressions in either order.
785
809
assert_eq ! ( old_count, self . expr_count) ;
0 commit comments