@@ -36,7 +36,6 @@ use std::fmt::{Debug, Formatter};
3636
3737use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
3838use rustc_index:: vec:: IndexVec ;
39- use rustc_middle:: mir:: tcx:: PlaceTy ;
4039use rustc_middle:: mir:: visit:: { MutatingUseContext , PlaceContext , Visitor } ;
4140use rustc_middle:: mir:: * ;
4241use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
@@ -552,9 +551,10 @@ impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
552551 }
553552}
554553
555- /// A partial mapping from `Place` to `PlaceIndex`, where some place indices have value indices .
554+ /// Partial mapping from [ `Place`] to [ `PlaceIndex`] , where some places also have a [`ValueIndex`] .
556555///
557- /// Some additional bookkeeping is done to speed up traversal:
556+ /// This data structure essentially maintains a tree of places and their projections. Some
557+ /// additional bookkeeping is done, to speed up traversal over this tree:
558558/// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children.
559559/// - To directly get the child for a specific projection, there is a `projections` map.
560560#[ derive( Debug ) ]
@@ -578,7 +578,8 @@ impl Map {
578578 /// Returns a map that only tracks places whose type passes the filter.
579579 ///
580580 /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
581- /// chosen is an implementation detail and may not be relied upon.
581+ /// chosen is an implementation detail and may not be relied upon (other than that their type
582+ /// passes the filter).
582583 #[ instrument( skip_all, level = "debug" ) ]
583584 pub fn from_filter < ' tcx > (
584585 tcx : TyCtxt < ' tcx > ,
@@ -599,6 +600,7 @@ impl Map {
599600 mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
600601 exclude : & FxHashSet < Place < ' tcx > > ,
601602 ) {
603+ // We use this vector as stack, pushing and popping projections.
602604 let mut projection = Vec :: new ( ) ;
603605 for ( local, decl) in body. local_decls . iter_enumerated ( ) {
604606 self . register_with_filter_rec (
@@ -612,6 +614,9 @@ impl Map {
612614 }
613615 }
614616
617+ /// Register fields of the given (local, projection) place.
618+ ///
619+ /// Invariant: The projection must only contain fields.
615620 fn register_with_filter_rec < ' tcx > (
616621 & mut self ,
617622 tcx : TyCtxt < ' tcx > ,
@@ -626,10 +631,19 @@ impl Map {
626631 return ;
627632 }
628633
629- if filter ( ty) {
630- // This might fail if `ty` is not scalar.
631- let _ = self . register_with_ty ( local, projection, ty) ;
634+ // Note: The framework supports only scalars for now.
635+ if filter ( ty) && ty. is_scalar ( ) {
636+ // We know that the projection only contains trackable elements.
637+ let place = self . make_place ( local, projection) . unwrap ( ) ;
638+
639+ // Allocate a value slot if it doesn't have one.
640+ if self . places [ place] . value_index . is_none ( ) {
641+ self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
642+ self . value_count += 1 ;
643+ }
632644 }
645+
646+ // Recurse with all fields of this place.
633647 iter_fields ( ty, tcx, |variant, field, ty| {
634648 if variant. is_some ( ) {
635649 // Downcasts are currently not supported.
@@ -668,59 +682,17 @@ impl Map {
668682 Ok ( index)
669683 }
670684
671- #[ allow( unused) ]
672- fn register < ' tcx > (
673- & mut self ,
674- local : Local ,
675- projection : & [ PlaceElem < ' tcx > ] ,
676- decls : & impl HasLocalDecls < ' tcx > ,
677- tcx : TyCtxt < ' tcx > ,
678- ) -> Result < ( ) , ( ) > {
679- projection
680- . iter ( )
681- . fold ( PlaceTy :: from_ty ( decls. local_decls ( ) [ local] . ty ) , |place_ty, & elem| {
682- place_ty. projection_ty ( tcx, elem)
683- } ) ;
684-
685- let place_ty = Place :: ty_from ( local, projection, decls, tcx) ;
686- if place_ty. variant_index . is_some ( ) {
687- return Err ( ( ) ) ;
688- }
689- self . register_with_ty ( local, projection, place_ty. ty )
690- }
691-
692- /// Tries to track the given place. Fails if type is non-scalar or projection is not trackable.
693- fn register_with_ty < ' tcx > (
694- & mut self ,
695- local : Local ,
696- projection : & [ PlaceElem < ' tcx > ] ,
697- ty : Ty < ' tcx > ,
698- ) -> Result < ( ) , ( ) > {
699- if !ty. is_scalar ( ) {
700- // Currently, only scalar types are allowed, because they are atomic
701- // and therefore do not require invalidation of parent places.
702- return Err ( ( ) ) ;
703- }
704-
705- let place = self . make_place ( local, projection) ?;
706-
707- // Allocate a value slot if it doesn't have one.
708- if self . places [ place] . value_index . is_none ( ) {
709- self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
710- self . value_count += 1 ;
711- }
712-
713- Ok ( ( ) )
714- }
715-
685+ /// Returns the number of tracked places, i.e., those for which a value can be stored.
716686 pub fn tracked_places ( & self ) -> usize {
717687 self . value_count
718688 }
719689
690+ /// Applies a single projection element, yielding the corresponding child.
720691 pub fn apply ( & self , place : PlaceIndex , elem : TrackElem ) -> Option < PlaceIndex > {
721692 self . projections . get ( & ( place, elem) ) . copied ( )
722693 }
723694
695+ /// Locates the given place, if it exists in the tree.
724696 pub fn find ( & self , place : PlaceRef < ' _ > ) -> Option < PlaceIndex > {
725697 let mut index = * self . locals . get ( place. local ) ?. as_ref ( ) ?;
726698
@@ -736,6 +708,7 @@ impl Map {
736708 Children :: new ( self , parent)
737709 }
738710
711+ /// Invoke a function on the given place and all descendants.
739712 pub fn preorder_invoke ( & self , root : PlaceIndex , f : & mut impl FnMut ( PlaceIndex ) ) {
740713 f ( root) ;
741714 for child in self . children ( root) {
0 commit comments