]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / borrow_check / two_phase_borrows.md
1 # Two-phase borrows
2
3 Two-phase borrows are a more permissive version of mutable borrows that allow
4 nested method calls such as `vec.push(vec.len())`. Such borrows first act as
5 shared borrows in a "reservation" phase and can later be "activated" into a
6 full mutable borrow.
7
8 Only certain implicit mutable borrows can be two-phase, any `&mut` or `ref mut`
9 in the source code is never a two-phase borrow. The cases where we generate a
10 two-phase borrow are:
11
12 1. The autoref borrow when calling a method with a mutable reference receiver.
13 2. A mutable reborrow in function arguments.
14 3. The implicit mutable borrow in an overloaded compound assignment operator.
15
16 To give some examples:
17
18 ```rust2018
19 // In the source code
20
21 // Case 1:
22 let mut v = Vec::new();
23 v.push(v.len());
24 let r = &mut Vec::new();
25 r.push(r.len());
26
27 // Case 2:
28 std::mem::replace(r, vec![1, r.len()]);
29
30 // Case 3:
31 let mut x = std::num::Wrapping(2);
32 x += x;
33 ```
34
35 Expanding these enough to show the two-phase borrows:
36
37 ```rust,ignore
38 // Case 1:
39 let mut v = Vec::new();
40 let temp1 = &two_phase v;
41 let temp2 = v.len();
42 Vec::push(temp1, temp2);
43 let r = &mut Vec::new();
44 let temp3 = &two_phase *r;
45 let temp4 = r.len();
46 Vec::push(temp3, temp4);
47
48 // Case 2:
49 let temp5 = &two_phase *r;
50 let temp6 = vec![1, r.len()];
51 std::mem::replace(temp5, temp6);
52
53 // Case 3:
54 let mut x = std::num::Wrapping(2);
55 let temp7 = &two_phase x;
56 let temp8 = x;
57 std::ops::AddAssign::add_assign(temp7, temp8);
58 ```
59
60 Whether a borrow can be two-phase is tracked by a flag on the [`AutoBorrow`]
61 after type checking, which is then [converted] to a [`BorrowKind`] during MIR
62 construction.
63
64 Each two-phase borrow is assigned to a temporary that is only used once. As
65 such we can define:
66
67 * The point where the temporary is assigned to is called the *reservation*
68 point of the two-phase borrow.
69 * The point where the temporary is used, which is effectively always a
70 function call, is called the *activation* point.
71
72 The activation points are found using the [`GatherBorrows`] visitor. The
73 [`BorrowData`] then holds both the reservation and activation points for the
74 borrow.
75
76 [`AutoBorrow`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adjustment/enum.AutoBorrow.html
77 [converted]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/cx/expr/trait.ToBorrowKind.html#method.to_borrow_kind
78 [`BorrowKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.BorrowKind.html
79 [`GatherBorrows`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/visit/trait.Visitor.html#method.visit_local
80 [`BorrowData`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/borrow_set/struct.BorrowData.html
81
82 ## Checking two-phase borrows
83
84 Two-phase borrows are treated as if they were mutable borrows with the
85 following exceptions:
86
87 1. At every location in the MIR we [check] if any two-phase borrows are
88 activated at this location. If a live two phase borrow is activated at a
89 location, then we check that there are no borrows that conflict with the
90 two-phase borrow.
91 2. At the reservation point we error if there are conflicting live *mutable*
92 borrows. And lint if there are any conflicting shared borrows.
93 3. Between the reservation and the activation point, the two-phase borrow acts
94 as a shared borrow. We determine (in [`is_active`]) if we're at such a point
95 by using the [`Dominators`] for the MIR graph.
96 4. After the activation point, the two-phase borrow acts as a mutable borrow.
97
98 [check]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/struct.MirBorrowckCtxt.html#method.check_activations
99 [`Dominators`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/graph/dominators/struct.Dominators.html
100 [`is_active`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/path_utils/fn.is_active.html