Closed
Description
I tried this code (reduced from https://users.rust-lang.org/t/lifetime-of-refcell-borrows/103346):
use std::cell::RefCell;
fn foo() {
let mut output = Vec::new();
for cell in vec![RefCell::new(Some(1))] {
let cell = cell;
if let Some(value) = cell.borrow().clone() {
output.push(value);
}
}
}
The following error results:
error[E0597]: `cell` does not live long enough
--> src/lib.rs:9:30
|
7 | let cell = cell;
| ---- binding `cell` declared here
8 |
9 | if let Some(value) = cell.borrow().clone() {
| ^^^^---------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
...
12 | }
| -
| |
| `cell` 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::option::Option<i32>>`
|
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
11 | };
| +
The suggested added semicolon does indeed let the code compile, but it really shouldn't be necessary because:
- A
for
loop cannot ever return a value other than()
- An
if let
withoutelse
cannot ever return a value other than()
(even if the pattern is irrefutable)
It's also weird that let cell = cell;
(or some other local let
binding) is needed to trigger the problem; presumably this happens because there's a drop scope in between the binding of the loop's pattern and the body block, but it's not at all obvious that the pattern should be longer-lived in that way.
Meta
rustc --version --verbose
:
rustc 1.76.0-nightly (6b771f6b5 2023-11-15)
binary: rustc
commit-hash: 6b771f6b5a6c8b03b6322a9c77ac77cb346148f0
commit-date: 2023-11-15
host: x86_64-apple-darwin
release: 1.76.0-nightly
LLVM version: 17.0.5
Also tested on stable 1.74.0 on the Playground.