Skip to content

Commit

Permalink
Note specific regions involved in 'borrowed data escapes' error
Browse files Browse the repository at this point in the history
Fixes #67007

Currently, a 'borrowed data escapes' error does not mention
the specific lifetime involved (except indirectly through a suggestion
about adding a lifetime bound). We now explain the specific lifetime
relationship that failed to hold, which improves otherwise vague
error messages.
  • Loading branch information
Aaron1011 committed Oct 5, 2021
1 parent 25ec827 commit 3c974ad
Show file tree
Hide file tree
Showing 18 changed files with 209 additions and 39 deletions.
21 changes: 21 additions & 0 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Expand Up @@ -498,6 +498,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
}

// Only show an extra note if we can find an 'error region' for both of the region
// variables. This avoids showing a noisy note that just mentions 'synthetic' regions
// that don't help the user understand the error.
if self.to_error_region(errci.fr).is_some()
&& self.to_error_region(errci.outlived_fr).is_some()
{
let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
fr_region_name.highlight_region_name(&mut diag);
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
outlived_fr_region_name.highlight_region_name(&mut diag);

diag.span_label(
*span,
format!(
"{}requires that `{}` must outlive `{}`",
category.description(),
fr_region_name,
outlived_fr_region_name,
),
);
}
diag
}

Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/async-await/issues/issue-62097.nll.stderr
Expand Up @@ -20,9 +20,15 @@ error[E0521]: borrowed data escapes outside of associated function
--> $DIR/issue-62097.rs:13:9
|
LL | pub async fn run_dummy_fn(&self) {
| ----- `self` is a reference that is only valid in the associated function body
| -----
| |
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
LL | foo(|| self.bar()).await;
| ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here
| ^^^^^^^^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'static`

error: aborting due to 2 previous errors

Expand Down
9 changes: 7 additions & 2 deletions src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
Expand Up @@ -2,9 +2,14 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/dyn-trait.rs:20:5
|
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| - `x` is a reference that is only valid in the function body
| -- - `x` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | static_val(x);
| ^^^^^^^^^^^^^ `x` escapes the function body here
| ^^^^^^^^^^^^^
| |
| `x` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to previous error

Expand Down
13 changes: 11 additions & 2 deletions src/test/ui/issues/issue-16683.nll.stderr
@@ -1,10 +1,19 @@
error[E0521]: borrowed data escapes outside of associated function
--> $DIR/issue-16683.rs:4:9
|
LL | trait T<'a> {
| -- lifetime `'a` defined here
LL | fn a(&'a self) -> &'a bool;
LL | fn b(&self) {
| ----- `self` is a reference that is only valid in the associated function body
| -----
| |
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
LL | self.a();
| ^^^^^^^^ `self` escapes the associated function body here
| ^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'a`

error: aborting due to previous error

Expand Down
13 changes: 11 additions & 2 deletions src/test/ui/issues/issue-17758.nll.stderr
@@ -1,10 +1,19 @@
error[E0521]: borrowed data escapes outside of associated function
--> $DIR/issue-17758.rs:7:9
|
LL | trait Foo<'a> {
| -- lifetime `'a` defined here
LL | fn foo(&'a self);
LL | fn bar(&self) {
| ----- `self` is a reference that is only valid in the associated function body
| -----
| |
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
LL | self.foo();
| ^^^^^^^^^^ `self` escapes the associated function body here
| ^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'a`

error: aborting due to previous error

Expand Down
Expand Up @@ -2,19 +2,29 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/lifetime-bound-will-change-warning.rs:34:5
|
LL | fn test2<'a>(x: &'a Box<dyn Fn() + 'a>) {
| - `x` is a reference that is only valid in the function body
| -- - `x` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | // but ref_obj will not, so warn.
LL | ref_obj(x)
| ^^^^^^^^^^ `x` escapes the function body here
| ^^^^^^^^^^
| |
| `x` escapes the function body here
| argument requires that `'a` must outlive `'static`

error[E0521]: borrowed data escapes outside of function
--> $DIR/lifetime-bound-will-change-warning.rs:39:5
|
LL | fn test2cc<'a>(x: &'a Box<dyn Fn() + 'a>) {
| - `x` is a reference that is only valid in the function body
| -- - `x` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | // same as test2, but cross crate
LL | lib::ref_obj(x)
| ^^^^^^^^^^^^^^^ `x` escapes the function body here
| ^^^^^^^^^^^^^^^
| |
| `x` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to 2 previous errors

Expand Down
Expand Up @@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
|
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
| ------ `cell_a` is a reference that is only valid in the function body
| -- ------ `cell_a` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
LL | |
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | });
| |______^ `cell_a` escapes the function body here
| | ^
| | |
| |______`cell_a` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to previous error

Expand Down
Expand Up @@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
|
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
| ------ `cell_a` is a reference that is only valid in the function body
| -- ------ `cell_a` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | |
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | });
| |______^ `cell_a` escapes the function body here
| | ^
| | |
| |______`cell_a` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to previous error

Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/nll/issue-67007-escaping-data.rs
@@ -0,0 +1,26 @@
// Regression test for issue #67007
// Ensures that we show information about the specific regions involved

#![feature(nll)]

// Covariant over 'a, invariant over 'tcx
struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ());

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn use_it(&self, _: &'tcx ()) {}
}

struct Consumer<'tcx>(&'tcx ());

impl<'tcx> Consumer<'tcx> {
fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
let other = self.use_fcx(fcx); //~ ERROR borrowed data
fcx.use_it(other);
}

fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () {
&()
}
}

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/nll/issue-67007-escaping-data.stderr
@@ -0,0 +1,21 @@
error[E0521]: borrowed data escapes outside of associated function
--> $DIR/issue-67007-escaping-data.rs:17:21
|
LL | impl<'tcx> Consumer<'tcx> {
| ---- lifetime `'tcx` defined here
LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
| -- ----- --- `fcx` is a reference that is only valid in the associated function body
| | |
| | `self` declared here, outside of the associated function body
| lifetime `'a` defined here
LL | let other = self.use_fcx(fcx);
| ^^^^^^^^^^^^^^^^^
| |
| `fcx` escapes the associated function body here
| argument requires that `'a` must outlive `'tcx`
|
= help: consider adding the following bound: `'a: 'tcx`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0521`.
9 changes: 8 additions & 1 deletion src/test/ui/nll/outlives-suggestion-simple.stderr
Expand Up @@ -92,13 +92,20 @@ LL | self.x
error[E0521]: borrowed data escapes outside of associated function
--> $DIR/outlives-suggestion-simple.rs:73:9
|
LL | impl<'a> Foo2<'a> {
| -- lifetime `'a` defined here
LL | // should not produce outlives suggestions to name 'self
LL | fn get_bar(&self) -> Bar2 {
| -----
| |
| `self` declared here, outside of the associated function body
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
LL | Bar2::new(&self)
| ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here
| ^^^^^^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'a`

error: aborting due to 9 previous errors

Expand Down
9 changes: 7 additions & 2 deletions src/test/ui/nll/user-annotations/closure-substs.stderr
Expand Up @@ -28,9 +28,14 @@ error[E0521]: borrowed data escapes outside of closure
--> $DIR/closure-substs.rs:29:9
|
LL | |x: &i32, b: fn(&'static i32)| {
| - `x` is a reference that is only valid in the closure body
| - - let's call the lifetime of this reference `'1`
| |
| `x` is a reference that is only valid in the closure body
LL | b(x);
| ^^^^ `x` escapes the closure body here
| ^^^^
| |
| `x` escapes the closure body here
| argument requires that `'1` must outlive `'static`

error: aborting due to 4 previous errors

Expand Down
Expand Up @@ -15,9 +15,14 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/object-lifetime-default-mybox.rs:31:5
|
LL | fn load2<'a>(ss: &MyBox<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
| -- `ss` is a reference that is only valid in the function body
| -- -- `ss` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | load0(ss)
| ^^^^^^^^^ `ss` escapes the function body here
| ^^^^^^^^^
| |
| `ss` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to 2 previous errors

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/regions/issue-78262.nll.stderr
Expand Up @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure
--> $DIR/issue-78262.rs:14:26
|
LL | let f = |x: &dyn TT| x.func();
| - ^^^^^^^^ `x` escapes the closure body here
| |
| - - ^^^^^^^^
| | | |
| | | `x` escapes the closure body here
| | | argument requires that `'1` must outlive `'static`
| | let's call the lifetime of this reference `'1`
| `x` is a reference that is only valid in the closure body

error: aborting due to previous error
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/regions/issue-78262.polonius.stderr
Expand Up @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure
--> $DIR/issue-78262.rs:14:26
|
LL | let f = |x: &dyn TT| x.func();
| - ^^^^^^^^ `x` escapes the closure body here
| |
| - - ^^^^^^^^
| | | |
| | | `x` escapes the closure body here
| | | argument requires that `'1` must outlive `'static`
| | let's call the lifetime of this reference `'1`
| `x` is a reference that is only valid in the closure body

error: aborting due to previous error
Expand Down
Expand Up @@ -2,10 +2,15 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/region-invariant-static-error-reporting.rs:15:9
|
LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
| - `x` is a reference that is only valid in the function body
| -- - `x` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
LL | let bad = if x.is_some() {
LL | x.unwrap()
| ^^^^^^^^^^ `x` escapes the function body here
| ^^^^^^^^^^
| |
| `x` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to previous error

Expand Down
Expand Up @@ -2,12 +2,17 @@ error[E0521]: borrowed data escapes outside of function
--> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
|
LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
| - - `b` is a reference that is only valid in the function body
| |
| `a` declared here, outside of the function body
| -- -- - - `b` is a reference that is only valid in the function body
| | | |
| | | `a` declared here, outside of the function body
| | lifetime `'b` defined here
| lifetime `'a` defined here
LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
LL | f.method(b);
| ^^^^^^^^^^^ `b` escapes the function body here
| ^^^^^^^^^^^
| |
| `b` escapes the function body here
| argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`

Expand Down

0 comments on commit 3c974ad

Please sign in to comment.