Skip to content
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

Error E0597 with Refcell::borrow and "if let", but disappear after adding more statements #67222

Closed
david0u0 opened this issue Dec 11, 2019 · 8 comments

Comments

@david0u0
Copy link

david0u0 commented Dec 11, 2019

There is a minimal repro at #67222 (comment) by @andreytkachenko

Sorry for the unclear title, but I found it hard to explain the situation I'm in. The following code leads to an E0597 error

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

fn main() {
    let mut s: HashMap<String, String> = HashMap::new();
    s.insert("a".to_owned(), "aa".to_owned());
    s.insert("b".to_owned(), "bb".to_owned());
    let mut s = Rc::new(RefCell::new(s));
    if let Some(o) = s.borrow().get("a") {
        println("{}, o);
    }
    else {
        // DO NOTHING 
    }
}

Which leads to:

error[E0597]: `s` does not live long enough
  --> src/main.rs:10:22
   |
10 |     if let Some(o) = s.borrow().get("a") {
   |                      ^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      a temporary with access to the borrow is created here ...
...
16 | }
   | -
   | |
   | `s` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::collections::HashMap<std::string::String, std::string::String>>`
   |

However, if I add some more statement before the main function ends, even a totally irrelevant print statement, the error disappear.

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

fn main() {
    let mut s: HashMap<String, String> = HashMap::new();
    s.insert("a".to_owned(), "aa".to_owned());
    s.insert("b".to_owned(), "bb".to_owned());
    let mut s = Rc::new(RefCell::new(s));
    if let Some(o) = s.borrow().get("a") {
        println("{}, o); 
    }
    else {
        // DO NOTHING 
    }
    println("hello!");  // <----- This line added!!
}

The platform is as follow:

 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

And the rustc version: rustc 1.41.0-nightly (7dbfb0a8c 2019-12-10)

Thanks!

@david0u0 david0u0 changed the title Error E0597 accurs at weird situation with Rc<RefCell<HashMap>> Error E0597 with Rc<RefCell<HashMap>>, but disapear when more statements are added Dec 11, 2019
@david0u0 david0u0 changed the title Error E0597 with Rc<RefCell<HashMap>>, but disapear when more statements are added Error E0597 with Rc<RefCell<HashMap>>, but disappear when more statements are added Dec 11, 2019
@alecmocatta
Copy link
Contributor

alecmocatta commented Dec 11, 2019

Adding a semicolon after the else clause resolves this. I believe this might be related to #21114.

@andreytkachenko
Copy link

Minimal repro:

fn main() {
    let s = std::cell::RefCell::new(Some(()));
    
    if let Some(_) = s.borrow().as_ref() {} else {} // add `;` to make it compilable
}

PS: I suspect - it has some tiny relation to #53528

@david0u0 david0u0 changed the title Error E0597 with Rc<RefCell<HashMap>>, but disappear when more statements are added Error E0597 with Refcell::borrow and "if let", but disappear when semicolons are added Dec 11, 2019
@david0u0
Copy link
Author

Thanks, I've changed the issue title to match the minimal repro

@jonas-schievink
Copy link
Contributor

The code and diagnostic reported in the original issue are wrong. Fixing the code yields this diagnostic:

error[E0597]: `s` does not live long enough
  --> src/main.rs:10:22
   |
10 |     if let Some(o) = s.borrow().get("a") {
   |                      ^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      a temporary with access to the borrow is created here ...
...
16 | }
   | -
   | |
   | `s` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::collections::HashMap<std::string::String, std::string::String>>`
   |
   = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.

The note at the end perfectly explains why this fails to compile and how to fix it. Closing.

@david0u0
Copy link
Author

The code and diagnostic reported in the original issue are wrong. Fixing the code yields this diagnostic:

error[E0597]: `s` does not live long enough
  --> src/main.rs:10:22
   |
10 |     if let Some(o) = s.borrow().get("a") {
   |                      ^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      a temporary with access to the borrow is created here ...
...
16 | }
   | -
   | |
   | `s` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::collections::HashMap<std::string::String, std::string::String>>`
   |
   = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.

The note at the end perfectly explains why this fails to compile and how to fix it. Closing.

Ok, somehow i had missed the note..... still I wander if it is a stable behavior, and if so, is it documented somewhere?

@jonas-schievink
Copy link
Contributor

It's documented here: https://doc.rust-lang.org/stable/reference/expressions.html#temporary-lifetimes

The text doesn't account for function bodies also being blocks, however. Feel free to send a PR to the reference changing the wording there.

@david0u0
Copy link
Author

@jonas-schievink
Besides, other than adding the semicolon, adding a new line of statement also make it compilable. I feel like this is somewhat inconsistent. Shouldn't it yield the same error E0597 after adding that statement?

@david0u0 david0u0 changed the title Error E0597 with Refcell::borrow and "if let", but disappear when semicolons are added Error E0597 with Refcell::borrow and "if let", but disappear after adding more statements Dec 12, 2019
@jonas-schievink
Copy link
Contributor

That also makes it no longer the trailing expression in the block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants