3232//! Because of that, we can assume that the only way to change the value behind a tracked place is
3333//! by direct assignment.
3434
35+ use std:: collections:: VecDeque ;
3536use std:: fmt:: { Debug , Formatter } ;
3637
3738use rustc_data_structures:: fx:: FxHashMap ;
@@ -608,7 +609,7 @@ impl Map {
608609 pub fn from_filter < ' tcx > (
609610 tcx : TyCtxt < ' tcx > ,
610611 body : & Body < ' tcx > ,
611- filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
612+ filter : impl Fn ( Ty < ' tcx > ) -> bool ,
612613 place_limit : Option < usize > ,
613614 ) -> Self {
614615 let mut map = Self :: new ( ) ;
@@ -623,51 +624,67 @@ impl Map {
623624 & mut self ,
624625 tcx : TyCtxt < ' tcx > ,
625626 body : & Body < ' tcx > ,
626- mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
627+ filter : impl Fn ( Ty < ' tcx > ) -> bool ,
627628 exclude : BitSet < Local > ,
628629 place_limit : Option < usize > ,
629630 ) {
630631 // We use this vector as stack, pushing and popping projections.
631- let mut projection = Vec :: new ( ) ;
632+ let mut worklist = VecDeque :: with_capacity ( place_limit. unwrap_or ( body. local_decls . len ( ) ) ) ;
633+ self . locals = IndexVec :: from_elem ( None , & body. local_decls ) ;
632634 for ( local, decl) in body. local_decls . iter_enumerated ( ) {
633- if !exclude. contains ( local) {
634- self . register_with_filter_rec (
635- tcx,
636- local,
637- & mut projection,
638- decl. ty ,
639- & mut filter,
640- place_limit,
641- ) ;
635+ if exclude. contains ( local) {
636+ continue ;
642637 }
638+
639+ // Create a place for the local.
640+ debug_assert ! ( self . locals[ local] . is_none( ) ) ;
641+ let place = self . places . push ( PlaceInfo :: new ( None ) ) ;
642+ self . locals [ local] = Some ( place) ;
643+
644+ // And push the eventual children places to the worklist.
645+ self . register_children ( tcx, place, decl. ty , & filter, & mut worklist) ;
646+ }
647+
648+ // `place.elem1.elem2` with type `ty`.
649+ while let Some ( ( mut place, elem1, elem2, ty) ) = worklist. pop_front ( ) {
650+ if let Some ( place_limit) = place_limit && self . value_count >= place_limit {
651+ break
652+ }
653+
654+ // Create a place for this projection.
655+ for elem in [ elem1, Some ( elem2) ] . into_iter ( ) . flatten ( ) {
656+ place = * self . projections . entry ( ( place, elem) ) . or_insert_with ( || {
657+ // Prepend new child to the linked list.
658+ let next = self . places . push ( PlaceInfo :: new ( Some ( elem) ) ) ;
659+ self . places [ next] . next_sibling = self . places [ place] . first_child ;
660+ self . places [ place] . first_child = Some ( next) ;
661+ next
662+ } ) ;
663+ }
664+
665+ // And push the eventual children places to the worklist.
666+ self . register_children ( tcx, place, ty, & filter, & mut worklist) ;
643667 }
644668 }
645669
646670 /// Potentially register the (local, projection) place and its fields, recursively.
647671 ///
648672 /// Invariant: The projection must only contain trackable elements.
649- fn register_with_filter_rec < ' tcx > (
673+ fn register_children < ' tcx > (
650674 & mut self ,
651675 tcx : TyCtxt < ' tcx > ,
652- local : Local ,
653- projection : & mut Vec < PlaceElem < ' tcx > > ,
676+ place : PlaceIndex ,
654677 ty : Ty < ' tcx > ,
655- filter : & mut impl FnMut ( Ty < ' tcx > ) -> bool ,
656- place_limit : Option < usize > ,
678+ filter : & impl Fn ( Ty < ' tcx > ) -> bool ,
679+ worklist : & mut VecDeque < ( PlaceIndex , Option < TrackElem > , TrackElem , Ty < ' tcx > ) > ,
657680 ) {
658- if let Some ( place_limit) = place_limit && self . value_count >= place_limit {
659- return
660- }
661-
662- // We know that the projection only contains trackable elements.
663- let place = self . make_place ( local, projection) . unwrap ( ) ;
664-
665681 // Allocate a value slot if it doesn't have one, and the user requested one.
666682 if self . places [ place] . value_index . is_none ( ) && filter ( ty) {
667683 self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
668684 self . value_count += 1 ;
669685 }
670686
687+ // For enums, directly create the `Discriminant`, as that's their main use.
671688 if ty. is_enum ( ) {
672689 let discr_ty = ty. discriminant_ty ( tcx) ;
673690 if filter ( discr_ty) {
@@ -692,48 +709,15 @@ impl Map {
692709
693710 // Recurse with all fields of this place.
694711 iter_fields ( ty, tcx, ty:: ParamEnv :: reveal_all ( ) , |variant, field, ty| {
695- if let Some ( variant) = variant {
696- projection. push ( PlaceElem :: Downcast ( None , variant) ) ;
697- let _ = self . make_place ( local, projection) ;
698- projection. push ( PlaceElem :: Field ( field, ty) ) ;
699- self . register_with_filter_rec ( tcx, local, projection, ty, filter, place_limit) ;
700- projection. pop ( ) ;
701- projection. pop ( ) ;
702- return ;
703- }
704- projection. push ( PlaceElem :: Field ( field, ty) ) ;
705- self . register_with_filter_rec ( tcx, local, projection, ty, filter, place_limit) ;
706- projection. pop ( ) ;
712+ worklist. push_back ( (
713+ place,
714+ variant. map ( TrackElem :: Variant ) ,
715+ TrackElem :: Field ( field) ,
716+ ty,
717+ ) )
707718 } ) ;
708719 }
709720
710- /// Tries to add the place to the map, without allocating a value slot.
711- ///
712- /// Can fail if the projection contains non-trackable elements.
713- fn make_place < ' tcx > (
714- & mut self ,
715- local : Local ,
716- projection : & [ PlaceElem < ' tcx > ] ,
717- ) -> Result < PlaceIndex , ( ) > {
718- // Get the base index of the local.
719- let mut index =
720- * self . locals . get_or_insert_with ( local, || self . places . push ( PlaceInfo :: new ( None ) ) ) ;
721-
722- // Apply the projection.
723- for & elem in projection {
724- let elem = elem. try_into ( ) ?;
725- index = * self . projections . entry ( ( index, elem) ) . or_insert_with ( || {
726- // Prepend new child to the linked list.
727- let next = self . places . push ( PlaceInfo :: new ( Some ( elem) ) ) ;
728- self . places [ next] . next_sibling = self . places [ index] . first_child ;
729- self . places [ index] . first_child = Some ( next) ;
730- next
731- } ) ;
732- }
733-
734- Ok ( index)
735- }
736-
737721 /// Returns the number of tracked places, i.e., those for which a value can be stored.
738722 pub fn tracked_places ( & self ) -> usize {
739723 self . value_count
@@ -750,7 +734,7 @@ impl Map {
750734 place : PlaceRef < ' _ > ,
751735 extra : impl IntoIterator < Item = TrackElem > ,
752736 ) -> Option < PlaceIndex > {
753- let mut index = * self . locals . get ( place. local ) ? . as_ref ( ) ?;
737+ let mut index = * self . locals [ place. local ] . as_ref ( ) ?;
754738
755739 for & elem in place. projection {
756740 index = self . apply ( index, elem. try_into ( ) . ok ( ) ?) ?;
@@ -794,7 +778,7 @@ impl Map {
794778 // We do not track indirect places.
795779 return ;
796780 }
797- let Some ( & Some ( mut index) ) = self . locals . get ( place. local ) else {
781+ let Some ( mut index) = self . locals [ place. local ] else {
798782 // The local is not tracked at all, so it does not alias anything.
799783 return ;
800784 } ;
0 commit comments