Drop + 'if let' causes 'does not live long enough' error


#1

Today I ran into an interesting borrow checker error when writing a Guard object and using ‘if let’. I’ve condensed it to the following, which fails to compile:

struct A(u32);

struct AIncrementer<'a>(&'a mut A);

impl A {
    fn get_guard(&mut self) -> Option<AIncrementer> {
        Some(AIncrementer(self))
    }
}

impl<'a> Drop for AIncrementer<'a> {
    fn drop(&mut self) {
        println!("dropping");
    }
}

fn main() {
    let mut a = A(0);
    {
        let ainc = a.get_guard().unwrap();
    }

    {
        let ainc = a.get_guard().unwrap();
    }

    // !!!  error `a` does not live long enough
    if let Some(ainc) = a.get_guard() {
    }
}

But if I do this instead then it compiles fine

    let guard = a.get_guard();
    if let Some(ainc) = guard {
    }

I couldn’t find an existing issue covering this, is this a bug? Should I file an issue?

Thanks,

Phil


#2

Attack of the flying semicolon!

struct A(u32);

struct AIncrementer<'a>(&'a mut A);

impl A {
    fn get_guard(&mut self) -> Option<AIncrementer> {
        Some(AIncrementer(self))
    }
}

impl<'a> Drop for AIncrementer<'a> {
    fn drop(&mut self) {
        println!("dropping");
    }
}

fn main() {
    let mut a = A(0);
    {
        let ainc = a.get_guard().unwrap();
    }

    {
        let ainc = a.get_guard().unwrap();
    }

    // !!!  error `a` does not live long enough
    if let Some(ainc) = a.get_guard() {
    };
}

I think this has something to do with drop order but I don’t know the specifics.


#3

Wow! Thanks very much @stebalien, I will add that to my internal list of things to think about when I next get a borrow check error!


#4

Found the bug: https://github.com/rust-lang/rust/issues/22252