What is conflicting shared borrows in two-phase borrows?

⚓ rust    📅 2025-06-17    👤 surdeus    👁️ 2      

surdeus

Consider this example:

fn main(){
  let mut x = vec![];
  let p = &x; 
  x.push(p.len());
}

Two-phase borrows works here. The code can be expanded to the following:

let mut x = vec![];
let p = &x; // #0
let temp1 = &two_phase x;  // #1
let temp2 = p.len();
Vec::push(temp1, temp2); // #2

According to the document of two-phase borrows, #1 is considered the reservation point and #2 is the activation point. However, there is a mess wording in the last paragraph

Two-phase borrows are treated as if they were mutable borrows with the following exceptions:

  • At every location in the MIR we check if any two-phase borrows are activated at this location. If a live two phase borrow is activated at a location, then we check that there are no borrows that conflict with the two-phase borrow.
  • At the reservation point we error if there are conflicting live mutable borrows. And lint if there are any conflicting shared borrows.
  • Between the reservation and the activation point, the two-phase borrow acts as a shared borrow. We determine (in is_active) if we're at such a point by using the Dominators for the MIR graph.
  • After the activation point, the two-phase borrow acts as a mutable borrow.

What does the conflicting shared borrows mean here? p is a shared borrow that lives at #1. Whether the &two_phase x at #1 is considered the deep write or deep read to the lvalue x?

According to 2094-nll - The Rust RFC Book, if &two_phase x is a deep write to x, then the loan at #0 conflicts with it.

The two-phase borrows document didn't specify how &two_phase lvalue behaves at the reservation point, so how to determine whether a loan conflicts with it at the reservation point?

3 posts - 2 participants

Read full topic

🏷️ rust_feed