Skip to content

Wrapper variable considered live after all of its constituents are consumed  #81693

@yshui

Description

@yshui

I tried this code:

use either::Either;
struct A;
struct B;
struct AW<'a>(&'a mut A);
impl<'a> Drop for AW<'a> {
    fn drop(&mut self) {

    }
}
fn cap(_: &mut A) -> Either::<AW<'_>, B> {
    unimplemented!()
}
pub fn main() {
    let mut a = A;
    let b = cap(&mut a);
    match b {
        Either::Left(a) => {
            drop(a);
        },
        Either::Right(y) => {
            a = A; // <- doesn't compile
        }
    }; // No way is the compiler going to drop b at this point in either case
}

In this piece of code, the compiler keeps b alive for the entire duration of match, preventing me from assigning to a in the Right arm. The explanation it gives is that it needs to run drop on b at the end of the match.

error[E0506]: cannot assign to `a` because it is borrowed
  --> src/main.rs:22:13
   |
15 |     let b = cap(&mut a);
   |                 ------ borrow of `a` occurs here
...
22 |             a = A;
   |             ^^^^^ assignment to borrowed `a` occurs here
...
26 | }
   | - borrow might be used here, when `b` is dropped and runs the destructor for type `Either<AW<'_>, B>`

However, that's not the case at all. b is partially moved in both arms, its drop cannot be called at the end of match.

Meta

rustc --version --verbose:

rustc 1.50.0-nightly (f76ecd066 2020-12-15)
binary: rustc
commit-hash: f76ecd0668fcdb289456cdc72a39ad15467cc454
commit-date: 2020-12-15
host: x86_64-unknown-linux-gnu
release: 1.50.0-nightly

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions