Skip to content

Odd and unexpected compiler error #95381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bananabrick opened this issue Mar 27, 2022 · 5 comments
Closed

Odd and unexpected compiler error #95381

bananabrick opened this issue Mar 27, 2022 · 5 comments
Labels
A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@bananabrick
Copy link

This code won't compile
I tried this code:

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());

    let branch = Rc::new(Node {
        value: 5,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![Rc::clone(&leaf)]),
    });

    *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

    if let Some(x) = leaf.parent.borrow().upgrade() {
        println!("leaf parent = {:?}", x);
    }
}

I expected to see this happen: code compiled

Instead, this happened: compiler error

a temporary with access to the borrow is created here ...rustcE0597
main.rs(35, 22): original diagnostic
`leaf` does not live long enough
borrowed value does not live long enoughrustcE0597
main.rs(38, 1): `leaf` dropped here while still borrowed
main.rs(35, 22): a temporary with access to the borrow is created here ...
main.rs(38, 1): ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, std::rc::Weak<Node>>`
main.rs(37, 6): consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped: `;`
@bananabrick bananabrick added the C-bug Category: This is a bug. label Mar 27, 2022
@scottmcm
Copy link
Member

scottmcm commented Mar 27, 2022

Playground repro: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=ef9fc1e647fb3d4c24bc023338d24f44

Real error, rather than the IDE-neutered one:

error[[E0597]](https://doc.rust-lang.org/nightly/error-index.html#E0597): `leaf` does not live long enough
  [--> src/main.rs:28:22
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
28 |     if let Some(x) = leaf.parent.borrow().upgrade() {
   |                      ^^^^----------------
   |                      |
   |                      borrowed value does not live long enough
   |                      a temporary with access to the borrow is created here ...
...
31 | }
   | -
   | |
   | `leaf` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, std::rc::Weak<Node>>`
   |
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
   |
30 |     };
   |      +

Note that this compiles if one adds the ; as suggested by the help.

@bananabrick
Copy link
Author

bananabrick commented Mar 27, 2022

Thanks, @scottmcm.

But I don't understand what's going on. Why is this error happening in the first place?

The leaf is valid until the end of main, and the temporary variable is presumably valid until the end of the let. And what is meant by local variables declared by the block are dropped.

As an aside, where is the borrow of "leaf" even occurring in that code.

@bananabrick
Copy link
Author

This code also doesn't compile for the same reasons.

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());

    let branch = Rc::new(Node {
        value: 5,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![Rc::clone(&leaf)]),
    });

    *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

    let x = leaf.parent.borrow().upgrade();
    if let Some(_) = leaf.parent.borrow().upgrade() {
        // println!("leaf parent = {:?}", x);
    }
}

No local variables defined in the block.

@zirconium-n
Copy link
Contributor

zirconium-n commented Mar 29, 2022

Minimized version

use std::cell::RefCell;

fn main() {
    let leaf = RefCell::new(());

    if let a = leaf.borrow() {}
}

@fmease fmease added A-borrow-checker Area: The borrow checker T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage-legacy labels Jan 24, 2024
@cyrgani
Copy link
Contributor

cyrgani commented Jun 2, 2025

This is fixed in the 2024 edition by shortening the temporary's scope to be dropped sooner: edition guide

@cyrgani cyrgani closed this as completed Jun 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants