Reputation: 30597
I came across this puzzler while trying to answer this question.
How / why does this compile:
#[derive(Debug,Default)]
struct Foo {
i: i32
}
#[derive(Debug)]
struct Bar<'a> {
foo: &'a Foo
}
impl<'a> Default for Bar<'a> {
fn default() -> Self {
Bar {
foo: &Foo{ i: 25 }
}
}
}
fn main() {
let bar : Bar = Default::default();
println!("{:?}", bar);
}
We create an instance of Bar
, which contains a reference to a Foo
, but who owns the Foo
? It was created anonymously within the default()
function, so I was expecting an error saying that the reference to it outlived its scope.
If I change the default()
implementation then I get the expected error:
fn default() -> Self {
let foo = Foo{ i: 25 };
Bar {
foo: &foo
}
}
error[E0515]: cannot return value referencing local variable `foo`
--> src/main.rs:15:9
|
15 | / Bar {
16 | | foo: &foo
| | ---- `foo` is borrowed here
17 | | }
| |_________^ returns a value referencing data owned by the current function
I read the section in the reference pertaining to temporary scopes - I didn't find any case where the scope of a temporary could extend beyond the scope of a function.
Upvotes: 2
Views: 111
Reputation: 60682
This is due to Constant Promotion:
Promotion of a value expression to a
'static
slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g.&None
always has the type&'static Option<_>
, as it contains nothing disallowed).
Upvotes: 1