Skip to content
Select theme

What is reborrowing?

Short answer: Passing a &mut to something that expects a &mut doesn’t move it. The compiler reborrows — it writes &mut *r for you, a fresh borrow of the value the reference points at, lasting for the call and no longer. The binding you passed is still there afterwards.

From a fresh project — cargo new reborrow-demo, then replace src/main.rs with the whole of this. The project name doesn’t matter, because nothing in the output depends on it:

7

r is used after the call, and the file compiles. A &mut i32 is not Copy, so if bump(r) moved it, the next line would be an error. What the compiler does instead is treat r as a place and reborrow through it: the call is really bump(&mut *r). That new reference points at value, lives for the duration of the call, and ends when bump returns. r is then a &mut i32 to the same value again — hence *r += 1 lands and the print shows 7. Nothing in the source marks any of this; reborrowing has no syntax.

The reborrow appears where the expected type is a reference. Assign the reference to another binding — let r2 = r; — and that is a plain move, because &mut i32 doesn’t implement Copy. The same goes for anything that takes the reference by value, and a generic parameter is the usual way to meet one:

error[E0382]: use of moved value: `r`
--> src/main.rs:8:5
|
5 | let r = &mut value;
| - move occurs because `r` has type `&mut i32`, which does not implement the `Copy` trait
6 |
7 | take_anything(r);
| - value moved here
8 | *r += 1;
| ^^^^^^^ value used here after move
|
help: consider creating a fresh reborrow of `r` here
|
7 | take_anything(&mut *r);
| +++++++
For more information about this error, try `rustc --explain E0382`.

At the call site the type of T isn’t known yet, so there is no reference type to reborrow through and r moves. The compiler’s suggestion names the fix: write the reborrow yourself.

6

&mut *r is the reborrow the compiler writes for you at a call site, now by hand: it borrows value again for the length of the call, and r is untouched.

A reborrow is an ordinary borrow, so exclusivity covers it too. Hand the same reference to a function twice and both arguments try to reborrow the same value:

error[E0499]: cannot borrow `*r` as mutable more than once at a time
--> src/main.rs:10:19
|
10 | bump_twice(r, r);
| ---------- - ^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
For more information about this error, try `rustc --explain E0499`.

The complaint is about *r — the value — not about the reference. Two exclusive borrows of value overlap for the length of the call, which is what the rules of borrowing refuse when you write &mut value twice. Reborrowing is a convenience, not a loophole.

Method calls reborrow too. A &mut self method called through a reference borrows the receiver for the call and hands it back:

[1, 2, 3, 4, 5]

If r.push(4) moved r, the second call couldn’t compile. Every chain of mutations through one &mut — and every mem::swap(ra, rb) between two of them — works because each call reborrows and returns the reference. Storing the reference in a struct field reborrows the same way: the field holds a borrow of the value, and r is usable again once the struct is done with it.