Skip to content

'Dropping temporaries' prevents borrow check to succeed in match arm without shared ownership #76149

@Byron

Description

@Byron

I tried this code (playground link):

struct Owner {
    to_be_shared: String,
}

impl Owner {
    fn share(&mut self) -> Result<Box<dyn ToString + '_>, ()> {
        Ok(Box::new(&self.to_be_shared) as Box<dyn ToString>)
    }
    fn do_something_else(&mut self) {}
}

fn use_owner(mut owner: Owner) {
    let _v = match owner.share() {
        Ok(v) => v,
        Err(()) => {
            owner.do_something_else();
            return;
        }
    };
}

fn main() {
    let owner = Owner {
        to_be_shared: String::new(),
    };
    use_owner(owner);
}

I expected to see this happen:

The code compiles. Especially it's possible to call owner.do_something_else() in the match branch dealing with the error, which does not borrow from owner.

Instead, this happened:

rror[E0499]: cannot borrow `owner` as mutable more than once at a time
  --> src/main.rs:16:13
   |
13 |     let _v = match owner.share() {
   |                    -------------
   |                    |
   |                    first mutable borrow occurs here
   |                    a temporary with access to the first borrow is created here ...
...
16 |             owner.do_something_else();
   |             ^^^^^ second mutable borrow occurs here
...
19 |     };
   |      - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `std::result::Result<std::boxed::Box<dyn std::string::ToString>, ()>`

According to The Rust Reference:Destructors I believe the drop scope should be relative to each match arm, not according to the outer scope. It appears that Rust still wants to drop the Result<_, _> which is already dissolved in the match arm.

Also, if no destructor is involved, the code compiles as expected.

The issue first occurred in gitoxide, and here is theworkaround.

Meta

rustc --version --verbose:

rustc 1.46.0 (04488afe3 2020-08-24)
binary: rustc
commit-hash: 04488afe34512aa4c33566eb16d8c912a3ae04f9
commit-date: 2020-08-24
host: x86_64-apple-darwin
release: 1.46.0
LLVM version: 10.0

rustc +nightly --version --verbose:

rustc 1.48.0-nightly (397b390cc 2020-08-27)
binary: rustc
commit-hash: 397b390cc76ba1d98f80b2a24a371f708dcc9169
commit-date: 2020-08-27
host: x86_64-apple-darwin
release: 1.48.0-nightly
LLVM version: 11.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-destructorsArea: Destructors (`Drop`, …)A-lifetimesArea: Lifetimes / regionsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    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