How does the borrow checker track reborrows?

⚓ Rust    📅 2025-07-13    👤 surdeus    👁️ 2      

surdeus

I'm trying to better understand how reborrowing works.

For example, consider the following two examples:

struct S {}

impl S {
    fn dup(&mut self) -> &mut S {
        return self;
    }
}

pub fn main() {
    let mut s = S {};
    let r1 = &mut s;
    let r2 = r1.dup();
    *r1 = S {};
    *r2 = S {};
}

fails to check with:

   |
12 |     let r2 = r1.dup();
   |              -- `*r1` is borrowed here
13 |     *r1 = S {};
   |     ^^^^^^^^^^ `*r1` is assigned to here but it was already borrowed
14 |     *r2 = S {};
   |     ---------- borrow later used here
struct S {}

struct C<'a> {
    s: &'a mut S
}

impl S {
    fn cap(&mut self) -> C {
        return C { s: self };
    }
}

pub fn main() {
    let mut s = S {};
    let r1 = &mut s;
    let c = r1.cap();
    *r1 = S {};
    *c.s = S {};
}

fails to check with:

   |
16 |     let c = r1.cap();
   |             -- `*r1` is borrowed here
17 |     *r1 = S {};
   |     ^^^^^^^^^^ `*r1` is assigned to here but it was already borrowed
18 |     *c.s = S {};
   |     ----------- borrow later used here

Removing the assignment in the last statement makes the code typecheck.

How does the borrow checker determine that s is still borrowed after the function calls, how does it reject the assignments, which do not explicitly mention s? Is there a relationship between parameters and return values?

5 posts - 2 participants

Read full topic

🏷️ rust_feed