Bug in borrow checker?

Minimal reproducible example:

use std::io::{stdin, BufRead};

fn main() {
    for line in stdin().lock().lines() {
        println!("{}", line.unwrap())
    }
}

playground

error:

Compiling playground v0.0.1 (file:///playground)
error[E0597]: borrowed value does not live long enough
 --> src/main.rs:4:17
  |
4 |     for line in stdin().lock().lines() {
  |                 ^^^^^^^ temporary value does not live long enough
5 |         println!("{}", line.unwrap())
6 |     }
  |     - temporary value dropped here while still borrowed
  |
  = note: values in a scope are dropped in the opposite order they are created
  = note: consider using a `let` binding to increase its lifetime

It works:

let stdin = stdin();
for line in stdin.lock().lines() { ... }

I see io::stdin() returns Stdin struct which is borrowed by lock method returning StdinLock which is borrowed by BufRead::lines() returning iterator which will be destroyed at the end of for loop.

We can see that

values in a scope are dropped in the opposite order they are created

therefore dropping order is: Iter => StdinLock => Stdin thus when Stdin gets dropped it's not borrowed anymore so there's no need to increase its lifetime with let bound.

Am I wrong?

UPD

What happens: Why doesn't `io::stdin().lock().lines().count()` work? - #7 by jorendorff

What to do?: create some temporary let bindings to get nested lifetimes.

See https://users.rust-lang.org/t/why-doesnt-io-stdin-lock-lines-count-work/

1 Like