7373//! * `_5` (Borrow) -> `_4` (Local)
7474//! * `_6` (LocalWithRefs) -> `_5` (Borrow)
7575//! * `_7` (LocalWithRefs) -> `_6` (LocalWithRefs)
76- //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done, but unsafe)
76+ //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs)
7777//!
7878//! We also have to be careful when dealing with `Terminator`s. Whenever we pass references,
7979//! pointers or `Local`s with `NodeKind::LocalWithRefs` to a `TerminatorKind::Call` or
104104//! * `_7` is a `Local` of kind `LocalWithRefs` so needs to be taken into account in the
105105//! analyis. It's live from stmt 5 to stmt 9
106106//! * `_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`
108108//! it's live at 7.
109109//!
110110//! 3. Determining which `Local`s are borrowed
115115//! `_6` (Borrow) -> `_4` (Local)
116116//! `_7` (LocalWithRef) -> `_5` (Borrow)
117117//! `_8` (LocalWithRef) -> `_6` (Borrow)
118- //! `_9` (LocalWithRef) -> `_8` (LocalWithRef) (FIXME currently not done)
118+ //! `_9` (LocalWithRef) -> `_8` (LocalWithRef)
119119//! `_7` (LocalWithRef) -> `_10` (Local)
120120//!
121121//! 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> {
266266 }
267267 StatementKind :: FakeRead ( ..)
268268 | StatementKind :: StorageDead ( _)
269- | StatementKind :: StorageLive ( _) => { }
269+ | StatementKind :: StorageLive ( _)
270+ | StatementKind :: AscribeUserType ( ..)
271+ | StatementKind :: Deinit ( _)
272+ | StatementKind :: Coverage ( _) => { }
270273 _ => {
271274 self . super_statement ( statement, location) ;
272275 }
@@ -289,7 +292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
289292 // hence we want to treat them as `NodeKind::Borrow`
290293 // FIXME Are these always Operand::Copy or is Operand::Move also possible for refs/ptrs?
291294 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" ) ;
293296 } ;
294297
295298 // These are just moves of refs/ptrs, hence `NodeKind::Borrow`.
@@ -344,39 +347,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
344347
345348 #[ instrument( skip( self ) , level = "debug" ) ]
346349 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`
348351 let place_ty = place. ty ( self . local_decls , self . tcx ) . ty ;
349352 debug ! ( ?place_ty) ;
350353 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+ }
373398 }
374- None => { }
375- } ,
376- _ => {
377- // FIXME I think we probably need to introduce edges here if `place.local`
378- // corresponds to a `NodeKind::LocalWithRefs`
379399 }
400+ _ => { }
380401 }
381402
382403 self . super_place ( place, context, location)
@@ -450,25 +471,33 @@ where
450471 dep_graph : & ' a Graph < NodeKind , ( ) > ,
451472 ) -> FxHashMap < Local , Vec < Local > > {
452473 let mut borrows_to_locals: FxHashMap < Local , Vec < Local > > = Default :: default ( ) ;
474+ let mut locals_visited = vec ! [ ] ;
475+
453476 for ( node_idx, node) in dep_graph. enumerated_nodes ( ) {
454477 let current_local = node. data . get_local ( ) ;
455478 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+ ) ;
457485 }
458486 }
459487
460488 debug ! ( "borrows_to_locals: {:#?}" , borrows_to_locals) ;
461489 borrows_to_locals
462490 }
463491
464- // FIXME Account for cycles in the graph!
465492 fn dfs_for_node (
466493 node_idx : NodeIndex ,
467494 borrows_to_locals : & mut FxHashMap < Local , Vec < Local > > ,
468495 dep_graph : & Graph < NodeKind , ( ) > ,
496+ locals_visited : & mut Vec < Local > ,
469497 ) -> Vec < Local > {
470498 let src_node = dep_graph. node ( node_idx) ;
471499 let current_local = src_node. data . get_local ( ) ;
500+ locals_visited. push ( current_local) ;
472501 if let Some ( locals_to_keep_alive) = borrows_to_locals. get ( & current_local) {
473502 // already traversed this node
474503 return ( * locals_to_keep_alive) . clone ( ) ;
@@ -480,30 +509,36 @@ where
480509 num_succs += 1 ;
481510 let target_node_idx = edge. target ( ) ;
482511 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+ }
483516
484517 debug ! (
485518 "edge {:?} ({:?}) -> {:?} ({:?})" ,
486519 node_idx, src_node. data, target_node_idx, target_node. data,
487520 ) ;
488521
489522 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 ) ;
491524 locals_for_node. append ( & mut locals_to_keep_alive_for_succ) ;
492525 }
493526
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 ( _) => {
499533 // These are locals that we need to keep alive, but that also contain
500534 // successors in the graph since they contain other references/pointers.
501535 locals_for_node. push ( current_local) ;
502536 }
503-
504- borrows_to_locals. insert ( current_local, locals_for_node. clone ( ) ) ;
505- locals_for_node
537+ NodeKind :: Borrow ( _) => { }
506538 }
539+
540+ borrows_to_locals. insert ( current_local, locals_for_node. clone ( ) ) ;
541+ locals_for_node
507542 }
508543}
509544
0 commit comments