Skip to content

Variable remains borrowed after match despite neither arm resulting that way #87930

@timotree3

Description

@timotree3

I tried this code:

struct Node {
    next: Option<&'static mut Node>,
}

fn errors(mut node: &mut Node) {
    match &mut node.next {
        Some(next) => {
            node = next
        },
        None => {},
    }
    &mut *node;
}

Compiling it gives the following error:

error[E0499]: cannot borrow `*node` as mutable more than once at a time
  --> src/lib.rs:12:5
   |
5  | fn errors(mut node: &mut Node) {
   |                     - let's call the lifetime of this reference `'1`
6  |     match &mut node.next {
   |           -------------- first mutable borrow occurs here
7  |         Some(next) => {
   |              ---- assignment requires that `node.next` is borrowed for `'1`
...
12 |     &mut *node;
   |     ^^^^^^^^^^ second mutable borrow occurs here

If I add an early return to the Some branch, it still errors:

fn still_errors(mut node: &mut Node) {
    match &mut node.next {
        Some(next) => {
            node = next;
            return
        },
        None => {},
    }
    &mut *node;
}

However if I add an early return to the None branch, it compiles:

fn compiles(mut node: &mut Node) {
    match &mut node.next {
        Some(next) => {
            node = next
        },
        None => return,
    }
    &mut *node;
}

Also, if I change it to use an if, it compiles:

fn also_compiles(mut node: &mut Node) {
    if node.next.is_some() {
        node = &mut *node.next.as_mut().unwrap()
    }
    &mut *node;
}

I would expect all four versions to compile since the third version compiles.

Meta

Occurs on the rust playground on stable 1.54.0, beta 1.55.0-beta.3 (2021-07-31 53fd98c), and 1.56.0-nightly (2021-08-09 ae90dcf)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.fixed-by-poloniusCompiling with `-Zpolonius` fixes this 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