@@ -150,7 +150,7 @@ macro_rules! make_mir_visitor {
150
150
151
151
fn visit_lvalue( & mut self ,
152
152
lvalue: & $( $mutability) * Lvalue <' tcx>,
153
- context: LvalueContext ,
153
+ context: LvalueContext < ' tcx> ,
154
154
location: Location ) {
155
155
self . super_lvalue( lvalue, context, location) ;
156
156
}
@@ -346,6 +346,7 @@ macro_rules! make_mir_visitor {
346
346
StatementKind :: StorageDead ( ref $( $mutability) * lvalue) => {
347
347
self . visit_lvalue( lvalue, LvalueContext :: StorageDead , location) ;
348
348
}
349
+ StatementKind :: Nop => { }
349
350
}
350
351
}
351
352
@@ -580,7 +581,7 @@ macro_rules! make_mir_visitor {
580
581
581
582
fn super_lvalue( & mut self ,
582
583
lvalue: & $( $mutability) * Lvalue <' tcx>,
583
- context: LvalueContext ,
584
+ context: LvalueContext < ' tcx> ,
584
585
location: Location ) {
585
586
match * lvalue {
586
587
Lvalue :: Var ( _) |
@@ -605,7 +606,12 @@ macro_rules! make_mir_visitor {
605
606
ref $( $mutability) * base,
606
607
ref $( $mutability) * elem,
607
608
} = * proj;
608
- self . visit_lvalue( base, LvalueContext :: Projection , location) ;
609
+ let context = if context. is_mutating_use( ) {
610
+ LvalueContext :: Projection ( Mutability :: Mut )
611
+ } else {
612
+ LvalueContext :: Projection ( Mutability :: Not )
613
+ } ;
614
+ self . visit_lvalue( base, context, location) ;
609
615
self . visit_projection_elem( elem, context, location) ;
610
616
}
611
617
@@ -750,6 +756,21 @@ macro_rules! make_mir_visitor {
750
756
751
757
fn super_const_usize( & mut self , _substs: & $( $mutability) * ConstUsize ) {
752
758
}
759
+
760
+ // Convenience methods
761
+
762
+ fn visit_location( & mut self , mir: & $( $mutability) * Mir <' tcx>, location: Location ) {
763
+ let basic_block = & $( $mutability) * mir[ location. block] ;
764
+ if basic_block. statements. len( ) == location. statement_index {
765
+ if let Some ( ref $( $mutability) * terminator) = basic_block. terminator {
766
+ self . visit_terminator( location. block, terminator, location)
767
+ }
768
+ } else {
769
+ let statement = & $( $mutability) *
770
+ basic_block. statements[ location. statement_index] ;
771
+ self . visit_statement( location. block, statement, location)
772
+ }
773
+ }
753
774
}
754
775
}
755
776
}
@@ -774,8 +795,20 @@ pub enum LvalueContext<'tcx> {
774
795
// Being borrowed
775
796
Borrow { region : & ' tcx Region , kind : BorrowKind } ,
776
797
777
- // Used as base for another lvalue, e.g. `x` in `x.y`
778
- Projection ,
798
+ // Used as base for another lvalue, e.g. `x` in `x.y`.
799
+ //
800
+ // The `Mutability` argument specifies whether the projection is being performed in order to
801
+ // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation
802
+ // in these cases:
803
+ //
804
+ // x.y = ...;
805
+ // f(&mut x.y);
806
+ //
807
+ // But not in these cases:
808
+ //
809
+ // z = x.y;
810
+ // f(&x.y);
811
+ Projection ( Mutability ) ,
779
812
780
813
// Consumed as part of an operand
781
814
Consume ,
@@ -784,3 +817,69 @@ pub enum LvalueContext<'tcx> {
784
817
StorageLive ,
785
818
StorageDead ,
786
819
}
820
+
821
+ impl < ' tcx > LvalueContext < ' tcx > {
822
+ /// Returns true if this lvalue context represents a drop.
823
+ pub fn is_drop ( & self ) -> bool {
824
+ match * self {
825
+ LvalueContext :: Drop => true ,
826
+ _ => false ,
827
+ }
828
+ }
829
+
830
+ /// Returns true if this lvalue context represents a storage live or storage dead marker.
831
+ pub fn is_storage_marker ( & self ) -> bool {
832
+ match * self {
833
+ LvalueContext :: StorageLive | LvalueContext :: StorageDead => true ,
834
+ _ => false ,
835
+ }
836
+ }
837
+
838
+ /// Returns true if this lvalue context represents a storage live marker.
839
+ pub fn is_storage_live_marker ( & self ) -> bool {
840
+ match * self {
841
+ LvalueContext :: StorageLive => true ,
842
+ _ => false ,
843
+ }
844
+ }
845
+
846
+ /// Returns true if this lvalue context represents a storage dead marker.
847
+ pub fn is_storage_dead_marker ( & self ) -> bool {
848
+ match * self {
849
+ LvalueContext :: StorageDead => true ,
850
+ _ => false ,
851
+ }
852
+ }
853
+
854
+ /// Returns true if this lvalue context represents a use that potentially changes the value.
855
+ pub fn is_mutating_use ( & self ) -> bool {
856
+ match * self {
857
+ LvalueContext :: Store | LvalueContext :: Call |
858
+ LvalueContext :: Borrow { kind : BorrowKind :: Mut , .. } |
859
+ LvalueContext :: Projection ( Mutability :: Mut ) |
860
+ LvalueContext :: Drop => true ,
861
+ LvalueContext :: Inspect |
862
+ LvalueContext :: Borrow { kind : BorrowKind :: Shared , .. } |
863
+ LvalueContext :: Borrow { kind : BorrowKind :: Unique , .. } |
864
+ LvalueContext :: Projection ( Mutability :: Not ) | LvalueContext :: Consume |
865
+ LvalueContext :: StorageLive | LvalueContext :: StorageDead => false ,
866
+ }
867
+ }
868
+
869
+ /// Returns true if this lvalue context represents a use that does not change the value.
870
+ pub fn is_nonmutating_use ( & self ) -> bool {
871
+ match * self {
872
+ LvalueContext :: Inspect | LvalueContext :: Borrow { kind : BorrowKind :: Shared , .. } |
873
+ LvalueContext :: Borrow { kind : BorrowKind :: Unique , .. } |
874
+ LvalueContext :: Projection ( Mutability :: Not ) | LvalueContext :: Consume => true ,
875
+ LvalueContext :: Borrow { kind : BorrowKind :: Mut , .. } | LvalueContext :: Store |
876
+ LvalueContext :: Call | LvalueContext :: Projection ( Mutability :: Mut ) |
877
+ LvalueContext :: Drop | LvalueContext :: StorageLive | LvalueContext :: StorageDead => false ,
878
+ }
879
+ }
880
+
881
+ pub fn is_use ( & self ) -> bool {
882
+ self . is_mutating_use ( ) || self . is_nonmutating_use ( )
883
+ }
884
+ }
885
+
0 commit comments