2929//!
3030//! The `Node`s in the dependency graph include data values of type `NodeKind`. `NodeKind` has
3131//! three variants: `Local`, `Borrow` and `LocalWithRefs`.
32- //! * `NodeKind::Local` is used for `Local`s that are borrowed somewhere (`_4` in our example)
32+ //! * `NodeKind::Local` is used for `Local`s that are borrowed somewhere (`_4` in our example), but aren't
33+ //! themselves references or pointers.
3334//! * `NodeKind::Borrow` is used for `Local`s that correspond to borrows (`_5` in our example) and
3435//! also `Local`s that result from re-borrows.
3536//! * `NodeKind::LocalWithRefs` is used for `Local`s that aren't themselves borrows, but contain
36- //! borrowed `Local`s. We want to keep these `Local`s live and also any of the references/pointers
37- //! they might contain . Let's look at an example:
37+ //! `Local`s that correspond to references, pointers or other `Local`s with `Node`s of kind
38+ //! `NodeKind::LocalWithRef`s . Let's look at an example:
3839//!
3940//! ```ignore(rust)
4041//! _4 = Bar {}
4748//! In this example `_6` would be given `NodeKind::LocalWithRefs` and our graph would look
4849//! as follows:
4950//!
50- //! `_7 (NodeKind::Borrow) -> `_6` (NodeKind::LocalWithRefs) -> `_5` (NodeKind::Borrow) -> `_4` (NodeKind::Local)
51- //!
52- //! In addition to keeping `_6` alive over the range of `_7` we also keep `_4` alive (leaf node).
51+ //! `_7` (NodeKind::Borrow) -> `_6` (NodeKind::LocalWithRefs) -> `_5` (NodeKind::Borrow) -> `_4` (NodeKind::Local)
52+ //!
53+ //! On the one hand we need to treat `Local`s with `Node`s of kind `NodeKind::LocalWithRefs` similarly
54+ //! to how we treat `Local`s with `Node`s of kind `NodeKind::Local`, in the sense that if they are
55+ //! borrowed we want to keep them live over the live range of the borrow. But on the other hand we
56+ //! want to also treat them like `Local`s with `Node`s of kind `NodeKind::Borrow` as they ultimately
57+ //! could also contain references or pointers that refer to other `Local`s. So we want a
58+ //! path in the graph from a `NodeKind::LocalWithRef`s node to the `NodeKind::Local` nodes, whose borrows
59+ //! they might contain.
5360//!
5461//! Additionally `NodeKind::LocalWithRefs` is also used for raw pointers that are cast to
5562//! `usize`:
6673//! * `_5` (Borrow) -> `_4` (Local)
6774//! * `_6` (LocalWithRefs) -> `_5` (Borrow)
6875//! * `_7` (LocalWithRefs) -> `_6` (LocalWithRefs)
69- //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done)
76+ //! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done, but unsafe )
7077//!
7178//! We also have to be careful when dealing with `Terminator`s. Whenever we pass references,
72- //! pointers or `Local`s with `NodeKind::LocalWithRefs` (FIXME currently not done) to
73- //! a `TerminatorKind::Call` or `TerminatorKind:: Yield` and the destination `Place` or resume place, resp.,
74- //! contains references/ pointers or generic parameters we have to be careful and treat the
75- //! `Local`s corresponding to the `Place`s as `NodeKind::LocalWithRef`s .
79+ //! pointers or `Local`s with `NodeKind::LocalWithRefs` to a `TerminatorKind::Call` or
80+ //! `TerminatorKind::Yield`, the destination `Place` or resume place, resp., might contain
81+ //! these references, pointers or `NodeKind::LocalWithRefs` `Local`s, hence we have to be conservative
82+ //! and keep the `destination` `Local` and `resume_arg` `Local` live .
7683//!
7784//! 2. Liveness analysis for borrows
7885//!
8693//! 3. _5 = Ref(_3)
8794//! 4. _6 = Ref(_4)
8895//! 5. _7 = Aggregate(..)(move _5)
89- //! 6. _8 = Call(..)(move _6) (assume _8 contains no refs/ptrs or generic params)
96+ //! 6. _8 = Call(..)(move _6)
9097//! 7. _9 = (_8.0)
91- //! 8. (_7.0) = _9
98+ //! 8. _10 = const 5
99+ //! 9. (_7.0) = move _10
92100//! ```
93101//!
94102//! * `_5` is live from stmt 3 to stmt 5
95103//! * `_6` is live from stmt 4 to stmt 6
96- //! * `_7` is a `Local` of kind `LocalWithRef` so needs to be taken into account in the
97- //! analyis. It's live from stmt 5 to stmt 8
104+ //! * `_7` is a `Local` of kind `LocalWithRefs` so needs to be taken into account in the
105+ //! analyis. It's live from stmt 5 to stmt 9
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),
108+ //! it's live at 7.
98109//!
99110//! 3. Determining which `Local`s are borrowed
100111//!
103114//! `_5` (Borrow) -> `_3` (Local)
104115//! `_6` (Borrow) -> `_4` (Local)
105116//! `_7` (LocalWithRef) -> `_5` (Borrow)
106- //! `_7` (LocalWithRef) -> `_9` (Local)
117+ //! `_8` (LocalWithRef) -> `_6` (Borrow)
118+ //! `_9` (LocalWithRef) -> `_8` (LocalWithRef) (FIXME currently not done)
119+ //! `_7` (LocalWithRef) -> `_10` (Local)
107120//!
108121//! So at each of those statements we have the following `Local`s that are live due to borrows:
109122//!
112125//! 3. {_3}
113126//! 4. {_3, _4}
114127//! 5. {_3, _4, _7}
115- //! 6. {_3, _4, _7}
116- //! 7. {_3, _7 }
128+ //! 6. {_3, _4, _7, _8 }
129+ //! 7. {_3, _4, _7, _8 }
117130//! 8. {_3, _7}
131+ //! 9. {_3, _7}
118132//!
119133
120134use super :: * ;
@@ -134,16 +148,16 @@ use either::Either;
134148
135149#[ derive( Copy , Clone , Debug ) ]
136150enum NodeKind {
137- // An node corresponding to the place of the borrowed place (`_4` in this case) in
138- // an assignment like `_3 = Ref(_, _, _4)`.
151+ // An node corresponding to the place on the lhs of an assignment like `_3 = Ref(_, _, _4)`.
139152 Borrow ( Local ) ,
140153
141154 // Nodes corresponding to the place on the lhs of a statement like
142155 // `_2 = Aggregate(Adt(..), _, _, _, _), [move _3, move _6])`,
143156 // where _3 and _6 are places corresponding to references or raw pointers.
144157 LocalWithRefs ( Local ) ,
145158
146- // Nodes corresponding to the place on the lhs of an assignment like `_2 = Ref(..)`.
159+ // Nodes corresponding to the borrowed place of an assignment like `_2 = Ref(_, _, borrowed_place)`,
160+ // if `borrowed_place` is a non-ref or non-ptr value.
147161 Local ( Local ) ,
148162}
149163
@@ -159,11 +173,25 @@ impl NodeKind {
159173
160174/// Used to build a dependency graph between borrows/pointers and the `Local`s that
161175/// they reference.
162- /// We add edges to the graph in two kinds of situations:
163- /// * direct assignment of reference or raw pointer (e.g. `_4 = Ref(..)` or `_4 = AddressOf`)
176+ /// We add edges to the graph in following situations:
177+ /// * direct assignment of reference or raw pointer (e.g. `_4 = Ref(_, _ , borrowed_place)` or
178+ /// `_4 = AddressOf(_, borrowed_place)`). For this case we create a `Node` of kind
179+ /// `NodeKind::Borrow` for the `Local` being assigned to and an edge to either an existing
180+ /// `Node` or if none exists yet to a new `Node` of type `NodeKind::Local` corresponding to
181+ /// a non-ref/ptr `Local`.
164182/// * assignments to non-reference or non-pointer `Local`s, which themselves might contain
165183/// references or pointers (e.g. `_2 = Aggregate(Adt(..), _, _, _, _), [move _3, move _6])`,
166- /// where `_3` and `_6` are places corresponding to references or raw pointers).
184+ /// where `_3` and `_6` are places corresponding to references or raw pointers). In this case
185+ /// we create a `Node` of kind `NodeKind::LocalWithRefs` for `_2`. Since `_3` and `_6` are
186+ /// `Local`s that correspond to references, pointers or composite types that might contain
187+ /// references or pointers (`NodeKind::LocalWithRefs`), there already exist `Node`s for these
188+ /// `Local`s. We then add edges from the `Node` for `_2` to both the `Node` for `_3` and the
189+ /// `Node` for `_6`.
190+ /// * `destination` places for `TerminatorKind::Call` and the `resume_arg` places for
191+ /// `TerminatorKind::Yield` if we pass in any references, pointers or composite values that
192+ /// might correspond to references, pointers or exposed pointers (`NodeKind::LocalWithRef`s).
193+ /// The rationale for this is that the return values of both of these terminators might themselves
194+ /// contain any of the references or pointers passed as arguments.
167195struct BorrowDependencies < ' a , ' tcx > {
168196 tcx : TyCtxt < ' tcx > ,
169197 local_decls : & ' a LocalDecls < ' tcx > ,
@@ -396,7 +424,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
396424}
397425
398426pub struct BorrowedLocalsResults < ' mir , ' tcx > {
427+ // the results of the liveness analysis of `LiveBorrows`
399428 borrows_analysis_results : Results < ' tcx , LiveBorrows < ' mir , ' tcx > > ,
429+
430+ // Maps each `Local` that corresponds to a reference, pointer or a node of kind
431+ // `NodeKind::LocalWithRefs` (i.e. `Local`s which either correspond to refs, pointers or
432+ // exposed pointers or a composite value that might include refs, pointers or exposed pointers)
433+ // to the set of `Local`s that are borrowed through those references, pointers or composite values.
400434 borrowed_local_to_locals_to_keep_alive : FxHashMap < Local , Vec < Local > > ,
401435}
402436
@@ -473,6 +507,8 @@ where
473507 }
474508}
475509
510+ /// The function gets the results of the borrowed locals analysis in this module. See the module
511+ /// doc-comment for information on what exactly this analysis does.
476512#[ instrument( skip( tcx) , level = "debug" ) ]
477513pub fn get_borrowed_locals_results < ' mir , ' tcx > (
478514 body : & ' mir Body < ' tcx > ,
@@ -517,9 +553,19 @@ pub fn get_borrowed_locals_results<'mir, 'tcx>(
517553 BorrowedLocalsResults :: new ( results)
518554}
519555
556+ /// The `ResultsCursor` equivalent for the borrowed locals analysis. Since this analysis doesn't
557+ /// require convergence, we expose the set of borrowed `Local`s for a `Location` directly via
558+ /// the `get` method without the need for any prior 'seek' calls.
520559pub struct BorrowedLocalsResultsCursor < ' a , ' mir , ' tcx > {
521560 body : & ' mir Body < ' tcx > ,
561+
562+ // The cursor for the liveness analysis performed by `LiveBorrows`
522563 borrows_analysis_cursor : ResultsRefCursor < ' a , ' mir , ' tcx , LiveBorrows < ' mir , ' tcx > > ,
564+
565+ // Maps each `Local` corresponding to a reference or pointer to the set of `Local`s
566+ // that are borrowed through the ref/ptr. Additionally contains entries for `Local`s
567+ // corresponding to `NodeKind::LocalWithRefs` since they might contain refs, ptrs or
568+ // exposed pointers and need to be treated equivalently to refs/ptrs
523569 borrowed_local_to_locals_to_keep_alive : & ' a FxHashMap < Local , Vec < Local > > ,
524570}
525571
@@ -586,7 +632,9 @@ impl<'a, 'mir, 'tcx> BorrowedLocalsResultsCursor<'a, 'mir, 'tcx> {
586632 }
587633}
588634
589- /// Performs a liveness analysis for borrows and raw pointers.
635+ /// Performs a liveness analysis for borrows and raw pointers. This analysis also tracks `Local`s
636+ /// corresponding to `Node`s of kind `NodeKind::LocalWithRefs`, as these could potentially refer to
637+ /// or include references, pointers or exposed pointers.
590638pub struct LiveBorrows < ' mir , ' tcx > {
591639 body : & ' mir Body < ' tcx > ,
592640 tcx : TyCtxt < ' tcx > ,
@@ -662,7 +710,7 @@ impl<'a, 'tcx> GenKillAnalysis<'tcx> for LiveBorrows<'a, 'tcx> {
662710 }
663711}
664712
665- /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals `.
713+ /// A `Visitor` that defines the transfer function for `LiveBorrows `.
666714struct TransferFunction < ' a , ' b , ' c , ' tcx , T > {
667715 body : & ' a Body < ' tcx > ,
668716 tcx : TyCtxt < ' tcx > ,
0 commit comments