rust

Cannot use format_args! due to temporary value freed at the end of the statement


I'm trying to construct my own custom LogRecord and pass it into the log crate.

use log::RecordBuilder;

fn main() {
    let msg = format_args!("Completed: {}, Elapsed={:?}", "blah", 20);
    //let msg = format_args!("This is OK");
    let mut builder = RecordBuilder::new();
    let _log_rec = builder
        .args(msg)
        .build();
}

I'm running into a temporary lifetime problem with the call to the args method. The error is

 --> src/main.rs:4:28
  |
4 |     let msg = format_args!("Completed: {}, Elapsed={:?}", "blah", 20);
  |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             - temporary value is freed at the end of this statement
  |                            |
  |                            creates a temporary which is freed while still in use
...
8 |         .args(msg)
  |               --- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

Normally this would be an easy fix - just put the temporary into a local variable. In this case though, I don't understand how to fix it, since I've got everything I can think of into local variables already (and is why I don't think this question is a duplicate of the others). It seems to be something particular to the format_args! macro.

Interestingly, the problem goes away if you don't use any {} placeholders in the call to format_args!().


Solution

  • format_args! is expected to be invoked exactly where the returned value will be used.

    let mut builder = RecordBuilder::new();
    let _log_rec = builder
        .args(format_args!("Completed: {}, Elapsed={:?}", "blah", 20))
        .build();
    

    This is because, as how it's implemented, the macro expands into (among other constructs) a sequence of narrowly scoped values for each of the given parameters, and the Arguments value is created with only a large enough lifetime to capture them.