Skip to content

Borrow checker false dropped while still borrowed #38915

Closed

Description

@letheed

The following does not compile:

use std::ffi::OsString;
use std::io::{Result as IoResult};
use std::path::Path;

fn main() {
    let paths: Vec<OsString> = vec!["filename".into()];
// Switching these two lines appeases our lord and savior the borrow checker
    let f = std::fs::rename;
    let dests = paths.clone();
// ---------------------------
    let pairs = paths.iter().zip(dests.iter());
//                               ----- borrow occurs here
    foo(f, pairs);
}
// `dests` does not live long enough.
// ^ `dests` dropped here while still borrowed

fn foo<P, I>(f: fn(P, P) -> IoResult<()>, pairs: I)
    where P: AsRef<Path>,
          I: Iterator<Item=(P, P)>,
{
    for (src, dest) in pairs {
        let _ = f(src, dest);
    }
}

EDIT: simplified code.

Activity

  1. durka commented on Jan 9, 2017

    @durka
    Contributor

    That's bizarre. Somehow the borrow checker thinks that f contains a borrow of dests. Removing the call to foo also eliminates the error.

  2. letheed commented on Jan 9, 2017

    @letheed
    ContributorAuthor

    Exactly. I have a hard time figuring out what is happening here; I'm not familiar with the compiler's internals.

  3. philipc commented on Jan 9, 2017

    @philipc
    Contributor

    Simplified a bit more:

    fn main() {
        fn f<T>(_: T) {}
        let f = f;
        let v = 0;
        f(&v);
    }
  4. Rufflewind commented on Oct 30, 2017

    @Rufflewind
    Contributor

    Looking at @philipc's example, I believe the problem is that the type of the local variable f is actually the specialized type (since Rust does not support generics as first-class values). If you try to write out the specialized type, you get:

    fn(&'a i32)

    for some unknown 'a. The problem is that the presence of 'a affects not just the argument but also the function pointer itself, so the function pointer cannot outlive 'a either.

    If we could somehow specialize for<T> fn(T) as for<'a> fn(&'a i32) (is this sound?), then this could be worked around by giving the local variable f the correct type annotation.

  5. letheed commented on Nov 27, 2017

    @letheed
    ContributorAuthor

    @Rufflewind That was a long time ago but I remember trying to use for<'a> because I something like that, but to no avail.

  6. memoryruins commented on Jan 30, 2019

    @memoryruins
    Contributor

    Triage: now compiles on 2018 edition.
    2015 errors:

    error[E0597]: `dests` does not live long enough
      --> src/main.rs:11:34
       |
    11 |     let pairs = paths.iter().zip(dests.iter());
       |                                  ^^^^^ borrowed value does not live long enough
    ...
    14 | }
       | - `dests` dropped here while still borrowed
       |
       = note: values in a scope are dropped in the opposite order they are created
    
    error: aborting due to previous error
    

    rustc: 1.32.0

  7. added a commit that references this issue on Mar 11, 2019
    65cb35a
  8. added 3 commits that reference this issue on Apr 22, 2019
    bf0ea60
    c21fbfe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.fixed-by-NLLBugs fixed, but only when NLL is enabled.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions