@@ -581,6 +581,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
581581 }
582582 }
583583
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+
584592 /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
585593 pub fn get_idx ( & self , place : PlaceIndex , map : & Map ) -> V {
586594 match & self . 0 {
@@ -626,45 +634,36 @@ pub struct Map {
626634}
627635
628636impl 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 {
631644 locals : IndexVec :: new ( ) ,
632645 projections : FxHashMap :: default ( ) ,
633646 places : IndexVec :: new ( ) ,
634647 value_count : 0 ,
635648 inner_values : IndexVec :: new ( ) ,
636649 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+ } ;
652651 let exclude = excluded_locals ( body) ;
653- map. register_with_filter ( tcx, body, filter , exclude, value_limit) ;
652+ map. register ( tcx, body, exclude, value_limit) ;
654653 debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
655654 map
656655 }
657656
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 > (
660659 & mut self ,
661660 tcx : TyCtxt < ' tcx > ,
662661 body : & Body < ' tcx > ,
663- filter : impl Fn ( Ty < ' tcx > ) -> bool ,
664662 exclude : BitSet < Local > ,
665663 value_limit : Option < usize > ,
666664 ) {
667665 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 ( ) ) ;
668667
669668 // Start by constructing the places for each bare local.
670669 self . locals = IndexVec :: from_elem ( None , & body. local_decls ) ;
@@ -679,7 +678,7 @@ impl Map {
679678 self . locals [ local] = Some ( place) ;
680679
681680 // 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) ;
683682 }
684683
685684 // `place.elem1.elem2` with type `ty`.
@@ -702,7 +701,7 @@ impl Map {
702701 }
703702
704703 // 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) ;
706705 }
707706
708707 // Pre-compute the tree of ValueIndex nested in each PlaceIndex.
@@ -732,42 +731,52 @@ impl Map {
732731 fn register_children < ' tcx > (
733732 & mut self ,
734733 tcx : TyCtxt < ' tcx > ,
734+ param_env : ty:: ParamEnv < ' tcx > ,
735735 place : PlaceIndex ,
736736 ty : Ty < ' tcx > ,
737- filter : & impl Fn ( Ty < ' tcx > ) -> bool ,
738737 worklist : & mut VecDeque < ( PlaceIndex , Option < TrackElem > , TrackElem , Ty < ' tcx > ) > ,
739738 ) {
740739 // 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 ( ) ) {
742742 self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
743743 self . value_count += 1 ;
744744 }
745745
746746 // For enums, directly create the `Discriminant`, as that's their main use.
747747 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 ;
767776 }
768777
769778 // 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| {
771780 worklist. push_back ( (
772781 place,
773782 variant. map ( TrackElem :: Variant ) ,
@@ -834,6 +843,11 @@ impl Map {
834843 self . find_extra ( place, [ TrackElem :: Discriminant ] )
835844 }
836845
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+
837851 /// Iterate over all direct children.
838852 pub fn children ( & self , parent : PlaceIndex ) -> impl Iterator < Item = PlaceIndex > + ' _ {
839853 Children :: new ( self , parent)
@@ -985,6 +999,8 @@ pub enum TrackElem {
985999 Field ( FieldIdx ) ,
9861000 Variant ( VariantIdx ) ,
9871001 Discriminant ,
1002+ // Length of a slice.
1003+ DerefLen ,
9881004}
9891005
9901006impl < V , T > TryFrom < ProjectionElem < V , T > > for TrackElem {
@@ -1124,6 +1140,9 @@ fn debug_with_context_rec<V: Debug + Eq>(
11241140 format ! ( "{}.{}" , place_str, field. index( ) )
11251141 }
11261142 }
1143+ TrackElem :: DerefLen => {
1144+ format ! ( "Len(*{})" , place_str)
1145+ }
11271146 } ;
11281147 debug_with_context_rec ( child, & child_place_str, new, old, map, f) ?;
11291148 }
0 commit comments