You cannot dereference a &'b mut &'c mut u32
and get a &'c mut u32
because:
&mut
references are not trivially copiable, so you can't copy the &'c mut u32
; and
- You cannot move out of a reference, so you also can't move the
&'c mut u32
(which would leave the outer reference dangling).
Instead, the compiler reborrows the u32
with the outer lifetime, 'b
. This is why you get an error message that data from rr2
flows into rr1
.
If foo
were allowed to compile, you could use it to get two &mut
references to the same u32
, which is forbidden by the rules of references:
let (mut x, mut y) = (10, 20);
let mut rx = &mut x;
let mut ry = &mut y;
foo(&mut rx, &mut ry); // rx and ry now both refer to y
std::mem::swap(rx, ry); // undefined behavior!
If I require that 'b outlives 'c, it works
Because 'c
must already outlive 'b
1, if you require that 'b
also outlives 'c
, it follows that 'c
= 'b
. The updated signature is equivalent to this:
fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
That is, you have unified 'c
and 'b
, and now there's no problem borrowing a &'b mut u32
from rr2
because the inner and outer lifetimes both live for 'b
. However, the compiler now won't let you write the broken code in the example I gave earlier, since ry
is already borrowed for its entire lifetime.
Interestingly, if you make the inner reference non-mut
, it also works:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
*rr1 = *rr2;
}
This is because &
references are Copy
, so *rr2
is not a reborrow, but actually just a copy of the inner value.
For more information, read:
1 It might not be obvious why 'c
outlives 'b
when there is no explicit 'c: 'b
bound. The reason is because the compiler assumes that the type &'b mut &'c mut u32
is well-formed. Well-formedness can become complex (see RFC 1214) but in this case it just means you can't have a reference that's valid for longer ('b
) than the thing it references ('c
).