]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/path_utils.rs
Fix rebase fail
[rust.git] / src / librustc_mir / borrow_check / path_utils.rs
1 use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
2 use crate::borrow_check::places_conflict;
3 use crate::borrow_check::Context;
4 use crate::borrow_check::AccessDepth;
5 use crate::dataflow::indexes::BorrowIndex;
6 use rustc::mir::{BasicBlock, Location, Mir, Place};
7 use rustc::mir::{ProjectionElem, BorrowKind};
8 use rustc::ty::TyCtxt;
9 use rustc_data_structures::graph::dominators::Dominators;
10
11 /// Returns true if the borrow represented by `kind` is
12 /// allowed to be split into separate Reservation and
13 /// Activation phases.
14 pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(
15     tcx: &TyCtxt<'a, 'gcx, 'tcx>,
16     kind: BorrowKind
17 ) -> bool {
18     tcx.two_phase_borrows()
19         && (kind.allows_two_phase_borrow()
20             || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
21 }
22
23 /// Control for the path borrow checking code
24 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
25 pub(super) enum Control {
26     Continue,
27     Break,
28 }
29
30 /// Encapsulates the idea of iterating over every borrow that involves a particular path
31 pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
32     s: &mut S,
33     tcx: TyCtxt<'a, 'gcx, 'tcx>,
34     mir: &Mir<'tcx>,
35     _context: Context,
36     access_place: (AccessDepth, &Place<'tcx>),
37     borrow_set: &BorrowSet<'tcx>,
38     candidates: I,
39     mut op: F,
40 ) where
41     F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
42     I: Iterator<Item=BorrowIndex>
43 {
44     let (access, place) = access_place;
45
46     // FIXME: analogous code in check_loans first maps `place` to
47     // its base_path.
48
49     // check for loan restricting path P being used. Accounts for
50     // borrows of P, P.a.b, etc.
51     for i in candidates {
52         let borrowed = &borrow_set[i];
53
54         if places_conflict::borrow_conflicts_with_place(
55             tcx,
56             mir,
57             &borrowed.borrowed_place,
58             borrowed.kind,
59             place,
60             access,
61             places_conflict::PlaceConflictBias::Overlap,
62         ) {
63             debug!(
64                 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
65                 i, borrowed, place, access
66             );
67             let ctrl = op(s, i, borrowed);
68             if ctrl == Control::Break {
69                 return;
70             }
71         }
72     }
73 }
74
75 pub(super) fn is_active<'tcx>(
76     dominators: &Dominators<BasicBlock>,
77     borrow_data: &BorrowData<'tcx>,
78     location: Location
79 ) -> bool {
80     debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
81
82     let activation_location = match borrow_data.activation_location {
83         // If this is not a 2-phase borrow, it is always active.
84         TwoPhaseActivation::NotTwoPhase => return true,
85         // And if the unique 2-phase use is not an activation, then it is *never* active.
86         TwoPhaseActivation::NotActivated => return false,
87         // Otherwise, we derive info from the activation point `loc`:
88         TwoPhaseActivation::ActivatedAt(loc) => loc,
89     };
90
91     // Otherwise, it is active for every location *except* in between
92     // the reservation and the activation:
93     //
94     //       X
95     //      /
96     //     R      <--+ Except for this
97     //    / \        | diamond
98     //    \ /        |
99     //     A  <------+
100     //     |
101     //     Z
102     //
103     // Note that we assume that:
104     // - the reservation R dominates the activation A
105     // - the activation A post-dominates the reservation R (ignoring unwinding edges).
106     //
107     // This means that there can't be an edge that leaves A and
108     // comes back into that diamond unless it passes through R.
109     //
110     // Suboptimal: In some cases, this code walks the dominator
111     // tree twice when it only has to be walked once. I am
112     // lazy. -nmatsakis
113
114     // If dominated by the activation A, then it is active. The
115     // activation occurs upon entering the point A, so this is
116     // also true if location == activation_location.
117     if activation_location.dominates(location, dominators) {
118         return true;
119     }
120
121     // The reservation starts *on exiting* the reservation block,
122     // so check if the location is dominated by R.successor. If so,
123     // this point falls in between the reservation and location.
124     let reserve_location = borrow_data.reserve_location.successor_within_block();
125     if reserve_location.dominates(location, dominators) {
126         false
127     } else {
128         // Otherwise, this point is outside the diamond, so
129         // consider the borrow active. This could happen for
130         // example if the borrow remains active around a loop (in
131         // which case it would be active also for the point R,
132         // which would generate an error).
133         true
134     }
135 }
136
137 /// Determines if a given borrow is borrowing local data
138 /// This is called for all Yield statements on movable generators
139 pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
140     match place {
141         Place::Promoted(_) |
142         Place::Static(..) => false,
143         Place::Local(..) => true,
144         Place::Projection(box proj) => {
145             match proj.elem {
146                 // Reborrow of already borrowed data is ignored
147                 // Any errors will be caught on the initial borrow
148                 ProjectionElem::Deref => false,
149
150                 // For interior references and downcasts, find out if the base is local
151                 ProjectionElem::Field(..)
152                     | ProjectionElem::Index(..)
153                     | ProjectionElem::ConstantIndex { .. }
154                 | ProjectionElem::Subslice { .. }
155                 | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
156             }
157         }
158     }
159 }