47

Why does this code compile?

fn get_iter() -> impl Iterator<Item = i32> {
    [1, 2, 3].iter().map(|&i| i)
}

fn main() {
    let _it = get_iter();
}

[1, 2, 3] is a local variable and iter() borrows it. This code should not compile because the returned value holds a reference to a local variable.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Boiethios
  • 38,438
  • 19
  • 134
  • 183

1 Answers1

64

In your example, [1, 2, 3] is not treated as local variable, but as static one!

Let's take a look at this code:

fn foo() -> &'static [i32] {
    &[1, 2, 3]
}

This works!

Some time ago, RFC 1414: Rvalue Static Promotion was merged: "Promote constexpr rvalues to values in static memory instead of stack slots". This means that basically all literals you write can live forever. Thus, things like let _: &'static i32 = &42; also work!

If we avoid using a literal array, we can see the expected error:

fn bar() -> impl Iterator<Item = i32> {
    vec![1, 2, 3].iter().map(|&i| i)
}

Here we get the "v does not live long enough" error.

This isn't limited to integers or arrays; it applies broadly to any literal that is composed solely of literals:

fn promote_integer() -> &'static i32 {
    &42
}
fn promote_float() -> &'static f64 {
    &42.42
}
fn promote_str() -> &'static str {
    "Hello World!"
}
struct Foo(char);

fn promote_struct() -> &'static Foo {
    &Foo('x')
}

Beyond literals, this also works for a tiny number of functions in the standard library, but these were likely a mistake. Deciding on if the result of arbitrary const functions can be automatically promoted to static is still an open topic.

hellow
  • 12,430
  • 7
  • 56
  • 79
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • It seems that the `const` variables are obsolete :p – Boiethios May 15 '18 at 08:09
  • 1
    @Boiethios that's an interesting idea. Have you found discuss on that that you could link? – Cosmo May 15 '18 at 08:14
  • @Cosmo I saw somewhere that (maybe) one day, the `const` functions could be detected by the compiler without any hint. However, nothing was said about `const` variables, and I do not find any link right now. – Boiethios May 15 '18 at 08:17
  • 6
    @Boiethios They are not obsolete. This only works for literals. Sometimes you need a const that must be computed. – Peter Hall May 15 '18 at 09:53
  • @PeterHall Hum, you are right; but in theory, the compiler could know without hint what is `const` and what isn't. – Boiethios May 15 '18 at 10:03
  • 4
    @Boiethios There are some downsides to storing data in static memory, especially if the data is large, and not required for the full lifespan of the program. There are definitely times when you should have to opt in to the behaviour. – Peter Hall May 15 '18 at 10:05
  • Does the use of `&42` force the compiler to store `42` in the static memory instead of inlining it? – Alexey Apr 18 '20 at 14:36
  • 2
    @Alexey Yes, that's what the language model says. However, the optimizer can still inline the value later anyway. – Lukas Kalbertodt Apr 20 '20 at 07:51