mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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:
parent
e6b883c74f
commit
d10fe26f39
@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
error_region,
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
vec![],
|
||||
),
|
||||
),
|
||||
(Some(error_region), _) => NiceRegionError::new(
|
||||
|
@ -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
|
||||
|
@ -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)),
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
19
src/test/ui/async-await/issues/issue-72312.rs
Normal file
19
src/test/ui/async-await/issues/issue-72312.rs
Normal 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() {}
|
20
src/test/ui/async-await/issues/issue-72312.stderr
Normal file
20
src/test/ui/async-await/issues/issue-72312.stderr
Normal 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`.
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user