Skip to content

Suggest appropriate syntax on missing lifetime specifier in return type #55173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 25, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
@@ -1152,7 +1152,7 @@ impl<'a> LoweringContext<'a> {
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
let span = t.span.shrink_to_lo();
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_ref_lifetime(span),
62 changes: 44 additions & 18 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
@@ -2235,21 +2235,46 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
};

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

if let Some(params) = error {
if lifetime_refs.len() == 1 {
self.report_elision_failure(&mut err, params);
add_label = add_label && self.report_elision_failure(&mut err, params, span);
}
}
if add_label {
add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
}

err.emit();
}

fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool {
match self.tcx.sess.source_map().span_to_snippet(span) {
Ok(ref snippet) => {
let (sugg, applicability) = if snippet == "&" {
("&'static ".to_owned(), Applicability::MachineApplicable)
} else if snippet == "'_" {
("'static".to_owned(), Applicability::MachineApplicable)
} else {
(format!("{} + 'static", snippet), Applicability::MaybeIncorrect)
};
db.span_suggestion_with_applicability(span, msg, sugg, applicability);
false
}
Err(_) => {
db.help(msg);
true
}
}
}

fn report_elision_failure(
&mut self,
db: &mut DiagnosticBuilder<'_>,
params: &[ElisionFailureInfo],
) {
span: Span,
) -> bool {
let mut m = String::new();
let len = params.len();

@@ -2304,33 +2329,32 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
"this function's return type contains a borrowed value, but \
there is no value for it to be borrowed from"
);
help!(db, "consider giving it a 'static lifetime");
self.suggest_lifetime(db, span, "consider giving it a 'static lifetime")
} else if elided_len == 0 {
help!(
db,
"this function's return type contains a borrowed value with \
an elided lifetime, but the lifetime cannot be derived from \
the arguments"
);
help!(
db,
"consider giving it an explicit bounded or 'static \
lifetime"
);
let msg = "consider giving it an explicit bounded or 'static lifetime";
self.suggest_lifetime(db, span, msg)
} else if elided_len == 1 {
help!(
db,
"this function's return type contains a borrowed value, but \
the signature does not say which {} it is borrowed from",
m
);
true
} else {
help!(
db,
"this function's return type contains a borrowed value, but \
the signature does not say whether it is borrowed from {}",
m
);
true
}
}

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

pub fn report_missing_lifetime_specifiers(
fn report_missing_lifetime_specifiers(
sess: &Session,
span: Span,
count: usize,
) -> DiagnosticBuilder<'_> {
let mut err = struct_span_err!(
struct_span_err!(
sess,
span,
E0106,
"missing lifetime specifier{}",
if count > 1 { "s" } else { "" }
);
)
}

let msg: Cow<'static, str> = if count > 1 {
format!("expected {} lifetime parameters", count).into()
fn add_missing_lifetime_specifiers_label(
err: &mut DiagnosticBuilder<'_>,
span: Span,
count: usize,
) {
if count > 1 {
err.span_label(span, format!("expected {} lifetime parameters", count));
} else {
"expected lifetime parameter".into()
err.span_label(span, "expected lifetime parameter");
};

err.span_label(span, msg);

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

error: aborting due to previous error

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

error: aborting due to previous error

18 changes: 18 additions & 0 deletions src/test/ui/foreign-fn-return-lifetime.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-rustfix

extern "C" {
pub fn g(_: &u8) -> &u8; // OK
pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
}

fn main() {}
6 changes: 4 additions & 2 deletions src/test/ui/foreign-fn-return-lifetime.rs
Original file line number Diff line number Diff line change
@@ -8,9 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-rustfix

extern "C" {
fn g(_: &u8) -> &u8; // OK
fn f() -> &u8; //~ ERROR missing lifetime specifier
pub fn g(_: &u8) -> &u8; // OK
pub fn f() -> &u8; //~ ERROR missing lifetime specifier
}

fn main() {}
7 changes: 3 additions & 4 deletions src/test/ui/foreign-fn-return-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
error[E0106]: missing lifetime specifier
--> $DIR/foreign-fn-return-lifetime.rs:13:15
--> $DIR/foreign-fn-return-lifetime.rs:15:19
|
LL | fn f() -> &u8; //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
LL | pub fn f() -> &u8; //~ ERROR missing lifetime specifier
| ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-13497.stderr
Original file line number Diff line number Diff line change
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
--> $DIR/issue-13497.rs:12:5
|
LL | &str //~ ERROR missing lifetime specifier
| ^ expected lifetime parameter
| ^ help: consider giving it a 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

error: aborting due to previous error

6 changes: 2 additions & 4 deletions src/test/ui/issues/issue-26638.stderr
Original file line number Diff line number Diff line change
@@ -10,19 +10,17 @@ error[E0106]: missing lifetime specifier
--> $DIR/issue-26638.rs:14:40
|
LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
| ^ expected lifetime parameter
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
= help: consider giving it an explicit bounded or 'static lifetime

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

error: aborting due to 3 previous errors

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

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

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

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

error: aborting due to 6 previous errors

12 changes: 12 additions & 0 deletions src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trait Future {
type Item;
type Error;
}

use std::error::Error;

fn foo() -> impl Future<Item=(), Error=Box<Error>> {
Ok(())
}

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0106]: missing lifetime specifier
--> $DIR/lifetime-elision-return-type-trait.rs:8:44
|
LL | fn foo() -> impl Future<Item=(), Error=Box<Error>> {
| ^^^^^ help: consider giving it a 'static lifetime: `Error + 'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from

error: aborting due to previous error

For more information about this error, try `rustc --explain E0106`.
Original file line number Diff line number Diff line change
@@ -26,10 +26,9 @@ error[E0106]: missing lifetime specifier
--> $DIR/underscore-lifetime-binders.rs:24:29
|
LL | fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR cannot be used here
| ^^ expected lifetime parameter
| ^^ help: consider giving it a 'static lifetime: `'static`
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime

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