Skip to content

E0621 "explicit lifetime required" recommending a perpetual borrow &'a mut Foo<'a> #156682

@kpreid

Description

@kpreid

Code

pub struct Buffer<'a> {
    buf: &'a mut [u8],
}

pub fn foo<'a>(buffer: &mut Buffer<'a>) {
    buffer.buf = &mut buffer.buf[..];
}

Current output

error[E0621]: explicit lifetime required in the type of `buffer`
 --> src/lib.rs:6:5
  |
6 |     buffer.buf = &mut buffer.buf[..];
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
  |
help: add explicit lifetime `'a` to the type of `buffer`
  |
5 | pub fn foo<'a>(buffer: &'a mut Buffer<'a>) {
  |                         ++

Desired output

Ideally, a detailed explanation with a better recommendation:

error: cannot produce a reference with lifetime `'a` using a reborrow
 --> src/lib.rs:6:5
  |
6 |     buffer.buf = &mut buffer.buf[..];
  |     ^^^^^^^^^^   ^^^^ ^^^^^^^^^^ cannot move out of `buffer.buf` because it is behind an `&mut` reference
  |              |      | therefore, this is a reborrow with a shorter lifetime than `'a`
  |              | lifetime `'a` required to assign to field `buf`
  |
help: to modify an `&mut` reference, the original must be moved rather than reborrowed
  |
6 |     buffer.buf = &mut std::mem::take(&mut buffer.buf)[..];
  |                       +++++++++++++++++++           +

Less ideally but easier to implement: simply remove the “help” subdiagnostic, whenever the suggested lifetime already appears in the type being altered. But that’s not very thorough, because “explicit lifetime required” might prompt users to do the same wrong thing on their own initiative.

Rationale and extra context

In almost all cases, &'a mut Foo<'a> is not what the user needs, because the Foo borrows itself forever, and thus can only be used once after this reference is created. The compiler should not recommend creating this type.

Other cases

This incorrect help does not appear if the function parameter is a self parameter:

impl<'a> Buffer<'a> {
    pub fn foo(self: &mut Buffer<'a>) {
        self.buf = &mut self.buf[..];
    }
}

Rust Version

1.95.0, playground

Anything else?

@rustbot label +D-confusing

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.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