1
1
//! Identifies the mutated places in a MIR instruction via modular approximation based on types.
2
2
3
3
use log:: debug;
4
- use rustc_middle:: mir:: { visit:: Visitor , * } ;
4
+ use rustc_middle:: {
5
+ mir:: { visit:: Visitor , * } ,
6
+ ty:: TyKind ,
7
+ } ;
5
8
6
9
use crate :: mir:: {
7
10
aliases:: Aliases ,
@@ -22,9 +25,8 @@ pub struct Mutation<'a, 'tcx> {
22
25
/// The place that is being mutated.
23
26
pub mutated : Place < ' tcx > ,
24
27
25
- /// The set of inputs to the mutating operation, each paired with
26
- /// an optional [`ProjectionElem::Field`] in the case of aggregate constructors.
27
- pub inputs : & ' a [ ( Place < ' tcx > , Option < PlaceElem < ' tcx > > ) ] ,
28
+ /// The set of inputs to the mutating operation.
29
+ pub inputs : & ' a [ Place < ' tcx > ] ,
28
30
29
31
/// Where the mutation is occuring.
30
32
pub location : Location ,
@@ -63,19 +65,74 @@ where
63
65
{
64
66
fn visit_assign (
65
67
& mut self ,
66
- place : & Place < ' tcx > ,
68
+ mutated : & Place < ' tcx > ,
67
69
rvalue : & Rvalue < ' tcx > ,
68
70
location : Location ,
69
71
) {
70
- debug ! ( "Checking {location:?}: {place:?} = {rvalue:?}" ) ;
71
- let mut collector = PlaceCollector {
72
- places : Vec :: new ( ) ,
73
- tcx : self . aliases . tcx ,
74
- } ;
72
+ debug ! ( "Checking {location:?}: {mutated:?} = {rvalue:?}" ) ;
73
+ let body = self . aliases . body ;
74
+ let tcx = self . aliases . tcx ;
75
+
76
+ match rvalue {
77
+ // In the case of _1 = aggregate { field1: op1, field2: op2, ... },
78
+ // then destructure this into a series of mutations like
79
+ // _1.field1 = op1, _1.field2 = op2, and so on.
80
+ Rvalue :: Aggregate ( box AggregateKind :: Adt ( def_id, idx, substs, _, _) , ops) => {
81
+ let adt_def = tcx. adt_def ( * def_id) ;
82
+ let variant = adt_def. variant ( * idx) ;
83
+ if variant. fields . len ( ) > 0 {
84
+ let fields = variant. fields . iter ( ) . enumerate ( ) . zip ( ops. iter ( ) ) . map (
85
+ |( ( i, field) , input_op) | {
86
+ let input_place = input_op. to_place ( ) ;
87
+ let field = PlaceElem :: Field ( Field :: from_usize ( i) , field. ty ( tcx, substs) ) ;
88
+ ( mutated. project_deeper ( & [ field] , tcx) , input_place)
89
+ } ,
90
+ ) ;
91
+ for ( mutated, input) in fields {
92
+ ( self . f ) ( Mutation {
93
+ mutated,
94
+ inputs : input. as_ref ( ) . map ( std:: slice:: from_ref) . unwrap_or_default ( ) ,
95
+ location,
96
+ status : MutationStatus :: Definitely ,
97
+ } ) ;
98
+ }
99
+ return ;
100
+ }
101
+ }
102
+
103
+ // In the case of _1 = _2 where _2 : struct Foo { x: T, y: S, .. },
104
+ // then destructure this into a series of mutations like
105
+ // _1.x = _2.x, _1.y = _2.y, and so on.
106
+ Rvalue :: Use ( Operand :: Move ( place) | Operand :: Copy ( place) ) => {
107
+ let place_ty = place. ty ( & body. local_decls , tcx) . ty ;
108
+ if let TyKind :: Adt ( adt_def, substs) = place_ty. kind ( ) {
109
+ if adt_def. is_struct ( ) {
110
+ let fields = adt_def. all_fields ( ) . enumerate ( ) . map ( |( i, field_def) | {
111
+ PlaceElem :: Field ( Field :: from_usize ( i) , field_def. ty ( tcx, substs) )
112
+ } ) ;
113
+ for field in fields {
114
+ let mutated_field = mutated. project_deeper ( & [ field] , tcx) ;
115
+ let input_field = place. project_deeper ( & [ field] , tcx) ;
116
+ ( self . f ) ( Mutation {
117
+ mutated : mutated_field,
118
+ inputs : & [ input_field] ,
119
+ location,
120
+ status : MutationStatus :: Definitely ,
121
+ } ) ;
122
+ }
123
+ return ;
124
+ }
125
+ }
126
+ }
127
+
128
+ _ => { }
129
+ }
130
+
131
+ let mut collector = PlaceCollector :: default ( ) ;
75
132
collector. visit_rvalue ( rvalue, location) ;
76
133
( self . f ) ( Mutation {
77
- mutated : * place ,
78
- inputs : & collector. places ,
134
+ mutated : * mutated ,
135
+ inputs : & collector. 0 ,
79
136
location,
80
137
status : MutationStatus :: Definitely ,
81
138
} ) ;
@@ -99,10 +156,7 @@ where
99
156
. map ( |( _, place) | place)
100
157
. filter ( |place| !async_hack. ignore_place ( * place) )
101
158
. collect :: < Vec < _ > > ( ) ;
102
- let arg_inputs = arg_places
103
- . iter ( )
104
- . map ( |place| ( * place, None ) )
105
- . collect :: < Vec < _ > > ( ) ;
159
+ let arg_inputs = arg_places. clone ( ) ;
106
160
107
161
let ret_is_unit = destination
108
162
. ty ( self . aliases . body . local_decls ( ) , tcx)
@@ -140,7 +194,7 @@ where
140
194
if let Some ( src) = value. to_place ( ) {
141
195
( self . f ) ( Mutation {
142
196
mutated : * place,
143
- inputs : & [ ( src, None ) ] ,
197
+ inputs : & [ src] ,
144
198
location,
145
199
status : MutationStatus :: Definitely ,
146
200
} ) ;
0 commit comments