@@ -36,7 +36,6 @@ use std::fmt::{Debug, Formatter};
36
36
37
37
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
38
38
use rustc_index:: vec:: IndexVec ;
39
- use rustc_middle:: mir:: tcx:: PlaceTy ;
40
39
use rustc_middle:: mir:: visit:: { MutatingUseContext , PlaceContext , Visitor } ;
41
40
use rustc_middle:: mir:: * ;
42
41
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
@@ -552,9 +551,10 @@ impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
552
551
}
553
552
}
554
553
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`] .
556
555
///
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:
558
558
/// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children.
559
559
/// - To directly get the child for a specific projection, there is a `projections` map.
560
560
#[ derive( Debug ) ]
@@ -578,7 +578,8 @@ impl Map {
578
578
/// Returns a map that only tracks places whose type passes the filter.
579
579
///
580
580
/// 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).
582
583
#[ instrument( skip_all, level = "debug" ) ]
583
584
pub fn from_filter < ' tcx > (
584
585
tcx : TyCtxt < ' tcx > ,
@@ -599,6 +600,7 @@ impl Map {
599
600
mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
600
601
exclude : & FxHashSet < Place < ' tcx > > ,
601
602
) {
603
+ // We use this vector as stack, pushing and popping projections.
602
604
let mut projection = Vec :: new ( ) ;
603
605
for ( local, decl) in body. local_decls . iter_enumerated ( ) {
604
606
self . register_with_filter_rec (
@@ -612,6 +614,9 @@ impl Map {
612
614
}
613
615
}
614
616
617
+ /// Register fields of the given (local, projection) place.
618
+ ///
619
+ /// Invariant: The projection must only contain fields.
615
620
fn register_with_filter_rec < ' tcx > (
616
621
& mut self ,
617
622
tcx : TyCtxt < ' tcx > ,
@@ -626,10 +631,19 @@ impl Map {
626
631
return ;
627
632
}
628
633
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
+ }
632
644
}
645
+
646
+ // Recurse with all fields of this place.
633
647
iter_fields ( ty, tcx, |variant, field, ty| {
634
648
if variant. is_some ( ) {
635
649
// Downcasts are currently not supported.
@@ -668,59 +682,17 @@ impl Map {
668
682
Ok ( index)
669
683
}
670
684
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.
716
686
pub fn tracked_places ( & self ) -> usize {
717
687
self . value_count
718
688
}
719
689
690
+ /// Applies a single projection element, yielding the corresponding child.
720
691
pub fn apply ( & self , place : PlaceIndex , elem : TrackElem ) -> Option < PlaceIndex > {
721
692
self . projections . get ( & ( place, elem) ) . copied ( )
722
693
}
723
694
695
+ /// Locates the given place, if it exists in the tree.
724
696
pub fn find ( & self , place : PlaceRef < ' _ > ) -> Option < PlaceIndex > {
725
697
let mut index = * self . locals . get ( place. local ) ?. as_ref ( ) ?;
726
698
@@ -736,6 +708,7 @@ impl Map {
736
708
Children :: new ( self , parent)
737
709
}
738
710
711
+ /// Invoke a function on the given place and all descendants.
739
712
pub fn preorder_invoke ( & self , root : PlaceIndex , f : & mut impl FnMut ( PlaceIndex ) ) {
740
713
f ( root) ;
741
714
for child in self . children ( root) {
0 commit comments