Assignment requires that `'1` must outlive `'2`

struct BackendState<'s> {
    storage: Storage,
    config: Config<'s>,
}
struct Storage {}
struct Config<'s> {
    engine: Engine<'s>,
}
struct Engine<'s> {
    storage: &'s Storage,
}

impl BackendState<'_> {
    fn update_config(&mut self) {
        self.storage = Storage {};
        let engine = Engine {
            storage: &self.storage,
        };
        self.config = Config { engine };
    }
}

(Playground)

Errors with:

error: lifetime may not live long enough
  --> src/lib.rs:19:9
   |
14 |     fn update_config(&mut self) {
   |                      ---------
   |                      |
   |                      let's call the lifetime of this reference `'1`
   |                      has type `&mut BackendState<'2>`
...
19 |         self.config = Config { engine };
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`

I know how to fix this, by using &'s mut self (see here). I'm trying to understand the error message.

IIUC the error message suggests that self of lifetime '1, references a BackendState which contains references of lifetime '2. Why does the self reference have to live longer than the references in BackendState for the assignment to be valid? If the '1 is shorter than '2 then the references in BackendState will still be valid won't they? Whereas if '1 outlives '2 couldn't self point at invalid references (ie: use after free)? What am I missing?

Assume the compiler didn't error out. Consider this code:

let mut s1: BackendState = ...;
s1.update_config();
let s2 = s1;

The final assignment is a move. '1 has now ended, but '2 (aka 's) is still alive and is pointing at a dead object with lifetime '1: s1.storage.

1 Like

This is what we call a self-referential struct. There are ways to get the borrow checker to allow self-referential structs (your fixed code), but this causes the object to become immovable.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.