Skip to content

Commit f50e285

Browse files
authored
Rollup merge of rust-lang#55173 - estebank:suggest-static, r=oli-obk
Suggest appropriate syntax on missing lifetime specifier in return type Suggest using `'static` when a lifetime is missing in the return type with a structured suggestion instead of a note. Fix rust-lang#55170.
2 parents 6dfeb76 + dd91c8f commit f50e285

13 files changed

+103
-45
lines changed

src/librustc/hir/lowering.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ impl<'a> LoweringContext<'a> {
11471147
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
11481148
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
11491149
TyKind::Rptr(ref region, ref mt) => {
1150-
let span = t.span.shrink_to_lo();
1150+
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
11511151
let lifetime = match *region {
11521152
Some(ref lt) => self.lower_lifetime(lt),
11531153
None => self.elided_ref_lifetime(span),

src/librustc/middle/resolve_lifetime.rs

+44-18
Original file line numberDiff line numberDiff line change
@@ -2235,21 +2235,46 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
22352235
};
22362236

22372237
let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
2238+
let mut add_label = true;
22382239

22392240
if let Some(params) = error {
22402241
if lifetime_refs.len() == 1 {
2241-
self.report_elision_failure(&mut err, params);
2242+
add_label = add_label && self.report_elision_failure(&mut err, params, span);
22422243
}
22432244
}
2245+
if add_label {
2246+
add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
2247+
}
22442248

22452249
err.emit();
22462250
}
22472251

2252+
fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool {
2253+
match self.tcx.sess.source_map().span_to_snippet(span) {
2254+
Ok(ref snippet) => {
2255+
let (sugg, applicability) = if snippet == "&" {
2256+
("&'static ".to_owned(), Applicability::MachineApplicable)
2257+
} else if snippet == "'_" {
2258+
("'static".to_owned(), Applicability::MachineApplicable)
2259+
} else {
2260+
(format!("{} + 'static", snippet), Applicability::MaybeIncorrect)
2261+
};
2262+
db.span_suggestion_with_applicability(span, msg, sugg, applicability);
2263+
false
2264+
}
2265+
Err(_) => {
2266+
db.help(msg);
2267+
true
2268+
}
2269+
}
2270+
}
2271+
22482272
fn report_elision_failure(
22492273
&mut self,
22502274
db: &mut DiagnosticBuilder<'_>,
22512275
params: &[ElisionFailureInfo],
2252-
) {
2276+
span: Span,
2277+
) -> bool {
22532278
let mut m = String::new();
22542279
let len = params.len();
22552280

@@ -2304,33 +2329,32 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23042329
"this function's return type contains a borrowed value, but \
23052330
there is no value for it to be borrowed from"
23062331
);
2307-
help!(db, "consider giving it a 'static lifetime");
2332+
self.suggest_lifetime(db, span, "consider giving it a 'static lifetime")
23082333
} else if elided_len == 0 {
23092334
help!(
23102335
db,
23112336
"this function's return type contains a borrowed value with \
23122337
an elided lifetime, but the lifetime cannot be derived from \
23132338
the arguments"
23142339
);
2315-
help!(
2316-
db,
2317-
"consider giving it an explicit bounded or 'static \
2318-
lifetime"
2319-
);
2340+
let msg = "consider giving it an explicit bounded or 'static lifetime";
2341+
self.suggest_lifetime(db, span, msg)
23202342
} else if elided_len == 1 {
23212343
help!(
23222344
db,
23232345
"this function's return type contains a borrowed value, but \
23242346
the signature does not say which {} it is borrowed from",
23252347
m
23262348
);
2349+
true
23272350
} else {
23282351
help!(
23292352
db,
23302353
"this function's return type contains a borrowed value, but \
23312354
the signature does not say whether it is borrowed from {}",
23322355
m
23332356
);
2357+
true
23342358
}
23352359
}
23362360

@@ -2744,26 +2768,28 @@ fn insert_late_bound_lifetimes(
27442768
}
27452769
}
27462770

2747-
pub fn report_missing_lifetime_specifiers(
2771+
fn report_missing_lifetime_specifiers(
27482772
sess: &Session,
27492773
span: Span,
27502774
count: usize,
27512775
) -> DiagnosticBuilder<'_> {
2752-
let mut err = struct_span_err!(
2776+
struct_span_err!(
27532777
sess,
27542778
span,
27552779
E0106,
27562780
"missing lifetime specifier{}",
27572781
if count > 1 { "s" } else { "" }
2758-
);
2782+
)
2783+
}
27592784

2760-
let msg: Cow<'static, str> = if count > 1 {
2761-
format!("expected {} lifetime parameters", count).into()
2785+
fn add_missing_lifetime_specifiers_label(
2786+
err: &mut DiagnosticBuilder<'_>,
2787+
span: Span,
2788+
count: usize,
2789+
) {
2790+
if count > 1 {
2791+
err.span_label(span, format!("expected {} lifetime parameters", count));
27622792
} else {
2763-
"expected lifetime parameter".into()
2793+
err.span_label(span, "expected lifetime parameter");
27642794
};
2765-
2766-
err.span_label(span, msg);
2767-
2768-
err
27692795
}

src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/bound-lifetime-in-binding-only.rs:62:23
33
|
44
LL | fn elision<T: Fn() -> &i32>() {
5-
| ^ expected lifetime parameter
5+
| ^ help: consider giving it a 'static lifetime: `&'static`
66
|
77
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8-
= help: consider giving it a 'static lifetime
98

109
error: aborting due to previous error
1110

src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/bound-lifetime-in-return-only.rs:44:23
33
|
44
LL | fn elision(_: fn() -> &i32) {
5-
| ^ expected lifetime parameter
5+
| ^ help: consider giving it a 'static lifetime: `&'static`
66
|
77
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8-
= help: consider giving it a 'static lifetime
98

109
error: aborting due to previous error
1110

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-rustfix
12+
13+
extern "C" {
14+
pub fn g(_: &u8) -> &u8; // OK
15+
pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
16+
}
17+
18+
fn main() {}

src/test/ui/foreign-fn-return-lifetime.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// run-rustfix
12+
1113
extern "C" {
12-
fn g(_: &u8) -> &u8; // OK
13-
fn f() -> &u8; //~ ERROR missing lifetime specifier
14+
pub fn g(_: &u8) -> &u8; // OK
15+
pub fn f() -> &u8; //~ ERROR missing lifetime specifier
1416
}
1517

1618
fn main() {}

src/test/ui/foreign-fn-return-lifetime.stderr

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
error[E0106]: missing lifetime specifier
2-
--> $DIR/foreign-fn-return-lifetime.rs:13:15
2+
--> $DIR/foreign-fn-return-lifetime.rs:15:19
33
|
4-
LL | fn f() -> &u8; //~ ERROR missing lifetime specifier
5-
| ^ expected lifetime parameter
4+
LL | pub fn f() -> &u8; //~ ERROR missing lifetime specifier
5+
| ^ help: consider giving it a 'static lifetime: `&'static`
66
|
77
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8-
= help: consider giving it a 'static lifetime
98

109
error: aborting due to previous error
1110

src/test/ui/issues/issue-13497.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/issue-13497.rs:12:5
33
|
44
LL | &str //~ ERROR missing lifetime specifier
5-
| ^ expected lifetime parameter
5+
| ^ help: consider giving it a 'static lifetime: `&'static`
66
|
77
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8-
= help: consider giving it a 'static lifetime
98

109
error: aborting due to previous error
1110

src/test/ui/issues/issue-26638.stderr

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,17 @@ error[E0106]: missing lifetime specifier
1010
--> $DIR/issue-26638.rs:14:40
1111
|
1212
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
13-
| ^ expected lifetime parameter
13+
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
1414
|
1515
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
16-
= help: consider giving it an explicit bounded or 'static lifetime
1716

1817
error[E0106]: missing lifetime specifier
1918
--> $DIR/issue-26638.rs:17:22
2019
|
2120
LL | fn parse_type_3() -> &str { unimplemented!() }
22-
| ^ expected lifetime parameter
21+
| ^ help: consider giving it a 'static lifetime: `&'static`
2322
|
2423
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
25-
= help: consider giving it a 'static lifetime
2624

2725
error: aborting due to 3 previous errors
2826

src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr

+4-8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
22
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:12:11
33
|
44
LL | fn f() -> &isize { //~ ERROR missing lifetime specifier
5-
| ^ expected lifetime parameter
5+
| ^ help: consider giving it a 'static lifetime: `&'static`
66
|
77
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8-
= help: consider giving it a 'static lifetime
98

109
error[E0106]: missing lifetime specifier
1110
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:33
@@ -27,28 +26,25 @@ error[E0106]: missing lifetime specifier
2726
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:31:20
2827
|
2928
LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier
30-
| ^ expected lifetime parameter
29+
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
3130
|
3231
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
33-
= help: consider giving it an explicit bounded or 'static lifetime
3432

3533
error[E0106]: missing lifetime specifier
3634
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:44:24
3735
|
3836
LL | fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier
39-
| ^ expected lifetime parameter
37+
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
4038
|
4139
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
42-
= help: consider giving it an explicit bounded or 'static lifetime
4340

4441
error[E0106]: missing lifetime specifier
4542
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:50:49
4643
|
4744
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
48-
| ^ expected lifetime parameter
45+
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
4946
|
5047
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
51-
= help: consider giving it an explicit bounded or 'static lifetime
5248

5349
error: aborting due to 6 previous errors
5450

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait Future {
2+
type Item;
3+
type Error;
4+
}
5+
6+
use std::error::Error;
7+
8+
fn foo() -> impl Future<Item=(), Error=Box<Error>> {
9+
Ok(())
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/lifetime-elision-return-type-trait.rs:8:44
3+
|
4+
LL | fn foo() -> impl Future<Item=(), Error=Box<Error>> {
5+
| ^^^^^ help: consider giving it a 'static lifetime: `Error + 'static`
6+
|
7+
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0106`.

src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ error[E0106]: missing lifetime specifier
2020
--> $DIR/underscore-lifetime-binders.rs:20:29
2121
|
2222
LL | fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR cannot be used here
23-
| ^^ expected lifetime parameter
23+
| ^^ help: consider giving it a 'static lifetime: `'static`
2424
|
2525
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
26-
= help: consider giving it a 'static lifetime
2726

2827
error[E0106]: missing lifetime specifier
2928
--> $DIR/underscore-lifetime-binders.rs:26:35

0 commit comments

Comments
 (0)