Double borrows drops temporary too early

The following code describes the issue:

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug, Clone, Default)]
struct A {
    id: usize,
    // ** more fields **
}

#[derive(Debug, Clone, Default)]
struct B {
    v: Vec<RefCell<A>>
}

#[derive(Debug, Clone, Default)]
struct C {
    rc: Rc<RefCell<B>>,
}

fn main() {
    let c = C::default();
    c.rc.borrow_mut().v.push(RefCell::new(A::default()));
    // This works
    // let id = {
    //     let b = c.rc.borrow();
    //     let id = b.v[0].borrow().id;
    //     id
    // };
    let id = c.rc.borrow().v[0].borrow().id;
    println!("Id: {}", id);
    
}

The code as above does not compile with the error:

error: borrowed value does not live long enough
  --> <anon>:26:14
   |
26 |     let id = c.rc.borrow().v[0].borrow().id;
   |              ^^^^^^^^^^^^^                 - temporary value dropped before borrower
   |              |
   |              temporary value created here
   |
   = note: values in a scope are dropped in the opposite order they are created
   = note: consider using a `let` binding to increase its lifetime

However if we uncomment that block instead it works. Firstly, is there a good reason why this is happening and should it really be happening. In this case I actually do not even understand what is happening and why is the compiler rejecting it? Could someone explain.

mbrubeck on IRC pointed out that this and this are related to this, but I still did not understand why.

Since id is just an integer and thus doesn't contain any references, I think your error is unfortunately a compiler bug – it looks that Rust incorrectly assumes that id may contain some references. You should file an issue on github. Meanwhile, let's hope it gets fixed soon!

2 Likes