rust icon indicating copy to clipboard operation
rust copied to clipboard

if let should pre-drop wrt else

Open est31 opened this issue 3 years ago • 2 comments

Consider this snippet:

struct Foo<'a>(&'a mut u32);

impl<'a> Drop for Foo<'a> {
    fn drop(&mut self) {
        *self.0 = 0;
    }
}

fn main() {
    let mut foo = 0;
    
    if let Foo(0) = Foo(&mut foo) { // Doesn't compile
    } else {
        *&mut foo = 1;
    }
    
    if matches!(Foo(&mut foo), Foo(0)) { // Compiles
    } else {
        *&mut foo = 1;
    }
}

Here, if let complains about an access of foo in the else branch, while if is okay with this.

This is due to if let dropping its temporaries after the else block. This is not neccessary, it could also drop them before.

Similar to #103107

cc @Nilstrieb

@rustbot label T-lang

est31 avatar Oct 16 '22 08:10 est31

This is probably a leftover from the time when if let used to desugar to a match, which keeps the scrutinee temporaries alive until the end of the match.

Dropping them early would be more consistent with if (it cannot be quite consistent as if let needs to keep them alive during the if block) but less consistent with match. Since if let is closer to if than match, I agree that it should behave more like it.

But I don't think we can change this. It could break code in extremely subtle undetectable cases (think of some kind of lock being held in the condition which is then required in the else branch). This also makes it hardly editionable, from a migration and also from a future rustc maintenance perspective.

Noratrieb avatar Oct 16 '22 09:10 Noratrieb

Good point about the consistency. There are analogous drop order optimization for matches too: You can drop the scrutinee temporaries before entering the body of any arm that is binding free and only followed by other binding-free arms, so cases like:

match foo {
    Enum::ValA(a) => {},
    Enum::ValB => {},
    _ => {},
}

for example, you would drop the temporaries before entering the bodies of the ValB and _ arms. Applied to if let, this would mean always dropping before else, and iff the pattern is binding free, also dropping before the then body.

But even without that extension, I'd be okay with the inconsistency with match if it makes more programs compile and drops resources more early on.

You are right, code might depend on the current behaviour and it might cause slight bugs. OTOH, one could also argue that if you rely on that specific quirk of drop order, then maybe your program was buggy from the start. <insert spacebar heating xkcd> :).

est31 avatar Oct 17 '22 01:10 est31