Fix temporary value lifetime in serialize_struct - #2950
Conversation
In the 2024 edition of Rust, `serde`s macros for `serialize_with` can
lead to a temporary lifetime error such as:
```
error[E0716]: temporary value dropped while borrowed
--> my-binary/src/main.rs:6:10
|
6 | #[derive(MyDerive)]
| ^^^^^^^-
| | |
| | temporary value is freed at the end of this statement
| creates a temporary value which is freed while still in use
| borrow later used by call
| in this derive macro expansion
|
::: /private/tmp/life/my-project/my-macro/src/lib.rs:6:1
|
6 | pub fn my_derive(_input: TokenStream) -> TokenStream {
| ---------------------------------------------------- in this expansion of `#[derive(MyDerive)]`
|
= note: consider using a `let` binding to create a longer lived value
```
This is because the macro code takes a reference to struct inside of a
block, which then goes out of scope when `serde` passes it to a
function.
To resolve this, we move the reference to outside of the block, to
ensure that the lifetime extends into the function call.
Signed-off-by: Andrew V. Teylu <andrew.teylu@vector.com>
|
For reference, a minimal example that can reproduce the problem is something like: use serde::{Serialize, Serializer};
#[derive(Serialize)]
struct S {
#[serde(serialize_with = "f")]
x: u8,
}
fn f<T, S>(_: &T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_unit()
}which generates code that is (similar to): use std::marker::PhantomData;
trait Error {}
fn takes_reference<T>(_: &T) {}
struct S {
x: u8,
}
impl S {
fn method(&self) {
takes_reference(
{
struct Wrapper<'a> {
value: &'a u8,
phantom: PhantomData<S>,
}
&Wrapper {
value: &self.x,
phantom: PhantomData,
}
}
);
}
}The issue is that the reference is taken against In actual If you compile this with Swapping all of |
dtolnay
left a comment
There was a problem hiding this comment.
Thanks!
This should not make a difference to anyone using the Serialize derive macro because those macro-generated tokens are all spanned with serde_derive's edition, which is 2021. But this PR helps when someone copied macro-generated Serialize code from cargo expand into a 2024-edition crate.
In the 2024 edition of Rust,
serde's macros forserialize_withcan lead to a temporary lifetime error such as:This is because the macro code takes a reference to struct inside of a block, which then goes out of scope when
serdepasses it to a function.To resolve this, we move the reference to outside of the block, to ensure that the lifetime extends into the function call.