Skip to content

Commit d10fe26

Browse files
committed
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.
1 parent e6b883c commit d10fe26

File tree

12 files changed

+212
-23
lines changed

12 files changed

+212
-23
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
368368
error_region,
369369
cause.clone(),
370370
placeholder_region,
371+
vec![],
371372
),
372373
),
373374
(Some(error_region), _) => NiceRegionError::new(

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
384384
sub_r,
385385
sup_origin,
386386
sup_r,
387+
_,
387388
) => {
388389
if sub_r.is_placeholder() {
389390
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
@@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
464465
errors.sort_by_key(|u| match *u {
465466
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
466467
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
467-
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
468+
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
468469
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
469470
});
470471
errors

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
6767
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
6868
match (&self.error, self.regions) {
6969
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
70-
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
70+
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
7171
Some((origin.span(), sub, sup))
7272
}
7373
(None, Some((span, sub, sup))) => Some((span, sub, sup)),

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
3434
sub_placeholder @ ty::RePlaceholder(_),
3535
_,
3636
sup_placeholder @ ty::RePlaceholder(_),
37+
_,
3738
)) => self.try_report_trait_placeholder_mismatch(
3839
Some(self.tcx().mk_region(ty::ReVar(*vid))),
3940
cause,
@@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
4950
sub_placeholder @ ty::RePlaceholder(_),
5051
_,
5152
_,
53+
_,
5254
)) => self.try_report_trait_placeholder_mismatch(
5355
Some(self.tcx().mk_region(ty::ReVar(*vid))),
5456
cause,
@@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
6466
_,
6567
_,
6668
sup_placeholder @ ty::RePlaceholder(_),
69+
_,
6770
)) => self.try_report_trait_placeholder_mismatch(
6871
Some(self.tcx().mk_region(ty::ReVar(*vid))),
6972
cause,
@@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
7982
_,
8083
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
8184
sup_placeholder @ ty::RePlaceholder(_),
85+
_,
8286
)) => self.try_report_trait_placeholder_mismatch(
8387
Some(self.tcx().mk_region(ty::ReVar(*vid))),
8488
cause,

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs

+59-10
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2323
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
2424
debug!("try_report_static_impl_trait(error={:?})", self.error);
2525
let tcx = self.tcx();
26-
let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
26+
let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
2727
RegionResolutionError::SubSupConflict(
2828
_,
2929
var_origin,
3030
sub_origin,
3131
sub_r,
3232
sup_origin,
3333
sup_r,
34+
spans,
3435
) if **sub_r == RegionKind::ReStatic => {
35-
(var_origin, sub_origin, sub_r, sup_origin, sup_r)
36+
(var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
3637
}
3738
RegionResolutionError::ConcreteFailure(
3839
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
@@ -123,15 +124,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
123124
param_name,
124125
lifetime,
125126
);
126-
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
127+
128+
let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) {
129+
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
130+
// The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
131+
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
132+
//
133+
// This avoids the following:
134+
//
135+
// LL | pub async fn run_dummy_fn(&self) {
136+
// | ^^^^^
137+
// | |
138+
// | this data with an anonymous lifetime `'_`...
139+
// | ...is captured here...
140+
(false, sup_origin.span())
141+
} else {
142+
(true, param.param_ty_span)
143+
};
144+
err.span_label(capture_point, &format!("this data with {}...", lifetime));
145+
127146
debug!("try_report_static_impl_trait: param_info={:?}", param);
128147

129148
// We try to make the output have fewer overlapping spans if possible.
130149
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
131150
&& sup_origin.span() != return_sp
132151
{
133-
// FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
134-
135152
// Customize the spans and labels depending on their relative order so
136153
// that split sentences flow correctly.
137154
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
@@ -152,29 +169,61 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
152169
// | ---- ^
153170
err.span_label(
154171
sup_origin.span(),
155-
"...is captured here, requiring it to live as long as `'static`",
172+
&format!(
173+
"...is captured here, requiring it to live as long as `'static`{}",
174+
if spans.is_empty() { "" } else { "..." },
175+
),
156176
);
157177
} else {
158-
err.span_label(sup_origin.span(), "...is captured here...");
159-
if return_sp < sup_origin.span() {
178+
if return_sp < sup_origin.span() && mention_capture {
179+
err.span_label(sup_origin.span(), "...is captured here...");
160180
err.span_note(
161181
return_sp,
162182
"...and is required to live as long as `'static` here",
163183
);
164184
} else {
165185
err.span_label(
166186
return_sp,
167-
"...and is required to live as long as `'static` here",
187+
&format!(
188+
"...is required to live as long as `'static` here{}",
189+
if spans.is_empty() { "" } else { "..." },
190+
),
168191
);
192+
if mention_capture {
193+
let span = sup_origin.span();
194+
let msg = if spans.iter().any(|sp| *sp > span) {
195+
"...is captured here..."
196+
} else {
197+
"...and is captured here"
198+
};
199+
err.span_label(span, msg);
200+
}
169201
}
170202
}
171203
} else {
172204
err.span_label(
173205
return_sp,
174-
"...is captured and required to live as long as `'static` here",
206+
&format!(
207+
"...is captured and required to live as long as `'static` here{}",
208+
if spans.is_empty() { "" } else { "..." },
209+
),
175210
);
176211
}
177212

213+
for span in spans {
214+
let msg =
215+
format!("...and is captured here{}", if mention_capture { " too" } else { "" });
216+
if span.overlaps(return_sp) {
217+
err.span_note(*span, &msg);
218+
} else {
219+
err.span_label(*span, &msg);
220+
}
221+
}
222+
223+
if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
224+
err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound");
225+
}
226+
178227
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
179228

180229
let mut override_error_code = None;

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2828
_sub,
2929
sup_origin,
3030
_sup,
31+
_,
3132
) = error.clone()
3233
{
3334
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
1919
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
2020
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
2121
use rustc_middle::ty::{Region, RegionVid};
22+
use rustc_span::Span;
2223
use std::fmt;
2324

2425
/// This function performs lexical region resolution given a complete
@@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> {
9697
Region<'tcx>,
9798
SubregionOrigin<'tcx>,
9899
Region<'tcx>,
100+
Vec<Span>,
99101
),
100102

101103
/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
@@ -144,8 +146,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
144146
let graph = self.construct_graph();
145147
self.expand_givens(&graph);
146148
self.expansion(&mut var_data);
147-
self.collect_errors(&mut var_data, errors);
148-
self.collect_var_errors(&var_data, &graph, errors);
149+
let captures = self.collect_errors(&mut var_data, errors);
150+
self.collect_var_errors(&var_data, &graph, errors, captures);
149151
var_data
150152
}
151153

@@ -443,9 +445,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
443445
&self,
444446
var_data: &mut LexicalRegionResolutions<'tcx>,
445447
errors: &mut Vec<RegionResolutionError<'tcx>>,
446-
) {
448+
) -> Vec<Span> {
449+
let mut captures = vec![];
450+
447451
for (constraint, origin) in &self.data.constraints {
448452
debug!(?constraint, ?origin);
453+
if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) =
454+
(constraint, origin)
455+
{
456+
captures.push(*sp);
457+
}
449458
match *constraint {
450459
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
451460
// Expansion will ensure that these constraints hold. Ignore.
@@ -515,6 +524,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
515524
sub,
516525
));
517526
}
527+
captures
518528
}
519529

520530
/// Go over the variables that were declared to be error variables
@@ -524,6 +534,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
524534
var_data: &LexicalRegionResolutions<'tcx>,
525535
graph: &RegionGraph<'tcx>,
526536
errors: &mut Vec<RegionResolutionError<'tcx>>,
537+
captures: Vec<Span>,
527538
) {
528539
debug!("collect_var_errors, var_data = {:#?}", var_data.values);
529540

@@ -567,7 +578,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
567578
// if this rule starts to create problems we'll
568579
// have to revisit this portion of the code and
569580
// think hard about it. =) -- nikomatsakis
570-
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
581+
self.collect_error_for_expanding_node(
582+
graph,
583+
&mut dup_vec,
584+
node_vid,
585+
errors,
586+
&captures,
587+
);
571588
}
572589
}
573590
}
@@ -621,6 +638,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
621638
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
622639
node_idx: RegionVid,
623640
errors: &mut Vec<RegionResolutionError<'tcx>>,
641+
captures: &[Span],
624642
) {
625643
// Errors in expanding nodes result from a lower-bound that is
626644
// not contained by an upper-bound.
@@ -667,13 +685,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
667685
sup: {:?}",
668686
origin, node_idx, lower_bound.region, upper_bound.region
669687
);
688+
689+
let mut capture_spans: Vec<Span> = captures.iter().cloned().collect();
690+
// Below, one span expects `&Span` and the other `&mut Span`, hence the dupes.
691+
capture_spans.sort_by_key(|span| (span.lo(), span.hi()));
692+
capture_spans.dedup_by_key(|span| (span.lo(), span.hi()));
670693
errors.push(RegionResolutionError::SubSupConflict(
671694
node_idx,
672695
origin,
673696
lower_bound.origin.clone(),
674697
lower_bound.region,
675698
upper_bound.origin.clone(),
676699
upper_bound.region,
700+
capture_spans,
677701
));
678702
return;
679703
}

src/test/ui/async-await/issues/issue-62097.stderr

+13-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
22
--> $DIR/issue-62097.rs:12:31
33
|
44
LL | pub async fn run_dummy_fn(&self) {
5-
| ^^^^^
6-
| |
7-
| this data with an anonymous lifetime `'_`...
8-
| ...is captured here...
5+
| ^^^^^ this data with an anonymous lifetime `'_`...
96
LL | foo(|| self.bar()).await;
10-
| --- ...and is required to live as long as `'static` here
7+
| --- ...is required to live as long as `'static` here...
8+
|
9+
note: ...and is captured here
10+
--> $DIR/issue-62097.rs:13:9
11+
|
12+
LL | foo(|| self.bar()).await;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: `'static` lifetime requirement introduced by this trait bound
15+
--> $DIR/issue-62097.rs:4:19
16+
|
17+
LL | F: FnOnce() + 'static
18+
| ^^^^^^^
1119

1220
error: aborting due to previous error
1321

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// edition:2018
2+
fn require_static<T: 'static>(val: T) -> T {
3+
//~^ NOTE 'static` lifetime requirement introduced by this trait bound
4+
val
5+
}
6+
7+
struct Problem;
8+
9+
impl Problem {
10+
pub async fn start(&self) { //~ ERROR E0759
11+
//~^ NOTE this data with an anonymous lifetime `'_`
12+
//~| NOTE in this expansion of desugaring of `async` block or function
13+
require_static(async move { //~ NOTE ...is required to live as long as `'static` here
14+
&self; //~ NOTE ...and is captured here
15+
});
16+
}
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
2+
--> $DIR/issue-72312.rs:10:24
3+
|
4+
LL | pub async fn start(&self) {
5+
| ^^^^^ this data with an anonymous lifetime `'_`...
6+
...
7+
LL | require_static(async move {
8+
| -------------- ...is required to live as long as `'static` here...
9+
LL | &self;
10+
| ----- ...and is captured here
11+
|
12+
note: `'static` lifetime requirement introduced by this trait bound
13+
--> $DIR/issue-72312.rs:2:22
14+
|
15+
LL | fn require_static<T: 'static>(val: T) -> T {
16+
| ^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0759`.

src/test/ui/traits/trait-upcasting/type-checking-test-4.rs

+18
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
2929
y.get_b() // ERROR
3030
}
3131

32+
fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
33+
<_ as Bar>::get_b(x) // ERROR
34+
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
35+
}
36+
37+
fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
38+
<_ as Bar<'_, '_>>::get_b(x) // ERROR
39+
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
40+
}
41+
42+
fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
43+
let y = x as &dyn Bar<'_, '_>;
44+
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
45+
y.get_b(); // ERROR
46+
let z = y;
47+
z.get_b() // ERROR
48+
}
49+
3250
fn main() {}

0 commit comments

Comments
 (0)