Skip to content

Commit

Permalink
Rollup merge of #90667 - rukai:improve_static_lifetime_diagnostics, r…
Browse files Browse the repository at this point in the history
…=estebank

Improve diagnostics when a static lifetime is expected

Makes progress towards #90600

The diagnostics here were previously entirely removed due to giving a misleading suggestion but if we instead provide an informative label in that same location it should better help the user understand the situation.

I included the example from the issue as it demonstrates an area where the diagnostics are still lacking.
Happy to remove that if its just adding noise atm.
  • Loading branch information
matthiaskrgr authored Nov 17, 2021
2 parents 0734282 + 130b9e9 commit d7b8688
Show file tree
Hide file tree
Showing 26 changed files with 269 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir::intravisit::Visitor;
use rustc_hir::FnRetTy;
use rustc_middle::ty;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
Expand Down Expand Up @@ -48,19 +46,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
return None; // inapplicable
};

// Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
// and can steer users down the wrong path.
if *named == ty::ReStatic {
return None;
}

debug!("try_report_named_anon_conflict: named = {:?}", named);
debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);

let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = (
anon_param_info.param,
anon_param_info.param_ty,
anon_param_info.param_ty_span,
anon_param_info.bound_region,
anon_param_info.is_first,
region_info.def_id,
region_info.is_impl_item,
);
let param = anon_param_info.param;
let new_ty = anon_param_info.param_ty;
let new_ty_span = anon_param_info.param_ty_span;
let br = anon_param_info.bound_region;
let is_first = anon_param_info.is_first;
let scope_def_id = region_info.def_id;
let is_impl_item = region_info.is_impl_item;

match br {
ty::BrAnon(_) => {}
_ => {
Expand All @@ -75,26 +78,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
return None;
}

if let Some((_, fndecl)) = find_anon_type(self.tcx(), anon, &br) {
if self.is_self_anon(is_first, scope_def_id) {
return None;
}

if let FnRetTy::Return(ty) = &fndecl.output {
let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
v.visit_ty(ty);

debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
if sub == &ty::ReStatic
&& v.0.into_iter().any(|t| t.span.desugaring_kind().is_none())
{
// If the failure is due to a `'static` requirement coming from a `dyn` or
// `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
// better in `static_impl_trait`.
debug!("try_report_named_anon_conflict: impl Trait + 'static");
return None;
}
}
if find_anon_type(self.tcx(), anon, &br).is_some()
&& self.is_self_anon(is_first, scope_def_id)
{
return None;
}

let (error_var, span_label_var) = match param.pat.simple_ident() {
Expand All @@ -114,16 +101,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
);

diag.span_label(span, format!("lifetime `{}` required", named));
// Suggesting `'static` is nearly always incorrect, and can steer users
// down the wrong path.
if *named != ty::ReStatic {
diag.span_suggestion(
new_ty_span,
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
new_ty.to_string(),
Applicability::Unspecified,
);
}
diag.span_suggestion(
new_ty_span,
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
new_ty.to_string(),
Applicability::Unspecified,
);

Some(diag)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
error[E0621]: explicit lifetime required in the type of `x`
error[E0521]: borrowed data escapes outside of function
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5
|
LL | fn foo(x: &()) {
| - - let's call the lifetime of this reference `'1`
| |
| `x` is a reference that is only valid in the function body
LL | / bar(|| {
LL | |
LL | | let _ = x;
LL | | })
| |______^ lifetime `'static` required
| | ^
| | |
| |______`x` escapes the function body here
| argument requires that `'1` must outlive `'static`

error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:9
Expand All @@ -31,5 +38,5 @@ LL | bar(move || {

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0373, E0621.
Some errors have detailed explanations: E0373, E0521.
For more information about an error, try `rustc --explain E0373`.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fn bar<F>(blk: F) where F: FnOnce() + 'static {

fn foo(x: &()) {
bar(|| {
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
let _ = x;
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
error[E0621]: explicit lifetime required in the type of `x`
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:9
|
LL | fn foo(x: &()) {
| --- this data with an anonymous lifetime `'_`...
LL | bar(|| {
| _________^
LL | |
LL | | let _ = x;
LL | | })
| |_____^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5
|
LL | bar(|| {
| ^^^ lifetime `'static` required
| ^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0621`.
For more information about this error, try `rustc --explain E0759`.
11 changes: 11 additions & 0 deletions src/test/ui/generator/generator-region-requirements.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: lifetime may not live long enough
--> $DIR/generator-region-requirements.rs:13:51
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| - let's call the lifetime of this reference `'1`
...
LL | GeneratorState::Complete(c) => return c,
| ^ returning this value requires that `'1` must outlive `'static`

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/generator/generator-region-requirements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || {
yield;
x
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
};
loop {
match Pin::new(&mut g).resume(()) {
GeneratorState::Complete(c) => return c,
//~^ ERROR explicit lifetime required
GeneratorState::Yielded(_) => (),
}
}
Expand Down
14 changes: 10 additions & 4 deletions src/test/ui/generator/generator-region-requirements.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:12:51
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/generator-region-requirements.rs:8:9
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- this data with an anonymous lifetime `'_`...
...
LL | x
| ^ ...is captured here...
...
LL | GeneratorState::Complete(c) => return c,
| ^ lifetime `'static` required
| - ...and is required to live as long as `'static` here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0621`.
For more information about this error, try `rustc --explain E0759`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: lifetime may not live long enough
--> $DIR/projection-type-lifetime-mismatch.rs:17:5
|
LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
| - let's call the lifetime of this reference `'1`
LL | x.m()
| ^^^^^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/projection-type-lifetime-mismatch.rs:22:5
|
LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
| - let's call the lifetime of this reference `'1`
LL | x.m()
| ^^^^^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/projection-type-lifetime-mismatch.rs:27:5
|
LL | fn h(x: &()) -> &'static () {
| - let's call the lifetime of this reference `'1`
LL | x.m()
| ^^^^^ returning this value requires that `'1` must outlive `'static`

error: aborting due to 3 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ impl X for () {

fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
x.m()
//~^ ERROR explicit lifetime required
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
}

fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
x.m()
//~^ ERROR explicit lifetime required
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
}

fn h(x: &()) -> &'static () {
x.m()
//~^ ERROR explicit lifetime required
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/projection-type-lifetime-mismatch.rs:17:5
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/projection-type-lifetime-mismatch.rs:17:7
|
LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
| ------------------------------- this data with an anonymous lifetime `'_`...
LL | x.m()
| ^^^^^ lifetime `'static` required
| --^-- ...is captured and required to live as long as `'static` here

error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/projection-type-lifetime-mismatch.rs:22:5
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/projection-type-lifetime-mismatch.rs:22:7
|
LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
| -- this data with an anonymous lifetime `'_`...
LL | x.m()
| ^^^^^ lifetime `'static` required
| --^-- ...is captured and required to live as long as `'static` here

error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/projection-type-lifetime-mismatch.rs:27:5
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/projection-type-lifetime-mismatch.rs:27:7
|
LL | fn h(x: &()) -> &'static () {
| --- this data with an anonymous lifetime `'_`...
LL | x.m()
| ^^^^^ lifetime `'static` required
| --^-- ...is captured and required to live as long as `'static` here

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0621`.
For more information about this error, try `rustc --explain E0759`.
10 changes: 10 additions & 0 deletions src/test/ui/issues/issue-46983.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/issue-46983.rs:2:5
|
LL | fn foo(x: &u32) -> &'static u32 {
| - let's call the lifetime of this reference `'1`
LL | &*x
| ^^^ returning this value requires that `'1` must outlive `'static`

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-46983.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn foo(x: &u32) -> &'static u32 {
&*x
//~^ ERROR explicit lifetime required in the type of `x` [E0621]
//~^ ERROR `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
}

fn main() {}
8 changes: 5 additions & 3 deletions src/test/ui/issues/issue-46983.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
error[E0621]: explicit lifetime required in the type of `x`
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-46983.rs:2:5
|
LL | fn foo(x: &u32) -> &'static u32 {
| ---- this data with an anonymous lifetime `'_`...
LL | &*x
| ^^^ lifetime `'static` required
| ^^^ ...is captured and required to live as long as `'static` here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0621`.
For more information about this error, try `rustc --explain E0759`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error[E0597]: `foo` does not live long enough
--> $DIR/issue-90600-expected-return-static-indirect.rs:7:32
|
LL | let refcell = RefCell::new(&mut foo);
| ^^^^^^^^ borrowed value does not live long enough
LL |
LL | let read = &refcell as &RefCell<dyn Read>;
| -------- cast requires that `foo` is borrowed for `'static`
...
LL | }
| - `foo` dropped here while still borrowed

error: lifetime may not live long enough
--> $DIR/issue-90600-expected-return-static-indirect.rs:9:16
|
LL | fn inner(mut foo: &[u8]) {
| - let's call the lifetime of this reference `'1`
...
LL | let read = &refcell as &RefCell<dyn Read>;
| ^^^^^^^^ cast requires that `'1` must outlive `'static`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0597`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use std::cell::RefCell;
use std::io::Read;

fn main() {}

fn inner(mut foo: &[u8]) {
let refcell = RefCell::new(&mut foo);
//~^ ERROR `foo` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement [E0759]
let read = &refcell as &RefCell<dyn Read>;

read_thing(read);
}

fn read_thing(refcell: &RefCell<dyn Read>) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0759]: `foo` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-90600-expected-return-static-indirect.rs:7:32
|
LL | fn inner(mut foo: &[u8]) {
| ----- this data with an anonymous lifetime `'_`...
LL | let refcell = RefCell::new(&mut foo);
| ^^^^^^^^ ...is captured here...
...
LL | read_thing(read);
| ---- ...and is required to live as long as `'static` here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0759`.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

fn foo(x: &u32) -> &'static u32 {
&*x
//~^ ERROR explicit lifetime required in the type of `x`
//~^ ERROR lifetime may not live long enough
}

fn main() { }
Loading

0 comments on commit d7b8688

Please sign in to comment.