Skip to content

Temporary lifetime extension applies to the last expression of a for loop body, causing unnecessary errors #118544

Closed
@kpreid

Description

@kpreid

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 without else 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions