@@ -581,6 +581,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
581
581
}
582
582
}
583
583
584
+ /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
585
+ pub fn get_len ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V {
586
+ match map. find_len ( place) {
587
+ Some ( place) => self . get_idx ( place, map) ,
588
+ None => V :: TOP ,
589
+ }
590
+ }
591
+
584
592
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
585
593
pub fn get_idx ( & self , place : PlaceIndex , map : & Map ) -> V {
586
594
match & self . 0 {
@@ -626,45 +634,36 @@ pub struct Map {
626
634
}
627
635
628
636
impl Map {
629
- fn new ( ) -> Self {
630
- Self {
637
+ /// Returns a map that only tracks places whose type has scalar layout.
638
+ ///
639
+ /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
640
+ /// chosen is an implementation detail and may not be relied upon (other than that their type
641
+ /// are scalars).
642
+ pub fn new < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > , value_limit : Option < usize > ) -> Self {
643
+ let mut map = Self {
631
644
locals : IndexVec :: new ( ) ,
632
645
projections : FxHashMap :: default ( ) ,
633
646
places : IndexVec :: new ( ) ,
634
647
value_count : 0 ,
635
648
inner_values : IndexVec :: new ( ) ,
636
649
inner_values_buffer : Vec :: new ( ) ,
637
- }
638
- }
639
-
640
- /// Returns a map that only tracks places whose type passes the filter.
641
- ///
642
- /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
643
- /// chosen is an implementation detail and may not be relied upon (other than that their type
644
- /// passes the filter).
645
- pub fn from_filter < ' tcx > (
646
- tcx : TyCtxt < ' tcx > ,
647
- body : & Body < ' tcx > ,
648
- filter : impl Fn ( Ty < ' tcx > ) -> bool ,
649
- value_limit : Option < usize > ,
650
- ) -> Self {
651
- let mut map = Self :: new ( ) ;
650
+ } ;
652
651
let exclude = excluded_locals ( body) ;
653
- map. register_with_filter ( tcx, body, filter , exclude, value_limit) ;
652
+ map. register ( tcx, body, exclude, value_limit) ;
654
653
debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
655
654
map
656
655
}
657
656
658
- /// Register all non-excluded places that pass the filter .
659
- fn register_with_filter < ' tcx > (
657
+ /// Register all non-excluded places that have scalar layout .
658
+ fn register < ' tcx > (
660
659
& mut self ,
661
660
tcx : TyCtxt < ' tcx > ,
662
661
body : & Body < ' tcx > ,
663
- filter : impl Fn ( Ty < ' tcx > ) -> bool ,
664
662
exclude : BitSet < Local > ,
665
663
value_limit : Option < usize > ,
666
664
) {
667
665
let mut worklist = VecDeque :: with_capacity ( value_limit. unwrap_or ( body. local_decls . len ( ) ) ) ;
666
+ let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
668
667
669
668
// Start by constructing the places for each bare local.
670
669
self . locals = IndexVec :: from_elem ( None , & body. local_decls ) ;
@@ -679,7 +678,7 @@ impl Map {
679
678
self . locals [ local] = Some ( place) ;
680
679
681
680
// And push the eventual children places to the worklist.
682
- self . register_children ( tcx, place, decl. ty , & filter , & mut worklist) ;
681
+ self . register_children ( tcx, param_env , place, decl. ty , & mut worklist) ;
683
682
}
684
683
685
684
// `place.elem1.elem2` with type `ty`.
@@ -702,7 +701,7 @@ impl Map {
702
701
}
703
702
704
703
// And push the eventual children places to the worklist.
705
- self . register_children ( tcx, place , ty , & filter , & mut worklist) ;
704
+ self . register_children ( tcx, param_env , place , ty , & mut worklist) ;
706
705
}
707
706
708
707
// Pre-compute the tree of ValueIndex nested in each PlaceIndex.
@@ -732,42 +731,52 @@ impl Map {
732
731
fn register_children < ' tcx > (
733
732
& mut self ,
734
733
tcx : TyCtxt < ' tcx > ,
734
+ param_env : ty:: ParamEnv < ' tcx > ,
735
735
place : PlaceIndex ,
736
736
ty : Ty < ' tcx > ,
737
- filter : & impl Fn ( Ty < ' tcx > ) -> bool ,
738
737
worklist : & mut VecDeque < ( PlaceIndex , Option < TrackElem > , TrackElem , Ty < ' tcx > ) > ,
739
738
) {
740
739
// Allocate a value slot if it doesn't have one, and the user requested one.
741
- if self . places [ place] . value_index . is_none ( ) && filter ( ty) {
740
+ assert ! ( self . places[ place] . value_index. is_none( ) ) ;
741
+ if tcx. layout_of ( param_env. and ( ty) ) . map_or ( false , |layout| layout. abi . is_scalar ( ) ) {
742
742
self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
743
743
self . value_count += 1 ;
744
744
}
745
745
746
746
// For enums, directly create the `Discriminant`, as that's their main use.
747
747
if ty. is_enum ( ) {
748
- let discr_ty = ty. discriminant_ty ( tcx) ;
749
- if filter ( discr_ty) {
750
- let discr = * self
751
- . projections
752
- . entry ( ( place, TrackElem :: Discriminant ) )
753
- . or_insert_with ( || {
754
- // Prepend new child to the linked list.
755
- let next = self . places . push ( PlaceInfo :: new ( Some ( TrackElem :: Discriminant ) ) ) ;
756
- self . places [ next] . next_sibling = self . places [ place] . first_child ;
757
- self . places [ place] . first_child = Some ( next) ;
758
- next
759
- } ) ;
760
-
761
- // Allocate a value slot if it doesn't have one.
762
- if self . places [ discr] . value_index . is_none ( ) {
763
- self . places [ discr] . value_index = Some ( self . value_count . into ( ) ) ;
764
- self . value_count += 1 ;
765
- }
766
- }
748
+ // Prepend new child to the linked list.
749
+ let discr = self . places . push ( PlaceInfo :: new ( Some ( TrackElem :: Discriminant ) ) ) ;
750
+ self . places [ discr] . next_sibling = self . places [ place] . first_child ;
751
+ self . places [ place] . first_child = Some ( discr) ;
752
+ let old = self . projections . insert ( ( place, TrackElem :: Discriminant ) , discr) ;
753
+ assert ! ( old. is_none( ) ) ;
754
+
755
+ // Allocate a value slot since it doesn't have one.
756
+ assert ! ( self . places[ discr] . value_index. is_none( ) ) ;
757
+ self . places [ discr] . value_index = Some ( self . value_count . into ( ) ) ;
758
+ self . value_count += 1 ;
759
+ }
760
+
761
+ if let Some ( ref_ty) = ty. builtin_deref ( true ) && let ty:: Slice ( ..) = ref_ty. ty . kind ( ) {
762
+ assert ! ( self . places[ place] . value_index. is_none( ) , "slices are not scalars" ) ;
763
+
764
+ // Prepend new child to the linked list.
765
+ let len = self . places . push ( PlaceInfo :: new ( Some ( TrackElem :: DerefLen ) ) ) ;
766
+ self . places [ len] . next_sibling = self . places [ place] . first_child ;
767
+ self . places [ place] . first_child = Some ( len) ;
768
+
769
+ let old = self . projections . insert ( ( place, TrackElem :: DerefLen ) , len) ;
770
+ assert ! ( old. is_none( ) ) ;
771
+
772
+ // Allocate a value slot since it doesn't have one.
773
+ assert ! ( self . places[ len] . value_index. is_none( ) ) ;
774
+ self . places [ len] . value_index = Some ( self . value_count . into ( ) ) ;
775
+ self . value_count += 1 ;
767
776
}
768
777
769
778
// Recurse with all fields of this place.
770
- iter_fields ( ty, tcx, ty :: ParamEnv :: reveal_all ( ) , |variant, field, ty| {
779
+ iter_fields ( ty, tcx, param_env , |variant, field, ty| {
771
780
worklist. push_back ( (
772
781
place,
773
782
variant. map ( TrackElem :: Variant ) ,
@@ -834,6 +843,11 @@ impl Map {
834
843
self . find_extra ( place, [ TrackElem :: Discriminant ] )
835
844
}
836
845
846
+ /// Locates the given place and applies `DerefLen`, if it exists in the tree.
847
+ pub fn find_len ( & self , place : PlaceRef < ' _ > ) -> Option < PlaceIndex > {
848
+ self . find_extra ( place, [ TrackElem :: DerefLen ] )
849
+ }
850
+
837
851
/// Iterate over all direct children.
838
852
pub fn children ( & self , parent : PlaceIndex ) -> impl Iterator < Item = PlaceIndex > + ' _ {
839
853
Children :: new ( self , parent)
@@ -985,6 +999,8 @@ pub enum TrackElem {
985
999
Field ( FieldIdx ) ,
986
1000
Variant ( VariantIdx ) ,
987
1001
Discriminant ,
1002
+ // Length of a slice.
1003
+ DerefLen ,
988
1004
}
989
1005
990
1006
impl < V , T > TryFrom < ProjectionElem < V , T > > for TrackElem {
@@ -1124,6 +1140,9 @@ fn debug_with_context_rec<V: Debug + Eq>(
1124
1140
format ! ( "{}.{}" , place_str, field. index( ) )
1125
1141
}
1126
1142
}
1143
+ TrackElem :: DerefLen => {
1144
+ format ! ( "Len(*{})" , place_str)
1145
+ }
1127
1146
} ;
1128
1147
debug_with_context_rec ( child, & child_place_str, new, old, map, f) ?;
1129
1148
}
0 commit comments