The problem
I stumbled upon this error when making a RenderPipeline in wgpu:
error[E0716]: temporary value dropped while borrowed
This is a simple problem, and it is easy to fix. The solution is to invoke a let statement to give the temporary value a longer lifetime. In fact, Rust explicitly shows me the solution, which I find a bit amusing. Here's the full error:
Compiling playground v0.0.1 (/playground)
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:19:19
|
19 | targets: &[Some(ColorTargetState {
| ___________________^
20 | | format: format,
21 | | })],
| |___________^ creates a temporary value which is freed while still in use
22 | });
| - temporary value is freed at the end of this statement
23 |
24 | dbg!(fragment);
| -------- borrow later used here
|
help: consider using a `let` binding to create a longer lived value
|
18 ~ let binding = [Some(ColorTargetState {
19 + format: format,
20 + })];
21 ~ let fragment = Some(FragmetState{
22 ~ targets: &binding,
|
For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground` (bin "playground") due to previous error
Here is the code which gives me this error:
(Don't be confused by the enum with only one type, and the structures with only one field. This is a simplified version of my code. I stripped away as much code as I could without removing the error):
#[derive(Debug)]
struct FragmetState<'a> {
targets: &'a [Option<ColorTargetState>]
}
#[derive(Debug)]
struct ColorTargetState {
format: TextureFormat,
}
#[derive(Debug)]
enum TextureFormat{
Default,
}
fn main() {
let format = TextureFormat::Default;
let fragment = Some(FragmetState{
targets: &[Some(ColorTargetState {
format: format,
})],
});
dbg!(fragment);
}
So. To be clear, I do understand what the compiler is saying. The array I've created is a temporary value and therefore doesn't live long enough.
The thing I don't understand is why Rust considers this a temporary variable. In most other cases similar code works just fine, yet this specific example does not.
The real issue how rust doesn't consider other similar examples to have temporary variable. In other words why does all of my other code work, except for this one? Is the compiler doing some magic behind the scenes in order to infer my intent?
Take a look at this code fore example:
#[derive(Debug)]
struct VertexState<'a> {
buffers: &'a [VertexBufferLayout<'a>],
}
#[derive(Debug)]
struct VertexBufferLayout<'a> {
attributes: &'a [VertexAttribute],
}
#[derive(Debug)]
struct VertexAttribute {}
fn main() {
let vertex = VertexState {
buffers: &[VertexBufferLayout {
attributes: &[
VertexAttribute {}
],
}],
};
dbg!(vertex);
}
This code gives me no error, yet it shares many similarities to the earlier code snippit. I'm still creating structs inside of an array slice. I still have nested struct literals. So why does this work while the previous code does not?
What I've discovered.
Going back to the first code snippit, I decided to see what changes med the code compile.
First I tried moving the enum format
directly into the field. Which removes the error:
#[derive(Debug)]
struct FragmetState<'a> {
targets: &'a [Option<ColorTargetState>]
}
#[derive(Debug)]
struct ColorTargetState {
format: TextureFormat,
}
#[derive(Debug)]
enum TextureFormat{
Default,
}
fn main() {
let fragment = Some(FragmetState{
targets: &[Some(ColorTargetState {
format: TextureFormat::Default,
})],
});
dbg!(fragment);
}
The only thing I changed was the removal of let format = TextureFormat::Default;
and addition of format: TextureFormat::Default,
. (I moved the enum directly into the field). To me, this code snippit is equivalent to the erroneous one.
I've also found that the problem only arises when the inner format field is an enum, if it's a struct or an i32 the error disappears.
This code snippit gives me no error:
#[derive(Debug)]
struct FragmetState<'a> {
targets: &'a [Option<ColorTargetState>]
}
#[derive(Debug)]
struct ColorTargetState {
format: i32,
}
fn main() {
let fragment = Some(FragmetState{
targets: &[Some(ColorTargetState {
format: 1,
})],
});
dbg!(fragment);
}
Conclusion
The things I've found is that the error only appears when the inner field is an enum and when the enum has a variable binding before going into the struct.
But even with these examples I'm not clear on what is considered a temporary variable by the compiler. What's so different from these 3 code snippits to the first? I still don't know. Maybe it has something to do with lifetime annotation?