@@ -26,22 +26,25 @@ use either::Either;
26
26
27
27
#[ derive( Copy , Clone , Debug ) ]
28
28
enum NodeKind {
29
- // An node corresponding to the place on the lhs of a statement like
30
- // `_3 = Ref(_, _, _4)`
29
+ // An node corresponding to the place of the borrowed place (`_4` in this case) in
30
+ // an assignment like `_3 = Ref(_, _, _4)`.
31
31
Borrow ( Local ) ,
32
32
33
33
// Nodes corresponding to the place on the lhs of a statement like
34
34
// `_2 = Aggregate(Adt(..), _, _, _, _), [move _3, move _6])`,
35
- // where _3 and _6 are places corresponding to references or raw pointers
36
- // or locals that are borrowed (`_2 = Ref(..)`).
37
- LocalOrLocalWithRefs ( Local ) ,
35
+ // where _3 and _6 are places corresponding to references or raw pointers.
36
+ LocalWithRefs ( Local ) ,
37
+
38
+ // Nodes corresponding to the place on the lhs of an assignment like `_2 = Ref(..)`.
39
+ Local ( Local ) ,
38
40
}
39
41
40
42
impl NodeKind {
41
43
fn get_local ( & self ) -> Local {
42
44
match self {
43
45
Self :: Borrow ( local) => * local,
44
- Self :: LocalOrLocalWithRefs ( local) => * local,
46
+ Self :: LocalWithRefs ( local) => * local,
47
+ Self :: Local ( local) => * local,
45
48
}
46
49
}
47
50
}
@@ -103,9 +106,8 @@ struct BorrowDependencies<'a, 'tcx> {
103
106
// liveness analysis.
104
107
dep_graph : Graph < NodeKind , ( ) > ,
105
108
106
- // Contains the `NodeIndex` corresponding to the local to which we're currently
107
- // assigning.
108
- current_local : Option < NodeIndex > ,
109
+ // Contains the `Local` to which we're currently assigning.
110
+ current_local : Option < Local > ,
109
111
}
110
112
111
113
impl < ' a , ' tcx > BorrowDependencies < ' a , ' tcx > {
@@ -122,6 +124,17 @@ impl<'a, 'tcx> BorrowDependencies<'a, 'tcx> {
122
124
locals_to_node_indexes : Default :: default ( ) ,
123
125
}
124
126
}
127
+
128
+ fn maybe_create_node ( & mut self , node_kind : NodeKind ) -> NodeIndex {
129
+ let local = node_kind. get_local ( ) ;
130
+ if let Some ( node_idx) = self . locals_to_node_indexes . get ( & local) {
131
+ * node_idx
132
+ } else {
133
+ let node_idx = self . dep_graph . add_node ( node_kind) ;
134
+ self . locals_to_node_indexes . insert ( local, node_idx) ;
135
+ node_idx
136
+ }
137
+ }
125
138
}
126
139
127
140
impl < ' a , ' tcx > Visitor < ' tcx > for BorrowDependencies < ' a , ' tcx > {
@@ -130,7 +143,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
130
143
// Add nodes for the arguments
131
144
for i in 1 ..=body. arg_count {
132
145
let local = Local :: from_usize ( i) ;
133
- let node_kind = NodeKind :: LocalOrLocalWithRefs ( local) ;
146
+ let node_kind = NodeKind :: Local ( local) ;
134
147
let node_idx = self . dep_graph . add_node ( node_kind) ;
135
148
self . locals_to_node_indexes . insert ( local, node_idx) ;
136
149
}
@@ -144,20 +157,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
144
157
StatementKind :: Assign ( assign) => {
145
158
let assign_place = assign. 0 ;
146
159
let assign_local = assign_place. local ;
147
-
148
- let node_kind = match assign_place. ty ( self . local_decls , self . tcx ) . ty . kind ( ) {
149
- ty:: Ref ( ..) | ty:: RawPtr ( ..) => NodeKind :: Borrow ( assign_local) ,
150
- _ => NodeKind :: LocalOrLocalWithRefs ( assign_local) ,
151
- } ;
152
-
153
- let node_idx = self . dep_graph . add_node ( node_kind) ;
154
- self . locals_to_node_indexes . insert ( assign_local, node_idx) ;
155
- self . current_local = Some ( node_idx) ;
156
-
157
- debug ! (
158
- "set current_local to {:?} for local {:?}" ,
159
- self . current_local, assign_local
160
- ) ;
160
+ self . current_local = Some ( assign_local) ;
161
+ debug ! ( "set current_local to {:?}" , self . current_local) ;
161
162
162
163
// Do not call `visit_place` here as this might introduce a self-edge, which our liveness analysis
163
164
// assumes not to exist.
@@ -178,18 +179,53 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
178
179
fn visit_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > , location : Location ) {
179
180
debug ! ( "self.current_local: {:?}" , self . current_local) ;
180
181
match rvalue {
182
+ Rvalue :: Use ( Operand :: Move ( place) | Operand :: Copy ( place) )
183
+ if matches ! (
184
+ place. ty( self . local_decls, self . tcx) . ty. kind( ) ,
185
+ ty:: Ref ( ..) | ty:: RawPtr ( ..)
186
+ ) =>
187
+ {
188
+ // these are just re-assignments of already outstanding refs or pointers,
189
+ // hence we want to treat them as `NodeKind::Borrow`
190
+ // FIXME Are these always Operand::Copy or is Operand::Move also possible for refs/ptrs?
191
+ let Some ( src_local) = self . current_local else {
192
+ bug ! ( "Expected self.current_local to be set with Rvalue::Ref|Rvalue::AddressOf" ) ;
193
+ } ;
194
+
195
+ // These are just moves of refs/ptrs, hence `NodeKind::Borrow`.
196
+ let src_node_kind = NodeKind :: Borrow ( src_local) ;
197
+ let src_node_idx = self . maybe_create_node ( src_node_kind) ;
198
+
199
+ let node_idx = if let Some ( node_idx) = self . locals_to_node_indexes . get ( & place. local )
200
+ {
201
+ * node_idx
202
+ } else {
203
+ bug ! ( "should have added a node for the moved borrowed place before" ) ;
204
+ } ;
205
+
206
+ debug ! (
207
+ "adding edge from {:?}({:?}) -> {:?}({:?})" ,
208
+ src_node_idx,
209
+ self . dep_graph. node( src_node_idx) . data,
210
+ node_idx,
211
+ self . dep_graph. node( node_idx) . data,
212
+ ) ;
213
+
214
+ self . dep_graph . add_edge ( src_node_idx, node_idx, ( ) ) ;
215
+ }
181
216
Rvalue :: Ref ( _, _, borrowed_place) | Rvalue :: AddressOf ( _, borrowed_place) => {
182
- let Some ( src_node_idx ) = self . current_local else {
217
+ let Some ( src_local ) = self . current_local else {
183
218
bug ! ( "Expected self.current_local to be set with Rvalue::Ref|Rvalue::AddressOf" ) ;
184
219
} ;
185
220
186
- let borrowed_local = borrowed_place. local ;
187
- let node_idx =
188
- if let Some ( node_idx) = self . locals_to_node_indexes . get ( & borrowed_local) {
189
- * node_idx
190
- } else {
191
- self . dep_graph . add_node ( NodeKind :: Borrow ( borrowed_place. local ) )
192
- } ;
221
+ // we're in a statement like `_4 = Ref(..)`, hence NodeKind::Borrow for `_4`
222
+ let src_node_kind = NodeKind :: Borrow ( src_local) ;
223
+ let src_node_idx = self . maybe_create_node ( src_node_kind) ;
224
+
225
+ // If we haven't previously added a node for `borrowed_place.local` then it can be neither
226
+ // `NodeKind::Borrow` nor `NodeKind::LocalsWithRefs`.
227
+ let borrowed_node_kind = NodeKind :: Local ( borrowed_place. local ) ;
228
+ let node_idx = self . maybe_create_node ( borrowed_node_kind) ;
193
229
194
230
debug ! (
195
231
"adding edge from {:?}({:?}) -> {:?}({:?})" ,
@@ -213,14 +249,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
213
249
debug ! ( "current local: {:?}" , self . current_local) ;
214
250
match place_ty. kind ( ) {
215
251
ty:: Ref ( ..) | ty:: RawPtr ( ..) => match self . current_local {
216
- Some ( src_node_idx) => {
217
- let borrowed_local = place. local ;
218
- let node_idx =
219
- if let Some ( node_idx) = self . locals_to_node_indexes . get ( & borrowed_local) {
220
- * node_idx
221
- } else {
222
- self . dep_graph . add_node ( NodeKind :: Borrow ( borrowed_local) )
223
- } ;
252
+ Some ( src_local) => {
253
+ // If we haven't created a node for this before, then this must be a
254
+ // `NodeKind::LocalWithRefs` as we would have handled the
255
+ // other possible assignment case (`NodeKind::Local`) previously in
256
+ // `visit_rvalue`.
257
+ let src_node_kind = NodeKind :: LocalWithRefs ( src_local) ;
258
+ let src_node_idx = self . maybe_create_node ( src_node_kind) ;
259
+
260
+ let borrowed_node_kind = NodeKind :: Borrow ( place. local ) ;
261
+ let node_idx = self . maybe_create_node ( borrowed_node_kind) ;
224
262
225
263
debug ! (
226
264
"adding edge from {:?}({:?}) -> {:?}({:?})" ,
@@ -268,13 +306,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
268
306
false
269
307
} ;
270
308
271
- let node_idx =
272
- self . dep_graph . add_node ( NodeKind :: LocalOrLocalWithRefs ( destination. local ) ) ;
273
- debug ! ( "added local {:?} to graph with idx {:?}" , destination. local, node_idx) ;
274
- self . locals_to_node_indexes . insert ( destination. local , node_idx) ;
275
-
276
309
if dest_might_include_refs_or_pointers {
277
- self . current_local = Some ( node_idx ) ;
310
+ self . current_local = Some ( destination . local ) ;
278
311
debug ! ( "self.current_local: {:?}" , self . current_local) ;
279
312
}
280
313
@@ -286,10 +319,29 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
286
319
self . current_local = None ;
287
320
}
288
321
TerminatorKind :: Yield { resume_arg, value, .. } => {
289
- let node_idx =
290
- self . dep_graph . add_node ( NodeKind :: LocalOrLocalWithRefs ( resume_arg. local ) ) ;
291
- debug ! ( "added local {:?} to graph with idx {:?}" , resume_arg. local, node_idx) ;
292
- self . locals_to_node_indexes . insert ( resume_arg. local , node_idx) ;
322
+ let resume_arg_ty = resume_arg. ty ( self . local_decls , self . tcx ) . ty ;
323
+ debug ! ( ?resume_arg_ty) ;
324
+
325
+ let mut has_refs_or_pointers_visitor = MaybeHasRefsOrPointersVisitor :: new ( ) ;
326
+ resume_arg_ty. visit_with ( & mut has_refs_or_pointers_visitor) ;
327
+
328
+ let dest_might_include_refs_or_pointers =
329
+ if has_refs_or_pointers_visitor. has_refs_or_pointers {
330
+ true
331
+ } else if has_refs_or_pointers_visitor. has_params {
332
+ // if we pass in any references or raw pointers as arguments and the
333
+ // return type includes type parameters, these type parameters could
334
+ // refer to those refs/ptrs, so we have to be conservative here and possibly
335
+ // include an edge.
336
+ true
337
+ } else {
338
+ false
339
+ } ;
340
+
341
+ if dest_might_include_refs_or_pointers {
342
+ self . current_local = Some ( resume_arg. local ) ;
343
+ debug ! ( "self.current_local: {:?}" , self . current_local) ;
344
+ }
293
345
294
346
self . super_operand ( value, location) ;
295
347
}
@@ -397,7 +449,7 @@ where
397
449
// base node to keep alive
398
450
vec ! [ src_node. data. get_local( ) ]
399
451
} else {
400
- if matches ! ( src_node. data, NodeKind :: LocalOrLocalWithRefs ( _) ) {
452
+ if matches ! ( src_node. data, NodeKind :: LocalWithRefs ( _) ) {
401
453
// These are locals that we need to keep alive, but that also contain
402
454
// successors in the graph since they contain other references/pointers.
403
455
locals_for_node. push ( current_local) ;
@@ -577,7 +629,7 @@ where
577
629
match projection. as_slice ( ) {
578
630
& [ ] | & [ ProjectionElem :: OpaqueCast ( _) ] => {
579
631
// If there aren't any projections or just an OpaqueCast we need to
580
- // kill the local if it's a ref or a pointer .
632
+ // kill the local.
581
633
match lhs_place_ty. kind ( ) {
582
634
ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
583
635
debug ! ( "killing {:?}" , lhs_place. local) ;
@@ -591,7 +643,7 @@ where
591
643
}
592
644
}
593
645
_ => {
594
- // With any other projection elements a projection of a local (of type ref/ptr)
646
+ // With any other projection elements, a projection of a local (of type ref/ptr)
595
647
// is actually a use-site, but we handle this in the call to `visit_place`.
596
648
self . super_assign ( & assign. 0 , & assign. 1 , location) ;
597
649
}
0 commit comments