Skip to content

Commit 189b2f8

Browse files
committed
Blame better constraints when failing to outlive 'static
1 parent 3b38264 commit 189b2f8

23 files changed

+147
-111
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -2062,7 +2062,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
20622062
// most likely to be the point where the value escapes -- but
20632063
// we still want to screen for an "interesting" point to
20642064
// highlight (e.g., a call site or something).
2065-
let target_scc = self.constraint_sccs.scc(target_region);
2065+
// As a special case, if the target region is 'static, it will always outlive the source,
2066+
// so they'll be in the same SCC. To get better diagnostics, we pretend those `'static: R`
2067+
// edges don't exist and use the resulting graph's SCCs.
2068+
let target_is_static = target_region == self.universal_regions().fr_static;
2069+
let sccs_without_static = target_is_static
2070+
.then(|| self.constraints.compute_sccs(RegionVid::MAX, &self.definitions));
2071+
let constraint_sccs = sccs_without_static.as_ref().unwrap_or(&self.constraint_sccs);
2072+
let target_scc = constraint_sccs.scc(target_region);
20662073
let mut range = 0..path.len();
20672074

20682075
// As noted above, when reporting an error, there is typically a chain of constraints
@@ -2110,7 +2117,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
21102117
let find_region = |i: &usize| {
21112118
let constraint = &path[*i];
21122119

2113-
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
2120+
let constraint_sup_scc = constraint_sccs.scc(constraint.sup);
21142121

21152122
if blame_source {
21162123
match categorized_path[*i].category {
@@ -2168,17 +2175,38 @@ impl<'tcx> RegionInferenceContext<'tcx> {
21682175
}
21692176
}
21702177

2178+
// If an "outlives 'static" constraint was from use as a const or static, blame that.
2179+
if target_is_static
2180+
&& blame_source
2181+
&& let Some(old_best) = categorized_path.iter().min_by_key(|p| p.category)
2182+
&& matches!(
2183+
old_best.category,
2184+
ConstraintCategory::UseAsConst
2185+
| ConstraintCategory::UseAsStatic
2186+
| ConstraintCategory::Cast {
2187+
is_implicit_coercion: true,
2188+
unsize_to: Some(_)
2189+
}
2190+
)
2191+
{
2192+
// FIXME(dianne): `BorrowExplanation::add_object_lifetime_default_note` depends on a
2193+
// coercion being blamed, so revert to the old blaming logic to prioritize that.
2194+
// The note's logic should be reworked, though; it's flaky (#131008 doesn't have a
2195+
// coercion, and even with this hack, one isn't always blamed when present).
2196+
// Only checking for a coercion also makes the note appear where it shouldn't
2197+
// shouldn't (e.g. `tests/ui/borrowck/two-phase-surprise-no-conflict.stderr`).
2198+
return (old_best.clone(), extra_info);
2199+
}
2200+
21712201
return (categorized_path[i].clone(), extra_info);
21722202
}
21732203

2174-
// If that search fails, that is.. unusual. Maybe everything
2175-
// is in the same SCC or something. In that case, find what
2176-
// appears to be the most interesting point to report to the
2177-
// user via an even more ad-hoc guess.
2178-
categorized_path.sort_by_key(|p| p.category);
2179-
debug!("sorted_path={:#?}", categorized_path);
2204+
// If that search fails, everything may be in the same SCC. In particular, this will be the
2205+
// case when dealing with invariant lifetimes. Find what appears to be the most interesting
2206+
// point to report to the user via an even more ad-hoc guess.
2207+
let best_choice = categorized_path.into_iter().min_by_key(|p| p.category).unwrap();
21802208

2181-
(categorized_path.remove(0), extra_info)
2209+
(best_choice, extra_info)
21822210
}
21832211

21842212
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {

tests/ui/borrowck/fn-item-check-type-params.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ LL | extend_lt(val);
1212
| argument requires that `'a` must outlive `'static`
1313

1414
error: lifetime may not live long enough
15-
--> $DIR/fn-item-check-type-params.rs:39:12
15+
--> $DIR/fn-item-check-type-params.rs:39:31
1616
|
1717
LL | pub fn test_coercion<'a>() {
1818
| -- lifetime `'a` defined here
1919
LL | let _: fn(&'a str) -> _ = extend_lt;
20-
| ^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
20+
| ^^^^^^^^^ coercion requires that `'a` must outlive `'static`
2121

2222
error[E0716]: temporary value dropped while borrowed
2323
--> $DIR/fn-item-check-type-params.rs:48:11

tests/ui/coroutine/resume-arg-outlives-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
1818
// exploit:
1919
generator.as_mut().resume("");
2020
generator.as_mut().resume(s); // <- generator hoards it as `let ctx`.
21-
//~^ ERROR borrowed data escapes outside of function
2221
thread::spawn(move || {
22+
//~^ ERROR borrowed data escapes outside of function
2323
thread::sleep(time::Duration::from_millis(200));
2424
generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`.
2525
})

tests/ui/coroutine/resume-arg-outlives-2.stderr

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
error[E0521]: borrowed data escapes outside of function
2-
--> $DIR/resume-arg-outlives-2.rs:20:5
2+
--> $DIR/resume-arg-outlives-2.rs:21:5
33
|
4-
LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
5-
| ----------- - `s` is a reference that is only valid in the function body
6-
| |
7-
| lifetime `'not_static` defined here
4+
LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
5+
| ----------- - `s` is a reference that is only valid in the function body
6+
| |
7+
| lifetime `'not_static` defined here
88
...
9-
LL | generator.as_mut().resume(s); // <- generator hoards it as `let ctx`.
10-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11-
| |
12-
| `s` escapes the function body here
13-
| argument requires that `'not_static` must outlive `'static`
9+
LL | / thread::spawn(move || {
10+
LL | |
11+
LL | | thread::sleep(time::Duration::from_millis(200));
12+
LL | | generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`.
13+
LL | | })
14+
| | ^
15+
| | |
16+
| |______`s` escapes the function body here
17+
| argument requires that `'not_static` must outlive `'static`
1418

1519
error: aborting due to 1 previous error
1620

tests/ui/impl-trait/precise-capturing/migration-note.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ fn needs_static() {
2929
let a = display_len(&x);
3030
//~^ ERROR `x` does not live long enough
3131
//~| NOTE this call may capture more lifetimes than intended
32-
//~| NOTE argument requires that `x` is borrowed for `'static`
3332
//~| NOTE borrowed value does not live long enoug
3433

3534
fn needs_static(_: impl Sized + 'static) {}
3635
needs_static(a);
36+
//~^ NOTE argument requires that `x` is borrowed for `'static`
3737
}
3838
//~^ NOTE `x` dropped here while still borrowed
3939

@@ -76,11 +76,11 @@ fn needs_static_mut() {
7676
let a = display_len_mut(&mut x);
7777
//~^ ERROR `x` does not live long enough
7878
//~| NOTE this call may capture more lifetimes than intended
79-
//~| NOTE argument requires that `x` is borrowed for `'static`
8079
//~| NOTE borrowed value does not live long enough
8180

8281
fn needs_static(_: impl Sized + 'static) {}
8382
needs_static(a);
83+
//~^ NOTE argument requires that `x` is borrowed for `'static`
8484
}
8585
//~^ NOTE `x` dropped here while still borrowed
8686

tests/ui/impl-trait/precise-capturing/migration-note.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ LL | let x = vec![1];
4242
| - binding `x` declared here
4343
LL |
4444
LL | let a = display_len(&x);
45-
| ------------^^-
46-
| | |
47-
| | borrowed value does not live long enough
48-
| argument requires that `x` is borrowed for `'static`
45+
| ^^ borrowed value does not live long enough
4946
...
47+
LL | needs_static(a);
48+
| --------------- argument requires that `x` is borrowed for `'static`
49+
LL |
5050
LL | }
5151
| - `x` dropped here while still borrowed
5252
|
@@ -118,11 +118,11 @@ LL | let mut x = vec![1];
118118
| ----- binding `x` declared here
119119
LL |
120120
LL | let a = display_len_mut(&mut x);
121-
| ----------------^^^^^^-
122-
| | |
123-
| | borrowed value does not live long enough
124-
| argument requires that `x` is borrowed for `'static`
121+
| ^^^^^^ borrowed value does not live long enough
125122
...
123+
LL | needs_static(a);
124+
| --------------- argument requires that `x` is borrowed for `'static`
125+
LL |
126126
LL | }
127127
| - `x` dropped here while still borrowed
128128
|

tests/ui/inline-const/const-match-pat-lifetime-err.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ fn match_covariant_ref<'a>() {
3535
// `y.0`), but using the associated const directly in the pattern also
3636
// errors.
3737
let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
38-
//~^ ERROR lifetime may not live long enough
3938
match y.0 {
4039
const { CovariantRef::<'a>::NEW } => (),
40+
//~^ ERROR lifetime may not live long enough
4141
}
4242
}
4343

tests/ui/inline-const/const-match-pat-lifetime-err.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ LL | }
1515
| - `y` dropped here while still borrowed
1616

1717
error: lifetime may not live long enough
18-
--> $DIR/const-match-pat-lifetime-err.rs:37:12
18+
--> $DIR/const-match-pat-lifetime-err.rs:39:17
1919
|
2020
LL | fn match_covariant_ref<'a>() {
2121
| -- lifetime `'a` defined here
2222
...
23-
LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
24-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
23+
LL | const { CovariantRef::<'a>::NEW } => (),
24+
| ^^^^^^^^^^^^^^^^^^^^^^^ using this value as a constant requires that `'a` must outlive `'static`
2525

2626
error: aborting due to 2 previous errors
2727

tests/ui/kindck/kindck-impl-type-params.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ LL | struct Foo; // does not impl Copy
112112
|
113113

114114
error: lifetime may not live long enough
115-
--> $DIR/kindck-impl-type-params.rs:30:19
115+
--> $DIR/kindck-impl-type-params.rs:30:13
116116
|
117117
LL | fn foo<'a>() {
118118
| -- lifetime `'a` defined here
119119
LL | let t: S<&'a isize> = S(marker::PhantomData);
120120
LL | let a = &t as &dyn Gettable<&'a isize>;
121-
| ^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
121+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`
122122

123123
error: aborting due to 7 previous errors
124124

tests/ui/lifetimes/issue-90600-expected-return-static-indirect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ fn inner(mut foo: &[u8]) {
77
let refcell = RefCell::new(&mut foo);
88
//~^ ERROR `foo` does not live long enough
99
let read = &refcell as &RefCell<dyn Read>;
10-
//~^ ERROR lifetime may not live long enough
1110

1211
read_thing(read);
12+
//~^ ERROR lifetime may not live long enough
1313
}
1414

1515
fn read_thing(refcell: &RefCell<dyn Read>) {}

tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ LL | fn inner(mut foo: &[u8]) {
55
| ------- binding `foo` declared here
66
LL | let refcell = RefCell::new(&mut foo);
77
| ^^^^^^^^ borrowed value does not live long enough
8-
LL |
9-
LL | let read = &refcell as &RefCell<dyn Read>;
10-
| ------------------------------ cast requires that `foo` is borrowed for `'static`
118
...
9+
LL | read_thing(read);
10+
| ---- coercion requires that `foo` is borrowed for `'static`
11+
LL |
1212
LL | }
1313
| - `foo` dropped here while still borrowed
1414

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

2424
error: aborting due to 2 previous errors
2525

tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ error[E0597]: `a` does not live long enough
5656
LL | let a = 0;
5757
| - binding `a` declared here
5858
LL | let cell = Cell::new(&a);
59-
| ----------^^-
60-
| | |
61-
| | borrowed value does not live long enough
62-
| argument requires that `a` is borrowed for `'static`
59+
| ^^ borrowed value does not live long enough
6360
...
61+
LL | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
62+
| ------------------------ argument requires that `a` is borrowed for `'static`
63+
LL | })
6464
LL | }
6565
| - `a` dropped here while still borrowed
6666

tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
3030
#[rustc_regions]
3131
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
3232
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
33-
//~^ ERROR borrowed data escapes outside of function
34-
3533
// Only works if 'x: 'y:
3634
demand_y(x, y, x.get())
35+
//~^ ERROR borrowed data escapes outside of function
3736
});
3837
}
3938

tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr

+11-19
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,18 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
2323
= note: defining type: supply
2424

2525
error[E0521]: borrowed data escapes outside of function
26-
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
26+
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:34:9
2727
|
28-
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
29-
| -- ------ `cell_a` is a reference that is only valid in the function body
30-
| |
31-
| lifetime `'a` defined here
32-
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
33-
LL | |
34-
LL | |
35-
LL | | // Only works if 'x: 'y:
36-
LL | | demand_y(x, y, x.get())
37-
LL | | });
38-
| | ^
39-
| | |
40-
| |______`cell_a` escapes the function body here
41-
| argument requires that `'a` must outlive `'static`
42-
|
43-
= note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant
44-
= note: the struct `Cell<T>` is invariant over the parameter `T`
45-
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
28+
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
29+
| -- ------ `cell_a` is a reference that is only valid in the function body
30+
| |
31+
| lifetime `'a` defined here
32+
...
33+
LL | demand_y(x, y, x.get())
34+
| ^^^^^^^^^^^^^^^^^^^^^^^
35+
| |
36+
| `cell_a` escapes the function body here
37+
| argument requires that `'a` must outlive `'static`
4638

4739
error: aborting due to 1 previous error
4840

tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
3333
#[rustc_regions]
3434
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
3535
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
36-
//~^ ERROR borrowed data escapes outside of function
37-
3836
// Only works if 'x: 'y:
3937
demand_y(x, y, x.get())
38+
//~^ ERROR borrowed data escapes outside of function
4039
});
4140
}
4241

tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr

+11-19
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,18 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
2323
= note: defining type: supply
2424

2525
error[E0521]: borrowed data escapes outside of function
26-
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
26+
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:37:9
2727
|
28-
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
29-
| -- ------ `cell_a` is a reference that is only valid in the function body
30-
| |
31-
| lifetime `'a` defined here
32-
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
33-
LL | |
34-
LL | |
35-
LL | | // Only works if 'x: 'y:
36-
LL | | demand_y(x, y, x.get())
37-
LL | | });
38-
| | ^
39-
| | |
40-
| |______`cell_a` escapes the function body here
41-
| argument requires that `'a` must outlive `'static`
42-
|
43-
= note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant
44-
= note: the struct `Cell<T>` is invariant over the parameter `T`
45-
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
28+
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
29+
| -- ------ `cell_a` is a reference that is only valid in the function body
30+
| |
31+
| lifetime `'a` defined here
32+
...
33+
LL | demand_y(x, y, x.get())
34+
| ^^^^^^^^^^^^^^^^^^^^^^^
35+
| |
36+
| `cell_a` escapes the function body here
37+
| argument requires that `'a` must outlive `'static`
4638

4739
error: aborting due to 1 previous error
4840

tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ error[E0597]: `s` does not live long enough
44
LL | let s = 2;
55
| - binding `s` declared here
66
LL | let a = (Foo(&s),);
7-
| ^^ borrowed value does not live long enough
8-
LL | drop(a.0);
9-
| --- copying this value requires that `s` is borrowed for `'static`
10-
LL | drop(a.0);
7+
| -----^^---
8+
| | |
9+
| | borrowed value does not live long enough
10+
| assignment requires that `s` is borrowed for `'static`
11+
...
1112
LL | }
1213
| - `s` dropped here while still borrowed
1314

0 commit comments

Comments
 (0)