summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_error_codes/src/error_codes/E0716.md
blob: c3546cd744f7b6be9527aa18cfc3eb1d0805aa74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
A temporary value is being dropped while a borrow is still in active use.

Erroneous code example:

```compile_fail,E0716
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let p = bar(&foo());
         // ------ creates a temporary
let q = *p;
```

Here, the expression `&foo()` is borrowing the expression `foo()`. As `foo()` is
a call to a function, and not the name of a variable, this creates a
**temporary** -- that temporary stores the return value from `foo()` so that it
can be borrowed. You could imagine that `let p = bar(&foo());` is equivalent to
the following, which uses an explicit temporary variable.

Erroneous code example:

```compile_fail,E0597
# fn foo() -> i32 { 22 }
# fn bar(x: &i32) -> &i32 { x }
let p = {
  let tmp = foo(); // the temporary
  bar(&tmp) // error: `tmp` does not live long enough
}; // <-- tmp is freed as we exit this block
let q = p;
```

Whenever a temporary is created, it is automatically dropped (freed) according
to fixed rules. Ordinarily, the temporary is dropped at the end of the enclosing
statement -- in this case, after the `let`. This is illustrated in the example
above by showing that `tmp` would be freed as we exit the block.

To fix this problem, you need to create a local variable to store the value in
rather than relying on a temporary. For example, you might change the original
program to the following:

```
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let value = foo(); // dropped at the end of the enclosing block
let p = bar(&value);
let q = *p;
```

By introducing the explicit `let value`, we allocate storage that will last
until the end of the enclosing block (when `value` goes out of scope). When we
borrow `&value`, we are borrowing a local variable that already exists, and
hence no temporary is created.

Temporaries are not always dropped at the end of the enclosing statement. In
simple cases where the `&` expression is immediately stored into a variable, the
compiler will automatically extend the lifetime of the temporary until the end
of the enclosing block. Therefore, an alternative way to fix the original
program is to write `let tmp = &foo()` and not `let tmp = foo()`:

```
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let value = &foo();
let p = bar(value);
let q = *p;
```

Here, we are still borrowing `foo()`, but as the borrow is assigned directly
into a variable, the temporary will not be dropped until the end of the
enclosing block. Similar rules apply when temporaries are stored into aggregate
structures like a tuple or struct:

```
// Here, two temporaries are created, but
// as they are stored directly into `value`,
// they are not dropped until the end of the
// enclosing block.
fn foo() -> i32 { 22 }
let value = (&foo(), &foo());
```