harmic
harmic

Reputation: 30597

Reference to temporary returned from a function

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);
}

Playground

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

Answers (1)

kmdreko
kmdreko

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

Related Questions