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

Lines changed: 37 additions & 9 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 14 additions & 10 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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>) {}

0 commit comments

Comments
 (0)