diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index a8d6afa0e55b..022f83af8159 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -287,6 +287,7 @@ struct ElisionFailureInfo { index: usize, lifetime_count: usize, have_bound_regions: bool, + span: Span, } type ScopeRef<'a> = &'a Scope<'a>; @@ -2273,6 +2274,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { index: i, lifetime_count: gather.lifetimes.len(), have_bound_regions: gather.have_bound_regions, + span: input.span, } }) .collect(); @@ -2483,11 +2485,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); let elided_len = elided_params.len(); + let mut spans = vec![]; - // FIXME: collect spans of the input params when appropriate to use in the diagnostic. for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = info; + spans.push(span); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -2518,14 +2521,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + let help = |msg| { + if spans.is_empty() { + db.help(msg); + } else { + db.span_help(spans, msg); + } + }; + if len == 0 { db.help( "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", + but there is no value for it to be borrowed from", ); self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { - db.help( + help( "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", @@ -2533,16 +2544,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let msg = "consider giving it an explicit bounded or 'static lifetime"; self.suggest_lifetime(db, span, msg) } else if elided_len == 1 { - db.help(&format!( + help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", + but the signature does not say which {} it is borrowed from", m )); true } else { - db.help(&format!( + help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", + but the signature does not say whether it is borrowed from {}", m )); true diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 7e45d588c6c6..a12c601b936a 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` + --> $DIR/issue-63388-2.rs:11:14 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | ^^^^^^^^ ^^^^^^^^^^^ error: cannot infer an appropriate lifetime --> $DIR/issue-63388-2.rs:11:9 diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index c5129152aa58..1be066caa87a 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | type Foo = fn(&u8, &u8) -> &u8; | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + --> $DIR/issue-19707.rs:3:15 + | +LL | type Foo = fn(&u8, &u8) -> &u8; + | ^^^ ^^^ help: consider introducing a named lifetime parameter | LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; @@ -16,7 +20,11 @@ error[E0106]: missing lifetime specifier LL | fn bar &u8>(f: &F) {} | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + --> $DIR/issue-19707.rs:5:14 + | +LL | fn bar &u8>(f: &F) {} + | ^^^ ^^^ = note: for more information on Higher-Ranked lifetimes, visit https://doc.rust-lang.org/nomicon/hrtb.html help: consider introducing a Higher-Ranked lifetime | diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 85d5d9cc42e9..882102799d91 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from + --> $DIR/issue-26638.rs:1:21 + | +LL | fn parse_type(iter: Box+'static>) -> &str { iter.next() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider introducing a named lifetime parameter | LL | fn parse_type<'lifetime>(iter: Box+'static>) -> &'lifetime str { iter.next() } diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index c94022776409..e2b57a20325d 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | fn f(a: &S, b: i32) -> &i32 { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from + --> $DIR/issue-30255.rs:9:9 + | +LL | fn f(a: &S, b: i32) -> &i32 { + | ^^ help: consider introducing a named lifetime parameter | LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { @@ -16,7 +20,11 @@ error[E0106]: missing lifetime specifier LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` + --> $DIR/issue-30255.rs:14:9 + | +LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { + | ^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { @@ -28,7 +36,11 @@ error[E0106]: missing lifetime specifier LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` + --> $DIR/issue-30255.rs:19:9 + | +LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { + | ^^^^^ ^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 1d5eeac23f96..d1b597804cda 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -12,7 +12,11 @@ error[E0106]: missing lifetime specifier LL | fn g(_x: &isize, _y: &isize) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` + --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:10 + | +LL | fn g(_x: &isize, _y: &isize) -> &isize { + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { @@ -24,7 +28,11 @@ error[E0106]: missing lifetime specifier LL | fn h(_x: &Foo) -> &isize { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from + --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:10 + | +LL | fn h(_x: &Foo) -> &isize { + | ^^^^ help: consider introducing a named lifetime parameter | LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index 2990ab868243..52a980a61daa 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | fn foo(x: &i32, y: &i32) -> &i32 { | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + --> $DIR/ex1b-return-no-names-if-else.rs:1:11 + | +LL | fn foo(x: &i32, y: &i32) -> &i32 { + | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 5b665e181412..aabe088d63ca 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + --> $DIR/rfc1623.rs:8:29 + | +LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = + | ^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/rfc1623.rs:10:39 @@ -12,7 +16,11 @@ error[E0106]: missing lifetime specifier LL | &(non_elidable as fn(&u8, &u8) -> &u8); | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + --> $DIR/rfc1623.rs:10:26 + | +LL | &(non_elidable as fn(&u8, &u8) -> &u8); + | ^^^ ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 7f5ff95938e3..3b7936c5f44b 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -10,7 +10,11 @@ error[E0106]: missing lifetime specifier LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + --> $DIR/return-without-lifetime.rs:5:20 + | +LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } + | ^^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 @@ -18,7 +22,11 @@ error[E0106]: missing lifetime specifier LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + --> $DIR/return-without-lifetime.rs:7:20 + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } + | ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 0a028e44919a..1e15196f8ec8 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | let _: dyn Foo(&isize, &usize) -> &usize; | ^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:20 + | +LL | let _: dyn Foo(&isize, &usize) -> &usize; + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn main<'lifetime>() { diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index cf820249c80a..801504627c0a 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -4,7 +4,11 @@ error[E0106]: missing lifetime specifier LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + --> $DIR/in-fn-return-illegal.rs:5:11 + | +LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } + | ^^^^ ^^^^ help: consider introducing a named lifetime parameter | LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 517904ee6286..ef3ad18ee886 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -30,7 +30,11 @@ error[E0106]: missing lifetime specifier LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } | ^^ expected named lifetime parameter | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` +help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` + --> $DIR/underscore-lifetime-binders.rs:16:12 + | +LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } + | ^^^^^^ ^^^^^^ help: consider introducing a named lifetime parameter | LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y }