73
73
//! * `_5` (Borrow) -> `_4` (Local)
74
74
//! * `_6` (LocalWithRefs) -> `_5` (Borrow)
75
75
//! * `_7` (LocalWithRefs) -> `_6` (LocalWithRefs)
76
- //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done, but unsafe)
76
+ //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs)
77
77
//!
78
78
//! We also have to be careful when dealing with `Terminator`s. Whenever we pass references,
79
79
//! pointers or `Local`s with `NodeKind::LocalWithRefs` to a `TerminatorKind::Call` or
104
104
//! * `_7` is a `Local` of kind `LocalWithRefs` so needs to be taken into account in the
105
105
//! analyis. It's live from stmt 5 to stmt 9
106
106
//! * `_8` is a `Local` of kind `LocalWithRefs`. It's live from 6. to 7.
107
- //! * `_9` is a `Local` of kind `LocalWithRefs` (FIXME this is currently not done, see FIXME above),
107
+ //! * `_9` is a `Local` of kind `LocalWithRefs`
108
108
//! it's live at 7.
109
109
//!
110
110
//! 3. Determining which `Local`s are borrowed
115
115
//! `_6` (Borrow) -> `_4` (Local)
116
116
//! `_7` (LocalWithRef) -> `_5` (Borrow)
117
117
//! `_8` (LocalWithRef) -> `_6` (Borrow)
118
- //! `_9` (LocalWithRef) -> `_8` (LocalWithRef) (FIXME currently not done)
118
+ //! `_9` (LocalWithRef) -> `_8` (LocalWithRef)
119
119
//! `_7` (LocalWithRef) -> `_10` (Local)
120
120
//!
121
121
//! So at each of those statements we have the following `Local`s that are live due to borrows:
@@ -266,7 +266,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
266
266
}
267
267
StatementKind :: FakeRead ( ..)
268
268
| StatementKind :: StorageDead ( _)
269
- | StatementKind :: StorageLive ( _) => { }
269
+ | StatementKind :: StorageLive ( _)
270
+ | StatementKind :: AscribeUserType ( ..)
271
+ | StatementKind :: Deinit ( _)
272
+ | StatementKind :: Coverage ( _) => { }
270
273
_ => {
271
274
self . super_statement ( statement, location) ;
272
275
}
@@ -289,7 +292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
289
292
// hence we want to treat them as `NodeKind::Borrow`
290
293
// FIXME Are these always Operand::Copy or is Operand::Move also possible for refs/ptrs?
291
294
let Some ( src_local) = self . current_local else {
292
- bug ! ( "Expected self.current_local to be set with Rvalue::Ref|Rvalue::AddressOf " ) ;
295
+ bug ! ( "Expected self.current_local to be set when encountering Rvalue" ) ;
293
296
} ;
294
297
295
298
// These are just moves of refs/ptrs, hence `NodeKind::Borrow`.
@@ -344,39 +347,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
344
347
345
348
#[ instrument( skip( self ) , level = "debug" ) ]
346
349
fn visit_place ( & mut self , place : & Place < ' tcx > , context : PlaceContext , location : Location ) {
347
- // Add edges for places that correspond to references or raw pointers
350
+ // Add edges for places that correspond to references/raw pointers or nodes of kind `LocalWithRefs`
348
351
let place_ty = place. ty ( self . local_decls , self . tcx ) . ty ;
349
352
debug ! ( ?place_ty) ;
350
353
debug ! ( "current local: {:?}" , self . current_local) ;
351
- match place_ty. kind ( ) {
352
- ty:: Ref ( ..) | ty:: RawPtr ( ..) => match self . current_local {
353
- Some ( src_local) => {
354
- // If we haven't created a node for this before, then this must be a
355
- // `NodeKind::LocalWithRefs` as we would have handled the
356
- // other possible assignment case (`NodeKind::Local`) previously in
357
- // `visit_rvalue`.
358
- let src_node_kind = NodeKind :: LocalWithRefs ( src_local) ;
359
- let src_node_idx = self . maybe_create_node ( src_node_kind) ;
360
-
361
- let borrowed_node_kind = NodeKind :: Borrow ( place. local ) ;
362
- let node_idx = self . maybe_create_node ( borrowed_node_kind) ;
363
-
364
- debug ! (
365
- "adding edge from {:?}({:?}) -> {:?}({:?})" ,
366
- src_node_idx,
367
- self . dep_graph. node( src_node_idx) . data,
368
- node_idx,
369
- place. local
370
- ) ;
371
-
372
- self . dep_graph . add_edge ( src_node_idx, node_idx, ( ) ) ;
354
+
355
+ match self . current_local {
356
+ Some ( src_local) => {
357
+ match place_ty. kind ( ) {
358
+ ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
359
+ // If we haven't created a node for this before, then this must be a
360
+ // `NodeKind::LocalWithRefs` as we would have handled the
361
+ // other possible assignment case (`NodeKind::Local`) previously in
362
+ // `visit_rvalue`.
363
+ let src_node_kind = NodeKind :: LocalWithRefs ( src_local) ;
364
+ let src_node_idx = self . maybe_create_node ( src_node_kind) ;
365
+
366
+ let borrowed_node_kind = NodeKind :: Borrow ( place. local ) ;
367
+ let node_idx = self . maybe_create_node ( borrowed_node_kind) ;
368
+
369
+ debug ! (
370
+ "adding edge from {:?}({:?}) -> {:?}({:?})" ,
371
+ src_node_idx,
372
+ self . dep_graph. node( src_node_idx) . data,
373
+ node_idx,
374
+ place. local
375
+ ) ;
376
+
377
+ self . dep_graph . add_edge ( src_node_idx, node_idx, ( ) ) ;
378
+ }
379
+ _ => {
380
+ if let Some ( node_idx) = self . locals_to_node_indexes . get ( & place. local ) {
381
+ // LocalsWithRefs -> LocalWithRefs
382
+
383
+ let node_idx = * node_idx;
384
+ let src_node_kind = NodeKind :: LocalWithRefs ( src_local) ;
385
+ let src_node_idx = self . maybe_create_node ( src_node_kind) ;
386
+
387
+ debug ! (
388
+ "adding edge from {:?}({:?}) -> {:?}({:?})" ,
389
+ src_node_idx,
390
+ self . dep_graph. node( src_node_idx) . data,
391
+ node_idx,
392
+ self . dep_graph. node( node_idx) . data,
393
+ ) ;
394
+
395
+ self . dep_graph . add_edge ( src_node_idx, node_idx, ( ) ) ;
396
+ }
397
+ }
373
398
}
374
- None => { }
375
- } ,
376
- _ => {
377
- // FIXME I think we probably need to introduce edges here if `place.local`
378
- // corresponds to a `NodeKind::LocalWithRefs`
379
399
}
400
+ _ => { }
380
401
}
381
402
382
403
self . super_place ( place, context, location)
@@ -450,25 +471,33 @@ where
450
471
dep_graph : & ' a Graph < NodeKind , ( ) > ,
451
472
) -> FxHashMap < Local , Vec < Local > > {
452
473
let mut borrows_to_locals: FxHashMap < Local , Vec < Local > > = Default :: default ( ) ;
474
+ let mut locals_visited = vec ! [ ] ;
475
+
453
476
for ( node_idx, node) in dep_graph. enumerated_nodes ( ) {
454
477
let current_local = node. data . get_local ( ) ;
455
478
if borrows_to_locals. get ( & current_local) . is_none ( ) {
456
- Self :: dfs_for_node ( node_idx, & mut borrows_to_locals, dep_graph) ;
479
+ Self :: dfs_for_node (
480
+ node_idx,
481
+ & mut borrows_to_locals,
482
+ dep_graph,
483
+ & mut locals_visited,
484
+ ) ;
457
485
}
458
486
}
459
487
460
488
debug ! ( "borrows_to_locals: {:#?}" , borrows_to_locals) ;
461
489
borrows_to_locals
462
490
}
463
491
464
- // FIXME Account for cycles in the graph!
465
492
fn dfs_for_node (
466
493
node_idx : NodeIndex ,
467
494
borrows_to_locals : & mut FxHashMap < Local , Vec < Local > > ,
468
495
dep_graph : & Graph < NodeKind , ( ) > ,
496
+ locals_visited : & mut Vec < Local > ,
469
497
) -> Vec < Local > {
470
498
let src_node = dep_graph. node ( node_idx) ;
471
499
let current_local = src_node. data . get_local ( ) ;
500
+ locals_visited. push ( current_local) ;
472
501
if let Some ( locals_to_keep_alive) = borrows_to_locals. get ( & current_local) {
473
502
// already traversed this node
474
503
return ( * locals_to_keep_alive) . clone ( ) ;
@@ -480,30 +509,36 @@ where
480
509
num_succs += 1 ;
481
510
let target_node_idx = edge. target ( ) ;
482
511
let target_node = dep_graph. node ( target_node_idx) ;
512
+ let target_local = target_node. data . get_local ( ) ;
513
+ if locals_visited. contains ( & target_local) {
514
+ continue ;
515
+ }
483
516
484
517
debug ! (
485
518
"edge {:?} ({:?}) -> {:?} ({:?})" ,
486
519
node_idx, src_node. data, target_node_idx, target_node. data,
487
520
) ;
488
521
489
522
let mut locals_to_keep_alive_for_succ =
490
- Self :: dfs_for_node ( target_node_idx, borrows_to_locals, dep_graph) ;
523
+ Self :: dfs_for_node ( target_node_idx, borrows_to_locals, dep_graph, locals_visited ) ;
491
524
locals_for_node. append ( & mut locals_to_keep_alive_for_succ) ;
492
525
}
493
526
494
- if num_succs == 0 {
495
- // base node to keep alive
496
- vec ! [ src_node. data. get_local( ) ]
497
- } else {
498
- if matches ! ( src_node. data, NodeKind :: LocalWithRefs ( _) ) {
527
+ match src_node. data {
528
+ NodeKind :: Local ( _) => {
529
+ assert ! ( num_succs == 0 , "Local node with successors" ) ;
530
+ return vec ! [ src_node. data. get_local( ) ] ;
531
+ }
532
+ NodeKind :: LocalWithRefs ( _) => {
499
533
// These are locals that we need to keep alive, but that also contain
500
534
// successors in the graph since they contain other references/pointers.
501
535
locals_for_node. push ( current_local) ;
502
536
}
503
-
504
- borrows_to_locals. insert ( current_local, locals_for_node. clone ( ) ) ;
505
- locals_for_node
537
+ NodeKind :: Borrow ( _) => { }
506
538
}
539
+
540
+ borrows_to_locals. insert ( current_local, locals_for_node. clone ( ) ) ;
541
+ locals_for_node
507
542
}
508
543
}
509
544
0 commit comments