]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_error_codes/src/error_codes/E0716.md
Rollup merge of #92310 - ehuss:rustdoc-ice, r=estebank
[rust.git] / compiler / rustc_error_codes / src / error_codes / E0716.md
1 A temporary value is being dropped while a borrow is still in active use.
2
3 Erroneous code example:
4
5 ```compile_fail,E0716
6 fn foo() -> i32 { 22 }
7 fn bar(x: &i32) -> &i32 { x }
8 let p = bar(&foo());
9          // ------ creates a temporary
10 let q = *p;
11 ```
12
13 Here, the expression `&foo()` is borrowing the expression `foo()`. As `foo()` is
14 a call to a function, and not the name of a variable, this creates a
15 **temporary** -- that temporary stores the return value from `foo()` so that it
16 can be borrowed. You could imagine that `let p = bar(&foo());` is equivalent to
17 the following, which uses an explicit temporary variable.
18
19 Erroneous code example:
20
21 ```compile_fail,E0597
22 # fn foo() -> i32 { 22 }
23 # fn bar(x: &i32) -> &i32 { x }
24 let p = {
25   let tmp = foo(); // the temporary
26   bar(&tmp) // error: `tmp` does not live long enough
27 }; // <-- tmp is freed as we exit this block
28 let q = p;
29 ```
30
31 Whenever a temporary is created, it is automatically dropped (freed) according
32 to fixed rules. Ordinarily, the temporary is dropped at the end of the enclosing
33 statement -- in this case, after the `let`. This is illustrated in the example
34 above by showing that `tmp` would be freed as we exit the block.
35
36 To fix this problem, you need to create a local variable to store the value in
37 rather than relying on a temporary. For example, you might change the original
38 program to the following:
39
40 ```
41 fn foo() -> i32 { 22 }
42 fn bar(x: &i32) -> &i32 { x }
43 let value = foo(); // dropped at the end of the enclosing block
44 let p = bar(&value);
45 let q = *p;
46 ```
47
48 By introducing the explicit `let value`, we allocate storage that will last
49 until the end of the enclosing block (when `value` goes out of scope). When we
50 borrow `&value`, we are borrowing a local variable that already exists, and
51 hence no temporary is created.
52
53 Temporaries are not always dropped at the end of the enclosing statement. In
54 simple cases where the `&` expression is immediately stored into a variable, the
55 compiler will automatically extend the lifetime of the temporary until the end
56 of the enclosing block. Therefore, an alternative way to fix the original
57 program is to write `let tmp = &foo()` and not `let tmp = foo()`:
58
59 ```
60 fn foo() -> i32 { 22 }
61 fn bar(x: &i32) -> &i32 { x }
62 let value = &foo();
63 let p = bar(value);
64 let q = *p;
65 ```
66
67 Here, we are still borrowing `foo()`, but as the borrow is assigned directly
68 into a variable, the temporary will not be dropped until the end of the
69 enclosing block. Similar rules apply when temporaries are stored into aggregate
70 structures like a tuple or struct:
71
72 ```
73 // Here, two temporaries are created, but
74 // as they are stored directly into `value`,
75 // they are not dropped until the end of the
76 // enclosing block.
77 fn foo() -> i32 { 22 }
78 let value = (&foo(), &foo());
79 ```