Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve diagnostics when a static lifetime is expected #90667

Merged
merged 1 commit into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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