Point at capture points for non-'static reference crossing a yield point

```
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> $DIR/issue-72312.rs:10:24
   |
LL |     pub async fn start(&self) {
   |                        ^^^^^ this data with an anonymous lifetime `'_`...
...
LL |         require_static(async move {
   |         -------------- ...is required to live as long as `'static` here...
LL |             &self;
   |             ----- ...and is captured here
   |
note: `'static` lifetime requirement introduced by this trait bound
  --> $DIR/issue-72312.rs:2:22
   |
LL | fn require_static<T: 'static>(val: T) -> T {
   |                      ^^^^^^^

error: aborting due to previous error

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

Fix #72312.
This commit is contained in:
Esteban Kuber 2021-10-10 10:37:57 +00:00
parent e6b883c74f
commit d10fe26f39
12 changed files with 212 additions and 23 deletions

View File

@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
cause.clone(),
placeholder_region,
vec![],
),
),
(Some(error_region), _) => NiceRegionError::new(

View File

@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
_,
) => {
if sub_r.is_placeholder() {
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors.sort_by_key(|u| match *u {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
});
errors

View File

@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
Some((origin.span(), sub, sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),

View File

@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,

View File

@ -23,7 +23,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
let tcx = self.tcx();
let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
RegionResolutionError::SubSupConflict(
_,
var_origin,
@ -31,8 +31,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
spans,
) if **sub_r == RegionKind::ReStatic => {
(var_origin, sub_origin, sub_r, sup_origin, sup_r)
(var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
}
RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
@ -123,15 +124,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
param_name,
lifetime,
);
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) {
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
// The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
// This avoids the following:
//
// LL | pub async fn run_dummy_fn(&self) {
// | ^^^^^
// | |
// | this data with an anonymous lifetime `'_`...
// | ...is captured here...
(false, sup_origin.span())
} else {
(true, param.param_ty_span)
};
err.span_label(capture_point, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param);
// We try to make the output have fewer overlapping spans if possible.
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
&& sup_origin.span() != return_sp
{
// FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
// Customize the spans and labels depending on their relative order so
// that split sentences flow correctly.
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
@ -152,11 +169,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// | ---- ^
err.span_label(
sup_origin.span(),
"...is captured here, requiring it to live as long as `'static`",
&format!(
"...is captured here, requiring it to live as long as `'static`{}",
if spans.is_empty() { "" } else { "..." },
),
);
} else {
err.span_label(sup_origin.span(), "...is captured here...");
if return_sp < sup_origin.span() {
if return_sp < sup_origin.span() && mention_capture {
err.span_label(sup_origin.span(), "...is captured here...");
err.span_note(
return_sp,
"...and is required to live as long as `'static` here",
@ -164,17 +184,46 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} else {
err.span_label(
return_sp,
"...and is required to live as long as `'static` here",
&format!(
"...is required to live as long as `'static` here{}",
if spans.is_empty() { "" } else { "..." },
),
);
if mention_capture {
let span = sup_origin.span();
let msg = if spans.iter().any(|sp| *sp > span) {
"...is captured here..."
} else {
"...and is captured here"
};
err.span_label(span, msg);
}
}
}
} else {
err.span_label(
return_sp,
"...is captured and required to live as long as `'static` here",
&format!(
"...is captured and required to live as long as `'static` here{}",
if spans.is_empty() { "" } else { "..." },
),
);
}
for span in spans {
let msg =
format!("...and is captured here{}", if mention_capture { " too" } else { "" });
if span.overlaps(return_sp) {
err.span_note(*span, &msg);
} else {
err.span_label(*span, &msg);
}
}
if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound");
}
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None;

View File

@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
_sub,
sup_origin,
_sup,
_,
) = error.clone()
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {

View File

@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
use rustc_span::Span;
use std::fmt;
/// This function performs lexical region resolution given a complete
@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>,
SubregionOrigin<'tcx>,
Region<'tcx>,
Vec<Span>,
),
/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
@ -144,8 +146,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let graph = self.construct_graph();
self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
let captures = self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors, captures);
var_data
}
@ -443,9 +445,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
&self,
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
) -> Vec<Span> {
let mut captures = vec![];
for (constraint, origin) in &self.data.constraints {
debug!(?constraint, ?origin);
if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) =
(constraint, origin)
{
captures.push(*sp);
}
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
// Expansion will ensure that these constraints hold. Ignore.
@ -515,6 +524,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sub,
));
}
captures
}
/// Go over the variables that were declared to be error variables
@ -524,6 +534,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
var_data: &LexicalRegionResolutions<'tcx>,
graph: &RegionGraph<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
captures: Vec<Span>,
) {
debug!("collect_var_errors, var_data = {:#?}", var_data.values);
@ -567,7 +578,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// if this rule starts to create problems we'll
// have to revisit this portion of the code and
// think hard about it. =) -- nikomatsakis
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
self.collect_error_for_expanding_node(
graph,
&mut dup_vec,
node_vid,
errors,
&captures,
);
}
}
}
@ -621,6 +638,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
captures: &[Span],
) {
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
@ -667,6 +685,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sup: {:?}",
origin, node_idx, lower_bound.region, upper_bound.region
);
let mut capture_spans: Vec<Span> = captures.iter().cloned().collect();
// Below, one span expects `&Span` and the other `&mut Span`, hence the dupes.
capture_spans.sort_by_key(|span| (span.lo(), span.hi()));
capture_spans.dedup_by_key(|span| (span.lo(), span.hi()));
errors.push(RegionResolutionError::SubSupConflict(
node_idx,
origin,
@ -674,6 +697,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
lower_bound.region,
upper_bound.origin.clone(),
upper_bound.region,
capture_spans,
));
return;
}

View File

@ -2,12 +2,20 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
| ^^^^^
| |
| this data with an anonymous lifetime `'_`...
| ...is captured here...
| ^^^^^ this data with an anonymous lifetime `'_`...
LL | foo(|| self.bar()).await;
| --- ...and is required to live as long as `'static` here
| --- ...is required to live as long as `'static` here...
|
note: ...and is captured here
--> $DIR/issue-62097.rs:13:9
|
LL | foo(|| self.bar()).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: `'static` lifetime requirement introduced by this trait bound
--> $DIR/issue-62097.rs:4:19
|
LL | F: FnOnce() + 'static
| ^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,19 @@
// edition:2018
fn require_static<T: 'static>(val: T) -> T {
//~^ NOTE 'static` lifetime requirement introduced by this trait bound
val
}
struct Problem;
impl Problem {
pub async fn start(&self) { //~ ERROR E0759
//~^ NOTE this data with an anonymous lifetime `'_`
//~| NOTE in this expansion of desugaring of `async` block or function
require_static(async move { //~ NOTE ...is required to live as long as `'static` here
&self; //~ NOTE ...and is captured here
});
}
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-72312.rs:10:24
|
LL | pub async fn start(&self) {
| ^^^^^ this data with an anonymous lifetime `'_`...
...
LL | require_static(async move {
| -------------- ...is required to live as long as `'static` here...
LL | &self;
| ----- ...and is captured here
|
note: `'static` lifetime requirement introduced by this trait bound
--> $DIR/issue-72312.rs:2:22
|
LL | fn require_static<T: 'static>(val: T) -> T {
| ^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0759`.

View File

@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
y.get_b() // ERROR
}
fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
<_ as Bar>::get_b(x) // ERROR
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
}
fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
<_ as Bar<'_, '_>>::get_b(x) // ERROR
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
}
fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
let y = x as &dyn Bar<'_, '_>;
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
y.get_b(); // ERROR
let z = y;
z.get_b() // ERROR
}
fn main() {}

View File

@ -39,9 +39,53 @@ LL | let y = x as &dyn Bar<'_, '_>;
| ...is captured here...
LL |
LL | y.get_b() // ERROR
| --------- ...and is required to live as long as `'static` here
| --------- ...is required to live as long as `'static` here...
|
note: ...and is captured here too
--> $DIR/type-checking-test-4.rs:29:5
|
LL | y.get_b() // ERROR
| ^
error: aborting due to 3 previous errors
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/type-checking-test-4.rs:33:5
|
LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ------------ this data with lifetime `'a`...
LL | <_ as Bar>::get_b(x) // ERROR
| ^^^^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/type-checking-test-4.rs:38:15
|
LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ------------ this data with lifetime `'a`...
LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR
| ----------^^---------------- ...is captured and required to live as long as `'static` here
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/type-checking-test-4.rs:43:27
|
LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
| ------------ this data with lifetime `'a`...
LL | let y = x as &dyn Bar<'_, '_>;
| - ^^
| |
| ...is captured here...
LL |
LL | y.get_b(); // ERROR
| - ...and is captured here too
LL | let z = y;
LL | z.get_b() // ERROR
| --------- ...is required to live as long as `'static` here...
|
note: ...and is captured here too
--> $DIR/type-checking-test-4.rs:47:5
|
LL | z.get_b() // ERROR
| ^
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0759.
For more information about an error, try `rustc --explain E0308`.