47
47
48
48
use std:: fmt:: { Debug , Formatter } ;
49
49
50
- use rustc_data_structures:: fx:: FxHashMap ;
50
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
51
51
use rustc_index:: vec:: IndexVec ;
52
52
use rustc_middle:: mir:: tcx:: PlaceTy ;
53
53
use rustc_middle:: mir:: visit:: { PlaceContext , Visitor } ;
@@ -405,12 +405,31 @@ rustc_index::newtype_index!(
405
405
) ;
406
406
407
407
/// See [`State`].
408
- #[ derive( PartialEq , Eq , Clone , Debug ) ]
408
+ #[ derive( PartialEq , Eq , Debug ) ]
409
409
enum StateData < V > {
410
410
Reachable ( IndexVec < ValueIndex , V > ) ,
411
411
Unreachable ,
412
412
}
413
413
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
+
414
433
/// The dataflow state for an instance of [`ValueAnalysis`].
415
434
///
416
435
/// Every instance specifies a lattice that represents the possible values of a single tracked
@@ -421,9 +440,19 @@ enum StateData<V> {
421
440
/// reachable state). All operations on unreachable states are ignored.
422
441
///
423
442
/// 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 ) ]
425
444
pub struct State < V > ( StateData < V > ) ;
426
445
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
+
427
456
impl < V : Clone + HasTop + HasBottom > State < V > {
428
457
pub fn is_reachable ( & self ) -> bool {
429
458
matches ! ( & self . 0 , StateData :: Reachable ( _) )
@@ -590,6 +619,7 @@ impl Map {
590
619
///
591
620
/// This is currently the only way to create a [`Map`]. The way in which the tracked places are
592
621
/// chosen is an implementation detail and may not be relied upon.
622
+ #[ instrument( skip_all, level = "debug" ) ]
593
623
pub fn from_filter < ' tcx > (
594
624
tcx : TyCtxt < ' tcx > ,
595
625
body : & Body < ' tcx > ,
@@ -604,11 +634,12 @@ impl Map {
604
634
if tcx. sess . opts . unstable_opts . unsound_mir_opts {
605
635
// We might want to add additional limitations. If a struct has 10 boxed fields of
606
636
// 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 ( ) ) ;
608
638
} else {
609
639
map. register_with_filter ( tcx, body, 0 , filter, & escaped_places ( body) ) ;
610
640
}
611
641
642
+ debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
612
643
map
613
644
}
614
645
@@ -619,7 +650,7 @@ impl Map {
619
650
body : & Body < ' tcx > ,
620
651
max_derefs : u32 ,
621
652
mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
622
- exclude : & [ Place < ' tcx > ] ,
653
+ exclude : & FxHashSet < Place < ' tcx > > ,
623
654
) {
624
655
// This is used to tell whether a type is `!Freeze`.
625
656
let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -648,10 +679,10 @@ impl Map {
648
679
ty : Ty < ' tcx > ,
649
680
filter : & mut impl FnMut ( Ty < ' tcx > ) -> bool ,
650
681
param_env : ty:: ParamEnv < ' tcx > ,
651
- exclude : & [ Place < ' tcx > ] ,
682
+ exclude : & FxHashSet < Place < ' tcx > > ,
652
683
) {
653
- // This currently does a linear scan, could be improved.
654
684
if exclude. contains ( & Place { local, projection : tcx. intern_place_elems ( projection) } ) {
685
+ // This will also exclude all projections of the excluded place.
655
686
return ;
656
687
}
657
688
@@ -764,6 +795,10 @@ impl Map {
764
795
Ok ( ( ) )
765
796
}
766
797
798
+ pub fn tracked_places ( & self ) -> usize {
799
+ self . value_count
800
+ }
801
+
767
802
pub fn apply ( & self , place : PlaceIndex , elem : TrackElem ) -> Option < PlaceIndex > {
768
803
self . projections . get ( & ( place, elem) ) . copied ( )
769
804
}
@@ -929,20 +964,20 @@ fn iter_fields<'tcx>(
929
964
/// Returns all places, that have their reference or address taken.
930
965
///
931
966
/// 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 > > {
933
968
struct Collector < ' tcx > {
934
- result : Vec < Place < ' tcx > > ,
969
+ result : FxHashSet < Place < ' tcx > > ,
935
970
}
936
971
937
972
impl < ' tcx > Visitor < ' tcx > for Collector < ' tcx > {
938
973
fn visit_place ( & mut self , place : & Place < ' tcx > , context : PlaceContext , _location : Location ) {
939
974
if context. is_borrow ( ) || context. is_address_of ( ) {
940
- self . result . push ( * place) ;
975
+ self . result . insert ( * place) ;
941
976
}
942
977
}
943
978
}
944
979
945
- let mut collector = Collector { result : Vec :: new ( ) } ;
980
+ let mut collector = Collector { result : FxHashSet :: default ( ) } ;
946
981
collector. visit_body ( body) ;
947
982
collector. result
948
983
}
0 commit comments