Skip to content

Commit

Permalink
Auto merge of #54164 - mikhail-m1:54131, r=pnkfelix
Browse files Browse the repository at this point in the history
add "temporary value borrowed for too long" error

Issue #54131

r? @nikomatsakis
  • Loading branch information
bors committed Sep 26, 2018
2 parents 92aff72 + 2af199d commit 0b2eae7
Show file tree
Hide file tree
Showing 60 changed files with 852 additions and 192 deletions.
6 changes: 3 additions & 3 deletions src/librustc_mir/borrow_check/error_reporting.rs
Expand Up @@ -694,9 +694,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {

let tcx = self.infcx.tcx;
let mut err =
tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(drop_span, "temporary value only lives until here");
tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
err.span_label(proper_span, "creates a temporary which is freed while still in use");
err.span_label(drop_span, "temporary value is freed at the end of this statement");

let explanation = self.explain_why_borrow_contains_point(context, borrow, None);
match explanation {
Expand Down
85 changes: 85 additions & 0 deletions src/librustc_mir/diagnostics.rs
Expand Up @@ -2261,7 +2261,92 @@ that after `demo` finishes excuting, something else (such as the
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());
```
"##,

}
Expand Down
16 changes: 16 additions & 0 deletions src/librustc_mir/util/borrowck_errors.rs
Expand Up @@ -730,6 +730,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {

self.cancel_if_wrong_origin(err, o)
}

fn temporary_value_borrowed_for_too_long(
self,
span: Span,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0716,
"temporary value dropped while borrowed{OGN}",
OGN = o
);

self.cancel_if_wrong_origin(err, o)
}
}

impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr
@@ -0,0 +1,18 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/borrowck-borrow-from-temporary.rs:19:24
|
LL | let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough
| ^^^^^^^^^^ creates a temporary which is freed while still in use
LL | x
LL | }
| - temporary value is freed at the end of this statement
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:8...
--> $DIR/borrowck-borrow-from-temporary.rs:18:8
|
LL | fn foo<'a>() -> &'a isize {
| ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0716`.
@@ -1,10 +1,10 @@
error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:32:20
|
LL | let x = defer(&vec!["Goodbye", "world!"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here
| ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| temporary value does not live long enough
| creates a temporary which is freed while still in use
LL | x.x[0];
| ------ borrow later used here
|
Expand All @@ -13,4 +13,4 @@ LL | x.x[0];

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
For more information about this error, try `rustc --explain E0716`.
8 changes: 4 additions & 4 deletions src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr
@@ -1,10 +1,10 @@
error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/borrowck-borrowed-uniq-rvalue.rs:20:28
|
LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough
| ^^^^^^^^^^^ - temporary value only lives until here
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| temporary value does not live long enough
| creates a temporary which is freed while still in use
...
LL | buggy_map.insert(43, &*tmp);
| --------- borrow later used here
Expand All @@ -13,4 +13,4 @@ LL | buggy_map.insert(43, &*tmp);

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
For more information about this error, try `rustc --explain E0716`.
32 changes: 16 additions & 16 deletions src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr
@@ -1,57 +1,57 @@
error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:21
|
LL | let ref mut x = 1234543; //~ ERROR
| ^^^^^^^ temporary value does not live long enough
| ^^^^^^^ creates a temporary which is freed while still in use
LL | x
LL | }
| - temporary value only lives until here
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:25
|
LL | let (ref mut x, ) = (1234543, ); //~ ERROR
| ^^^^^^^^^^^ temporary value does not live long enough
| ^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | x
LL | }
| - temporary value only lives until here
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:25:11
|
LL | match 1234543 {
| ^^^^^^^ temporary value does not live long enough
| ^^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value only lives until here
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:31:11
|
LL | match (123443,) {
| ^^^^^^^^^ temporary value does not live long enough
| ^^^^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value only lives until here
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0597]: borrowed value does not live long enough
error[E0716]: temporary value dropped while borrowed
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:37:10
|
LL | &mut 1234543 //~ ERROR
| ^^^^^^^ temporary value does not live long enough
| ^^^^^^^ creates a temporary which is freed while still in use
LL | }
| - temporary value only lives until here
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0597`.
For more information about this error, try `rustc --explain E0716`.
@@ -0,0 +1,43 @@
error: `foo` is not yet stable as a const fn
--> $DIR/dont_promote_unstable_const_fn.rs:25:25
|
LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
| ^^^^^
|
= help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable

error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn.rs:28:28
|
LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough
| ^^^^^ creates a temporary which is freed while still in use
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn.rs:32:28
|
LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough
| ^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn.rs:33:26
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | //~^ does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0716`.
@@ -0,0 +1,24 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:18:28
|
LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough
| ^^^^^ creates a temporary which is freed while still in use
LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
|
LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
| ^^^^^ creates a temporary which is freed while still in use
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0716`.
35 changes: 35 additions & 0 deletions src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr
@@ -0,0 +1,35 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/promoted_raw_ptr_ops.rs:14:29
|
LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0716]: temporary value dropped while borrowed
--> $DIR/promoted_raw_ptr_ops.rs:16:30
|
LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error[E0716]: temporary value dropped while borrowed
--> $DIR/promoted_raw_ptr_ops.rs:17:28
|
LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0716`.
14 changes: 14 additions & 0 deletions src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr
@@ -0,0 +1,14 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/transmute-const-promotion.rs:16:37
|
LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) };
| ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | //~^ ERROR value does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0716`.
16 changes: 16 additions & 0 deletions src/test/ui/consts/const-eval/union_promotion.nll.stderr
@@ -0,0 +1,16 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/union_promotion.rs:19:29
|
LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough
| _____________________________^
LL | | Foo { a: &1 }.b == Foo { a: &2 }.b
LL | | };
| |_____^ creates a temporary which is freed while still in use
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0716`.

0 comments on commit 0b2eae7

Please sign in to comment.