]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/diagnostics.rs
Give an error number for "borrowed data escapes outside of closure"
[rust.git] / src / librustc_mir / diagnostics.rs
index 0c31e5c4da8ac605ca65eb25d1512253f39a2ec7..773064f15dcf0698a7b02aa0a6b5472bea7e72b6 100644 (file)
@@ -665,24 +665,6 @@ fn main() {
 ```
 "##,
 
-E0022: r##"
-Constant functions are not allowed to mutate anything. Thus, binding to an
-argument with a mutable pattern is not allowed. For example,
-
-```compile_fail
-const fn foo(mut x: u8) {
-    // do stuff
-}
-```
-
-Is incorrect because the function body may not mutate `x`.
-
-Remove any mutable bindings from the argument list to fix this error. In case
-you need to mutate the argument, try lazily initializing a global variable
-instead of using a `const fn`, or refactoring the code to a functional style to
-avoid mutation if possible.
-"##,
-
 E0133: r##"
 Unsafe code was used outside of an unsafe function or block.
 
@@ -2261,7 +2243,92 @@ impl<'a> Drop for S<'a> {
 destructor!) could access `s.data` after the end of that shorter
 lifetime, which would again violate the `&mut`-borrow's exclusive
 access.
+"##,
+
+E0716: r##"
+This error indicates that a temporary value is being dropped
+while a borrow is still in active use.
+
+Erroneous code example:
 
+```compile_fail,E0716
+# #![feature(nll)]
+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 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.
+So you might imagine that `let p = bar(&foo())` is equivalent
+to this:
+
+```compile_fail,E0597
+# fn foo() -> i32 { 22 }
+# fn bar(x: &i32) -> &i32 { x }
+let p = {
+  let tmp = foo(); // the temporary
+  bar(&tmp)
+}; // <-- 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 enclosinb
+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());
+```
 "##,
 
 }
@@ -2272,6 +2339,7 @@ impl<'a> Drop for S<'a> {
 //  E0471, // constant evaluation error (in pattern)
 //    E0385, // {} in an aliasable location
     E0493, // destructors cannot be evaluated at compile-time
+    E0521,  // borrowed data escapes outside of closure
     E0524, // two closures require unique access to `..` at the same time
     E0526, // shuffle indices are not constant
     E0594, // cannot assign to {}