confusing error message saying variable must be valid for anonymous lifetime that it appears to live long enough for

fc5579d
Opened by L. David Baron at 2023-06-05 12:33:10

I initially raised this on twitter without a reduced testcase, and @SimonSapin suggested I file an issue because the error message could be improved.

A reasonably-reduced testcase for this error is the following code:

pub struct IrcServer {
    options: String,
}

impl IrcServer {
    fn new() -> IrcServer {
        IrcServer { options: String::from("test") }
    }

    fn options(&self) -> &String {
        &self.options
    }
}

pub fn main_loop_iteration(server: IrcServer, irc_state: &mut IRCState) {
    let options = server.options();
    handle_bot_command(&server, options, irc_state)
}

fn handle_bot_command<'opts>(server: &IrcServer,
                             options: &'opts String,
                             irc_state: &mut IRCState<'opts>) {
}

pub struct IRCState<'opts> {
    options: &'opts String,
}

impl<'opts> IRCState<'opts> {
    fn new(options_: &'opts String) -> IRCState<'opts> {
        IRCState { options: options_ }
    }
}

which, when compiled with rustc --crate-type lib lib.rs gives the following error:

error: `server` does not live long enough
  --> lib.rs:16:19
   |
16 |     let options = server.options();
   |                   ^^^^^^ does not live long enough
17 |     handle_bot_command(&server, options, irc_state)
18 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #2 defined on the body at 15:72...
  --> lib.rs:15:73
   |
15 |   pub fn main_loop_iteration(server: IrcServer, irc_state: &mut IRCState) {
   |  _________________________________________________________________________^ starting here...
16 | |     let options = server.options();
17 | |     handle_bot_command(&server, options, irc_state)
18 | | }
   | |_^ ...ending here

error: aborting due to previous error

This error is particularly confusing because it looks like the borrowed value is valid for the anonymous lifetime being pointed to; the "borrowed value only lives until here" points to the same point as the "...ending here".

The way to fix the code is with lifetime parameters and passing options in from the caller, i.e., to change the code to be:

pub struct IrcServer {
    options: String,
}

impl IrcServer {
    fn new() -> IrcServer {
        IrcServer { options: String::from("test") }
    }

    fn options(&self) -> &String {
        &self.options
    }
}

pub fn main_loop_iteration<'opts>(server: IrcServer,
                                  options: &'opts String,
                                  irc_state: &mut IRCState<'opts>) {
    handle_bot_command(&server, options, irc_state)
}

fn handle_bot_command<'opts>(server: &IrcServer,
                             options: &'opts String,
                             irc_state: &mut IRCState<'opts>) {
}

pub struct IRCState<'opts> {
    options: &'opts String,
}

impl<'opts> IRCState<'opts> {
    fn new(options_: &'opts String) -> IRCState<'opts> {
        IRCState { options: options_ }
    }
}

but it required stepping away from the problem for a bit and coming back to it later to recognize that.

  1. So actually, I think the problem here is that the IrcState struct is indicated as being borrowed from the server, which leads to the problem -- server will go out of scope in main_loop_iteration while still being borrowed by the irc_state struct. The message can be improved, though.

    Mark Rousskov at 2017-06-22 13:21:42

  2. Current error:

    error[[E0597]](https://doc.rust-lang.org/nightly/error_codes/E0597.html): `server` does not live long enough
      --> src/lib.rs:16:19
       |
    15 | pub fn main_loop_iteration(server: IrcServer, irc_state: &mut IRCState) {
       |                            ------             --------- has type `&mut IRCState<'1>`
       |                            |
       |                            binding `server` declared here
    16 |     let options = server.options();
       |                   ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
    17 |     handle_bot_command(&server, options, irc_state)
       |     ----------------------------------------------- argument requires that `server` is borrowed for `'1`
    18 | }
       | - `server` dropped here while still borrowed
    

    Dylan DPC at 2023-06-05 12:33:10