4747
4848use std:: fmt:: { Debug , Formatter } ;
4949
50- use rustc_data_structures:: fx:: FxHashMap ;
50+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
5151use rustc_index:: vec:: IndexVec ;
5252use rustc_middle:: mir:: tcx:: PlaceTy ;
5353use rustc_middle:: mir:: visit:: { PlaceContext , Visitor } ;
@@ -405,12 +405,31 @@ rustc_index::newtype_index!(
405405) ;
406406
407407/// See [`State`].
408- #[ derive( PartialEq , Eq , Clone , Debug ) ]
408+ #[ derive( PartialEq , Eq , Debug ) ]
409409enum StateData < V > {
410410 Reachable ( IndexVec < ValueIndex , V > ) ,
411411 Unreachable ,
412412}
413413
414+ impl < V : Clone > Clone for StateData < V > {
415+ fn clone ( & self ) -> Self {
416+ match self {
417+ Self :: Reachable ( x) => Self :: Reachable ( x. clone ( ) ) ,
418+ Self :: Unreachable => Self :: Unreachable ,
419+ }
420+ }
421+
422+ fn clone_from ( & mut self , source : & Self ) {
423+ match ( & mut * self , source) {
424+ ( Self :: Reachable ( x) , Self :: Reachable ( y) ) => {
425+ // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`.
426+ x. raw . clone_from ( & y. raw ) ;
427+ }
428+ _ => * self = source. clone ( ) ,
429+ }
430+ }
431+ }
432+
414433/// The dataflow state for an instance of [`ValueAnalysis`].
415434///
416435/// Every instance specifies a lattice that represents the possible values of a single tracked
@@ -421,9 +440,19 @@ enum StateData<V> {
421440/// reachable state). All operations on unreachable states are ignored.
422441///
423442/// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
424- #[ derive( PartialEq , Eq , Clone , Debug ) ]
443+ #[ derive( PartialEq , Eq , Debug ) ]
425444pub struct State < V > ( StateData < V > ) ;
426445
446+ impl < V : Clone > Clone for State < V > {
447+ fn clone ( & self ) -> Self {
448+ Self ( self . 0 . clone ( ) )
449+ }
450+
451+ fn clone_from ( & mut self , source : & Self ) {
452+ self . 0 . clone_from ( & source. 0 ) ;
453+ }
454+ }
455+
427456impl < V : Clone + HasTop + HasBottom > State < V > {
428457 pub fn is_reachable ( & self ) -> bool {
429458 matches ! ( & self . 0 , StateData :: Reachable ( _) )
@@ -590,6 +619,7 @@ impl Map {
590619 ///
591620 /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
592621 /// chosen is an implementation detail and may not be relied upon.
622+ #[ instrument( skip_all, level = "debug" ) ]
593623 pub fn from_filter < ' tcx > (
594624 tcx : TyCtxt < ' tcx > ,
595625 body : & Body < ' tcx > ,
@@ -604,11 +634,12 @@ impl Map {
604634 if tcx. sess . opts . unstable_opts . unsound_mir_opts {
605635 // We might want to add additional limitations. If a struct has 10 boxed fields of
606636 // itself, there will currently be `10.pow(max_derefs)` tracked places.
607- map. register_with_filter ( tcx, body, 2 , filter, & [ ] ) ;
637+ map. register_with_filter ( tcx, body, 2 , filter, & FxHashSet :: default ( ) ) ;
608638 } else {
609639 map. register_with_filter ( tcx, body, 0 , filter, & escaped_places ( body) ) ;
610640 }
611641
642+ debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
612643 map
613644 }
614645
@@ -619,7 +650,7 @@ impl Map {
619650 body : & Body < ' tcx > ,
620651 max_derefs : u32 ,
621652 mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
622- exclude : & [ Place < ' tcx > ] ,
653+ exclude : & FxHashSet < Place < ' tcx > > ,
623654 ) {
624655 // This is used to tell whether a type is `!Freeze`.
625656 let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -648,10 +679,10 @@ impl Map {
648679 ty : Ty < ' tcx > ,
649680 filter : & mut impl FnMut ( Ty < ' tcx > ) -> bool ,
650681 param_env : ty:: ParamEnv < ' tcx > ,
651- exclude : & [ Place < ' tcx > ] ,
682+ exclude : & FxHashSet < Place < ' tcx > > ,
652683 ) {
653- // This currently does a linear scan, could be improved.
654684 if exclude. contains ( & Place { local, projection : tcx. intern_place_elems ( projection) } ) {
685+ // This will also exclude all projections of the excluded place.
655686 return ;
656687 }
657688
@@ -764,6 +795,10 @@ impl Map {
764795 Ok ( ( ) )
765796 }
766797
798+ pub fn tracked_places ( & self ) -> usize {
799+ self . value_count
800+ }
801+
767802 pub fn apply ( & self , place : PlaceIndex , elem : TrackElem ) -> Option < PlaceIndex > {
768803 self . projections . get ( & ( place, elem) ) . copied ( )
769804 }
@@ -929,20 +964,20 @@ fn iter_fields<'tcx>(
929964/// Returns all places, that have their reference or address taken.
930965///
931966/// This includes shared references.
932- fn escaped_places < ' tcx > ( body : & Body < ' tcx > ) -> Vec < Place < ' tcx > > {
967+ fn escaped_places < ' tcx > ( body : & Body < ' tcx > ) -> FxHashSet < Place < ' tcx > > {
933968 struct Collector < ' tcx > {
934- result : Vec < Place < ' tcx > > ,
969+ result : FxHashSet < Place < ' tcx > > ,
935970 }
936971
937972 impl < ' tcx > Visitor < ' tcx > for Collector < ' tcx > {
938973 fn visit_place ( & mut self , place : & Place < ' tcx > , context : PlaceContext , _location : Location ) {
939974 if context. is_borrow ( ) || context. is_address_of ( ) {
940- self . result . push ( * place) ;
975+ self . result . insert ( * place) ;
941976 }
942977 }
943978 }
944979
945- let mut collector = Collector { result : Vec :: new ( ) } ;
980+ let mut collector = Collector { result : FxHashSet :: default ( ) } ;
946981 collector. visit_body ( body) ;
947982 collector. result
948983}
0 commit comments