Skip to content

Wrong hint for multiple mutable borrows #164169

Open

Description

@alexkazik

Code

use std::path::PathBuf;

fn main() {}

type Test = Option<(PathBuf, Vec<u8>)>;

fn test1(backend: &mut Vec<Test>) -> Result<(), String> {
    let mut backend2 = Vec::new();
    for b in backend {
        backend2.push(match b {
            None => None,
            Some((file, bytes)) => Some((file.as_path(), bytes)),
        });
    }

    loop {
        test2(&mut backend2)?;
    }
}

fn test2<'a, P, C>(disks: &'a mut [Option<(P, &'a mut Vec<u8>)>]) -> Result<C, String> {
    todo!()
}

fn test3<'a, P, C>(disks: &'a mut [Option<(P, &'a mut Vec<u8>)>]) -> Result<C, String> {
    loop {
        test2(disks)?;
    }
}

Current output

error[E0499]: cannot borrow `backend2` as mutable more than once at a time
  --> atari-sio-link-cli/src/main.rs:17:15
   |
10 |         backend2.push(match b {
   |         -------- first borrow used here, in later iteration of loop
...
17 |         test2(&mut backend2)?;
   |               ^^^^^^^^^^^^^ `backend2` was mutably borrowed here in the previous iteration of the loop

error[E0499]: cannot borrow `*disks` as mutable more than once at a time
  --> atari-sio-link-cli/src/main.rs:27:15
   |
25 | fn test3<'a, P, C>(disks: &'a mut [Option<(P, &'a mut Vec<u8>)>]) -> Result<C, String> {
   |          -- lifetime `'a` defined here
26 |     loop {
27 |         test2(disks)?;
   |         ------^^^^^-
   |         |     |
   |         |     `*disks` was mutably borrowed here in the previous iteration of the loop
   |         argument requires that `*disks` is borrowed for `'a`

Desired output

Rationale and extra context

I guess it's the same problem in both cases though the first reports the problem outside the loop.

Other cases

Rust Version

rustc 1.98.1 (48a229cea 2026-09-01)
binary: rustc
commit-hash: 48a229ceaefd4985c50990b14116b6d856af0985
commit-date: 2026-09-01
host: aarch64-apple-darwin
release: 1.98.1
LLVM version: 22.1.8

Anything else?

No response

Activity

  1. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Oct 11, 2026
  2. maxdexh commented on Oct 11, 2026

    @maxdexh
    Member

    I don't understand what you're saying the problem is. What do you expect to happen?

  3. alexkazik commented on Oct 11, 2026

    @alexkazik
    Author

    If both are the same errors (which I guess but are not totally sure) then I'd expect that both messages tell me that the function in the loop is where the problem is, but the error in test1 refers to a use outside of the loop.

  4. maxdexh commented on Oct 11, 2026

    @maxdexh
    Member

    Hm yeah, this is strange. The usage of backend2 in the for loop should not have any relevance to the error later on.
    The same thing doesn't happen when unwrapping the for loop (e.g. by just matching &mut backend[0] without a loop).

  5. added
    D-confusingDiagnostics: Confusing error or lint that should be reworked.
    D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.
    on Oct 11, 2026
  6. estebank commented on Oct 12, 2026

    @estebank
    Contributor

    Just FYI, signatures like disks: &'a mut [Option<(P, &'a mut Vec<u8>)>] are almost never what you want, the inner borrow and the outer borrow should have different lifetimes.

  7. alexkazik commented on Oct 12, 2026

    @alexkazik
    Author

    Thanks, luckily I already figured that out (before posting).

  8. xizheyin commented on Oct 16, 2026

    @xizheyin
    Member

    Indeed strange, the first borrow backend2.push already released when loop, but the error points to it.

  9. self-assigned this
    on Oct 16, 2026
  10. added 3 commits that reference this issue on Oct 16, 2026
  11. added 2 commits that reference this issue on Oct 17, 2026
  12. added 2 commits that reference this issue on Oct 17, 2026
  13. added a commit that references this issue on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions