@@ -463,7 +463,19 @@ impl<V: Clone> Clone for State<V> {
463
463
}
464
464
}
465
465
466
- impl < V : Clone + HasTop + HasBottom > State < V > {
466
+ impl < V : Clone > State < V > {
467
+ pub fn new ( init : V , map : & Map ) -> State < V > {
468
+ let values = IndexVec :: from_elem_n ( init, map. value_count ) ;
469
+ State ( StateData :: Reachable ( values) )
470
+ }
471
+
472
+ pub fn all ( & self , f : impl Fn ( & V ) -> bool ) -> bool {
473
+ match self . 0 {
474
+ StateData :: Unreachable => true ,
475
+ StateData :: Reachable ( ref values) => values. iter ( ) . all ( f) ,
476
+ }
477
+ }
478
+
467
479
pub fn is_reachable ( & self ) -> bool {
468
480
matches ! ( & self . 0 , StateData :: Reachable ( _) )
469
481
}
@@ -472,7 +484,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
472
484
self . 0 = StateData :: Unreachable ;
473
485
}
474
486
475
- pub fn flood_all ( & mut self ) {
487
+ pub fn flood_all ( & mut self )
488
+ where
489
+ V : HasTop ,
490
+ {
476
491
self . flood_all_with ( V :: TOP )
477
492
}
478
493
@@ -481,28 +496,52 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
481
496
values. raw . fill ( value) ;
482
497
}
483
498
499
+ /// Assign `value` to all places that are contained in `place` or may alias one.
484
500
pub fn flood_with ( & mut self , place : PlaceRef < ' _ > , map : & Map , value : V ) {
485
- let StateData :: Reachable ( values) = & mut self . 0 else { return } ;
486
- map. for_each_aliasing_place ( place, None , & mut |vi| {
487
- values[ vi] = value. clone ( ) ;
488
- } ) ;
501
+ self . flood_with_tail_elem ( place, None , map, value)
489
502
}
490
503
491
- pub fn flood ( & mut self , place : PlaceRef < ' _ > , map : & Map ) {
504
+ /// Assign `TOP` to all places that are contained in `place` or may alias one.
505
+ pub fn flood ( & mut self , place : PlaceRef < ' _ > , map : & Map )
506
+ where
507
+ V : HasTop ,
508
+ {
492
509
self . flood_with ( place, map, V :: TOP )
493
510
}
494
511
512
+ /// Assign `value` to the discriminant of `place` and all places that may alias it.
495
513
pub fn flood_discr_with ( & mut self , place : PlaceRef < ' _ > , map : & Map , value : V ) {
496
- let StateData :: Reachable ( values) = & mut self . 0 else { return } ;
497
- map. for_each_aliasing_place ( place, Some ( TrackElem :: Discriminant ) , & mut |vi| {
498
- values[ vi] = value. clone ( ) ;
499
- } ) ;
514
+ self . flood_with_tail_elem ( place, Some ( TrackElem :: Discriminant ) , map, value)
500
515
}
501
516
502
- pub fn flood_discr ( & mut self , place : PlaceRef < ' _ > , map : & Map ) {
517
+ /// Assign `TOP` to the discriminant of `place` and all places that may alias it.
518
+ pub fn flood_discr ( & mut self , place : PlaceRef < ' _ > , map : & Map )
519
+ where
520
+ V : HasTop ,
521
+ {
503
522
self . flood_discr_with ( place, map, V :: TOP )
504
523
}
505
524
525
+ /// This method is the most general version of the `flood_*` method.
526
+ ///
527
+ /// Assign `value` on the given place and all places that may alias it. In particular, when
528
+ /// the given place has a variant downcast, we invoke the function on all the other variants.
529
+ ///
530
+ /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
531
+ /// as such.
532
+ pub fn flood_with_tail_elem (
533
+ & mut self ,
534
+ place : PlaceRef < ' _ > ,
535
+ tail_elem : Option < TrackElem > ,
536
+ map : & Map ,
537
+ value : V ,
538
+ ) {
539
+ let StateData :: Reachable ( values) = & mut self . 0 else { return } ;
540
+ map. for_each_aliasing_place ( place, tail_elem, & mut |vi| {
541
+ values[ vi] = value. clone ( ) ;
542
+ } ) ;
543
+ }
544
+
506
545
/// Low-level method that assigns to a place.
507
546
/// This does nothing if the place is not tracked.
508
547
///
@@ -553,44 +592,104 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
553
592
}
554
593
555
594
/// Helper method to interpret `target = result`.
556
- pub fn assign ( & mut self , target : PlaceRef < ' _ > , result : ValueOrPlace < V > , map : & Map ) {
595
+ pub fn assign ( & mut self , target : PlaceRef < ' _ > , result : ValueOrPlace < V > , map : & Map )
596
+ where
597
+ V : HasTop ,
598
+ {
557
599
self . flood ( target, map) ;
558
600
if let Some ( target) = map. find ( target) {
559
601
self . insert_idx ( target, result, map) ;
560
602
}
561
603
}
562
604
563
605
/// Helper method for assignments to a discriminant.
564
- pub fn assign_discr ( & mut self , target : PlaceRef < ' _ > , result : ValueOrPlace < V > , map : & Map ) {
606
+ pub fn assign_discr ( & mut self , target : PlaceRef < ' _ > , result : ValueOrPlace < V > , map : & Map )
607
+ where
608
+ V : HasTop ,
609
+ {
565
610
self . flood_discr ( target, map) ;
566
611
if let Some ( target) = map. find_discr ( target) {
567
612
self . insert_idx ( target, result, map) ;
568
613
}
569
614
}
570
615
616
+ /// Retrieve the value stored for a place, or `None` if it is not tracked.
617
+ pub fn try_get ( & self , place : PlaceRef < ' _ > , map : & Map ) -> Option < V > {
618
+ let place = map. find ( place) ?;
619
+ self . try_get_idx ( place, map)
620
+ }
621
+
622
+ /// Retrieve the discriminant stored for a place, or `None` if it is not tracked.
623
+ pub fn try_get_discr ( & self , place : PlaceRef < ' _ > , map : & Map ) -> Option < V > {
624
+ let place = map. find_discr ( place) ?;
625
+ self . try_get_idx ( place, map)
626
+ }
627
+
628
+ /// Retrieve the slice length stored for a place, or `None` if it is not tracked.
629
+ pub fn try_get_len ( & self , place : PlaceRef < ' _ > , map : & Map ) -> Option < V > {
630
+ let place = map. find_len ( place) ?;
631
+ self . try_get_idx ( place, map)
632
+ }
633
+
634
+ /// Retrieve the value stored for a place index, or `None` if it is not tracked.
635
+ pub fn try_get_idx ( & self , place : PlaceIndex , map : & Map ) -> Option < V > {
636
+ match & self . 0 {
637
+ StateData :: Reachable ( values) => {
638
+ map. places [ place] . value_index . map ( |v| values[ v] . clone ( ) )
639
+ }
640
+ StateData :: Unreachable => None ,
641
+ }
642
+ }
643
+
571
644
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
572
- pub fn get ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V {
573
- map. find ( place) . map ( |place| self . get_idx ( place, map) ) . unwrap_or ( V :: TOP )
645
+ ///
646
+ /// This method returns ⊥ if the place is tracked and the state is unreachable.
647
+ pub fn get ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V
648
+ where
649
+ V : HasBottom + HasTop ,
650
+ {
651
+ match & self . 0 {
652
+ StateData :: Reachable ( _) => self . try_get ( place, map) . unwrap_or ( V :: TOP ) ,
653
+ // Because this is unreachable, we can return any value we want.
654
+ StateData :: Unreachable => V :: BOTTOM ,
655
+ }
574
656
}
575
657
576
658
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
577
- pub fn get_discr ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V {
578
- match map. find_discr ( place) {
579
- Some ( place) => self . get_idx ( place, map) ,
580
- None => V :: TOP ,
659
+ ///
660
+ /// This method returns ⊥ the current state is unreachable.
661
+ pub fn get_discr ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V
662
+ where
663
+ V : HasBottom + HasTop ,
664
+ {
665
+ match & self . 0 {
666
+ StateData :: Reachable ( _) => self . try_get_discr ( place, map) . unwrap_or ( V :: TOP ) ,
667
+ // Because this is unreachable, we can return any value we want.
668
+ StateData :: Unreachable => V :: BOTTOM ,
581
669
}
582
670
}
583
671
584
672
/// 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 ,
673
+ ///
674
+ /// This method returns ⊥ the current state is unreachable.
675
+ pub fn get_len ( & self , place : PlaceRef < ' _ > , map : & Map ) -> V
676
+ where
677
+ V : HasBottom + HasTop ,
678
+ {
679
+ match & self . 0 {
680
+ StateData :: Reachable ( _) => self . try_get_len ( place, map) . unwrap_or ( V :: TOP ) ,
681
+ // Because this is unreachable, we can return any value we want.
682
+ StateData :: Unreachable => V :: BOTTOM ,
589
683
}
590
684
}
591
685
592
686
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
593
- pub fn get_idx ( & self , place : PlaceIndex , map : & Map ) -> V {
687
+ ///
688
+ /// This method returns ⊥ the current state is unreachable.
689
+ pub fn get_idx ( & self , place : PlaceIndex , map : & Map ) -> V
690
+ where
691
+ V : HasBottom + HasTop ,
692
+ {
594
693
match & self . 0 {
595
694
StateData :: Reachable ( values) => {
596
695
map. places [ place] . value_index . map ( |v| values[ v] . clone ( ) ) . unwrap_or ( V :: TOP )
0 commit comments