Skip to content

Commit dcdcafb

Browse files
committed
On E0478, point at source of lifetime requirement
1 parent a4f7a36 commit dcdcafb

File tree

4 files changed

+224
-6
lines changed

4 files changed

+224
-6
lines changed

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

+47-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use crate::traits::{
6161
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
6262
use rustc_errors::{
6363
codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic,
64-
DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg,
64+
DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan,
6565
};
6666
use rustc_hir as hir;
6767
use rustc_hir::def::DefKind;
@@ -450,11 +450,54 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
450450
// the error. If all of these fails, we fall back to a rather
451451
// general bit of code that displays the error information
452452
RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
453-
if sub.is_placeholder() || sup.is_placeholder() {
454-
self.report_placeholder_failure(origin, sub, sup).emit();
453+
let mut err = if sub.is_placeholder() || sup.is_placeholder() {
454+
self.report_placeholder_failure(origin, sub, sup)
455455
} else {
456-
self.report_concrete_failure(origin, sub, sup).emit();
456+
self.report_concrete_failure(origin, sub, sup)
457+
};
458+
if let hir::def::DefKind::Impl { .. } =
459+
self.tcx.def_kind(generic_param_scope)
460+
&& let Some(def_id) =
461+
self.tcx.trait_id_of_impl(generic_param_scope.into())
462+
{
463+
// Collect all the `Span`s corresponding to the predicates introducing
464+
// the `sub` lifetime that couldn't be met (sometimes `'static`) on
465+
// both the `trait` and the `impl`.
466+
let spans: Vec<Span> = self
467+
.tcx
468+
.predicates_of(def_id)
469+
.predicates
470+
.iter()
471+
.chain(
472+
self.tcx.predicates_of(generic_param_scope).predicates.iter(),
473+
)
474+
.filter_map(|(pred, span)| {
475+
if let Some(ty::ClauseKind::TypeOutlives(
476+
ty::OutlivesPredicate(pred_ty, r),
477+
)) = pred.kind().no_bound_vars()
478+
&& r == sub
479+
&& let ty::Param(param) = pred_ty.kind()
480+
&& param.name.as_str() == "Self"
481+
{
482+
Some(*span)
483+
} else {
484+
None
485+
}
486+
})
487+
.collect();
488+
489+
if !spans.is_empty() {
490+
let spans_len = spans.len();
491+
err.span_note(
492+
MultiSpan::from(spans),
493+
format!(
494+
"`{sub}` requirement{} introduced here",
495+
pluralize!(spans_len),
496+
),
497+
);
498+
}
457499
}
500+
err.emit();
458501
}
459502

460503
RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {

tests/ui/lifetimes/static-impl-obligation.rs

+69
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,73 @@ mod s {
207207
y.hello(); //~ ERROR lifetime may not live long enough
208208
}
209209
}
210+
mod t {
211+
trait OtherTrait<'a> {}
212+
impl<'a> OtherTrait<'a> for &'a () {}
213+
214+
trait ObjectTrait {}
215+
trait MyTrait where Self: 'static {
216+
fn use_self(&self) -> &() where Self: 'static { panic!() }
217+
}
218+
trait Irrelevant {
219+
fn use_self(&self) -> &() { panic!() }
220+
}
221+
222+
impl MyTrait for dyn ObjectTrait + '_ {} //~ ERROR lifetime bound not satisfied
223+
224+
fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
225+
val.use_self() //~ ERROR borrowed data escapes
226+
}
227+
}
228+
mod u {
229+
trait OtherTrait<'a> {}
230+
impl<'a> OtherTrait<'a> for &'a () {}
231+
232+
trait ObjectTrait {}
233+
trait MyTrait {
234+
fn use_self(&self) -> &() where Self: 'static { panic!() }
235+
}
236+
trait Irrelevant {
237+
fn use_self(&self) -> &() { panic!() }
238+
}
239+
240+
impl MyTrait for dyn ObjectTrait + '_ {}
241+
242+
fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
243+
val.use_self() //~ ERROR borrowed data escapes
244+
}
245+
}
246+
mod v {
247+
trait OtherTrait<'a> {}
248+
impl<'a> OtherTrait<'a> for &'a () {}
249+
250+
trait ObjectTrait {}
251+
trait MyTrait where Self: 'static {
252+
fn use_self(&'static self) -> &() { panic!() }
253+
}
254+
trait Irrelevant {
255+
fn use_self(&self) -> &() { panic!() }
256+
}
257+
258+
impl MyTrait for dyn ObjectTrait {}
259+
260+
fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
261+
val.use_self() //~ ERROR borrowed data escapes
262+
}
263+
}
264+
mod w {
265+
trait Foo {}
266+
impl<'a> Foo for &'a u32 {}
267+
268+
trait Trait where Self: 'static { fn hello(&self) {} }
269+
270+
impl Trait for dyn Foo + '_ { //~ERROR lifetime bound not satisfied
271+
fn hello(&self) {}
272+
273+
}
274+
fn convert<'a>(x: &'a &'a u32) {
275+
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
276+
y.hello();
277+
}
278+
}
210279
fn main() {}

tests/ui/lifetimes/static-impl-obligation.stderr

+103-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,95 @@
1+
error[E0478]: lifetime bound not satisfied
2+
--> $DIR/static-impl-obligation.rs:222:10
3+
|
4+
LL | impl MyTrait for dyn ObjectTrait + '_ {}
5+
| ^^^^^^^
6+
|
7+
note: lifetime parameter instantiated with the anonymous lifetime as defined here
8+
--> $DIR/static-impl-obligation.rs:222:40
9+
|
10+
LL | impl MyTrait for dyn ObjectTrait + '_ {}
11+
| ^^
12+
= note: but lifetime parameter must outlive the static lifetime
13+
note: `'static` requirement introduced here
14+
--> $DIR/static-impl-obligation.rs:215:31
15+
|
16+
LL | trait MyTrait where Self: 'static {
17+
| ^^^^^^^
18+
19+
error[E0521]: borrowed data escapes outside of function
20+
--> $DIR/static-impl-obligation.rs:225:9
21+
|
22+
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
23+
| -- --- `val` is a reference that is only valid in the function body
24+
| |
25+
| lifetime `'a` defined here
26+
LL | val.use_self()
27+
| ^^^^^^^^^^^^^^
28+
| |
29+
| `val` escapes the function body here
30+
| argument requires that `'a` must outlive `'static`
31+
32+
error[E0521]: borrowed data escapes outside of function
33+
--> $DIR/static-impl-obligation.rs:243:9
34+
|
35+
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
36+
| -- --- `val` is a reference that is only valid in the function body
37+
| |
38+
| lifetime `'a` defined here
39+
LL | val.use_self()
40+
| ^^^^^^^^^^^^^^
41+
| |
42+
| `val` escapes the function body here
43+
| argument requires that `'a` must outlive `'static`
44+
45+
error[E0521]: borrowed data escapes outside of function
46+
--> $DIR/static-impl-obligation.rs:261:9
47+
|
48+
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
49+
| -- --- `val` is a reference that is only valid in the function body
50+
| |
51+
| lifetime `'a` defined here
52+
LL | val.use_self()
53+
| ^^^^^^^^^^^^^^
54+
| |
55+
| `val` escapes the function body here
56+
| argument requires that `'a` must outlive `'static`
57+
|
58+
note: the used `impl` has a `'static` requirement
59+
--> $DIR/static-impl-obligation.rs:258:26
60+
|
61+
LL | fn use_self(&'static self) -> &() { panic!() }
62+
| -------- calling this method introduces the `impl`'s `'static` requirement
63+
...
64+
LL | impl MyTrait for dyn ObjectTrait {}
65+
| ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
66+
note: the `impl` on `(dyn v::ObjectTrait + 'static)` has `'static` lifetime requirements
67+
--> $DIR/static-impl-obligation.rs:252:21
68+
|
69+
LL | fn use_self(&'static self) -> &() { panic!() }
70+
| ^^^^^^^^^^^^^
71+
...
72+
LL | impl MyTrait for dyn ObjectTrait {}
73+
| ^^^^^^^^^^^^^^^
74+
75+
error[E0478]: lifetime bound not satisfied
76+
--> $DIR/static-impl-obligation.rs:270:10
77+
|
78+
LL | impl Trait for dyn Foo + '_ {
79+
| ^^^^^
80+
|
81+
note: lifetime parameter instantiated with the anonymous lifetime as defined here
82+
--> $DIR/static-impl-obligation.rs:270:30
83+
|
84+
LL | impl Trait for dyn Foo + '_ {
85+
| ^^
86+
= note: but lifetime parameter must outlive the static lifetime
87+
note: `'static` requirement introduced here
88+
--> $DIR/static-impl-obligation.rs:268:29
89+
|
90+
LL | trait Trait where Self: 'static { fn hello(&self) {} }
91+
| ^^^^^^^
92+
193
error: lifetime may not live long enough
294
--> $DIR/static-impl-obligation.rs:9:9
395
|
@@ -329,6 +421,15 @@ help: consider relaxing the implicit `'static` requirement on the impl
329421
LL | impl Trait for dyn Foo + '_ {
330422
| ++++
331423

332-
error: aborting due to 19 previous errors
424+
error: lifetime may not live long enough
425+
--> $DIR/static-impl-obligation.rs:275:27
426+
|
427+
LL | fn convert<'a>(x: &'a &'a u32) {
428+
| -- lifetime `'a` defined here
429+
LL | let y: &dyn Foo = x;
430+
| ^ cast requires that `'a` must outlive `'static`
431+
432+
error: aborting due to 25 previous errors
333433

334-
For more information about this error, try `rustc --explain E0521`.
434+
Some errors have detailed explanations: E0478, E0521.
435+
For more information about an error, try `rustc --explain E0478`.

tests/ui/static/static-lifetime.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ note: lifetime parameter instantiated with the lifetime `'a` as defined here
1010
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
1111
| ^^
1212
= note: but lifetime parameter must outlive the static lifetime
13+
note: `'static` requirement introduced here
14+
--> $DIR/static-lifetime.rs:1:30
15+
|
16+
LL | pub trait Arbitrary: Sized + 'static {}
17+
| ^^^^^^^
1318

1419
error: aborting due to 1 previous error
1520

0 commit comments

Comments
 (0)