]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_error_codes/src/error_codes/E0716.md
Auto merge of #82747 - JohnTitor:pin-es-check-version, r=Mark-Simulacrum
[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 this:
18
19 ```compile_fail,E0597
20 # fn foo() -> i32 { 22 }
21 # fn bar(x: &i32) -> &i32 { x }
22 let p = {
23   let tmp = foo(); // the temporary
24   bar(&tmp)
25 }; // <-- tmp is freed as we exit this block
26 let q = p;
27 ```
28
29 Whenever a temporary is created, it is automatically dropped (freed) according
30 to fixed rules. Ordinarily, the temporary is dropped at the end of the enclosing
31 statement -- in this case, after the `let`. This is illustrated in the example
32 above by showing that `tmp` would be freed as we exit the block.
33
34 To fix this problem, you need to create a local variable to store the value in
35 rather than relying on a temporary. For example, you might change the original
36 program to the following:
37
38 ```
39 fn foo() -> i32 { 22 }
40 fn bar(x: &i32) -> &i32 { x }
41 let value = foo(); // dropped at the end of the enclosing block
42 let p = bar(&value);
43 let q = *p;
44 ```
45
46 By introducing the explicit `let value`, we allocate storage that will last
47 until the end of the enclosing block (when `value` goes out of scope). When we
48 borrow `&value`, we are borrowing a local variable that already exists, and
49 hence no temporary is created.
50
51 Temporaries are not always dropped at the end of the enclosing statement. In
52 simple cases where the `&` expression is immediately stored into a variable, the
53 compiler will automatically extend the lifetime of the temporary until the end
54 of the enclosing block. Therefore, an alternative way to fix the original
55 program is to write `let tmp = &foo()` and not `let tmp = foo()`:
56
57 ```
58 fn foo() -> i32 { 22 }
59 fn bar(x: &i32) -> &i32 { x }
60 let value = &foo();
61 let p = bar(value);
62 let q = *p;
63 ```
64
65 Here, we are still borrowing `foo()`, but as the borrow is assigned directly
66 into a variable, the temporary will not be dropped until the end of the
67 enclosing block. Similar rules apply when temporaries are stored into aggregate
68 structures like a tuple or struct:
69
70 ```
71 // Here, two temporaries are created, but
72 // as they are stored directly into `value`,
73 // they are not dropped until the end of the
74 // enclosing block.
75 fn foo() -> i32 { 22 }
76 let value = (&foo(), &foo());
77 ```