Disallow non-explicit elided lifetimes in async fn
This commit is contained in:
parent
00859e3e65
commit
c6e13bc20b
@ -362,10 +362,6 @@ struct Foo1 { x: &bool }
|
||||
// ^ expected lifetime parameter
|
||||
struct Foo2<'a> { x: &'a bool } // correct
|
||||
|
||||
impl Foo2 {}
|
||||
// ^^^^ expected lifetime parameter
|
||||
impl<'a> Foo2<'a> {} // correct
|
||||
|
||||
struct Bar1 { x: Foo2 }
|
||||
// ^^^^ expected lifetime parameter
|
||||
struct Bar2<'a> { x: Foo2<'a> } // correct
|
||||
@ -2208,4 +2204,5 @@ register_diagnostics! {
|
||||
E0710, // an unknown tool name found in scoped lint
|
||||
E0711, // a feature has been declared with conflicting stability attributes
|
||||
// E0702, // replaced with a generic attribute input check
|
||||
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
||||
}
|
||||
|
@ -2110,15 +2110,49 @@ impl<'a> LoweringContext<'a> {
|
||||
.expect("already checked that type args or bindings exist");
|
||||
(false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
|
||||
};
|
||||
self.sess.buffer_lint_with_diagnostic(
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
CRATE_NODE_ID,
|
||||
path_span,
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
expected_lifetimes, path_span, incl_angl_brckt, insertion_span, suggestion
|
||||
)
|
||||
);
|
||||
match self.anonymous_lifetime_mode {
|
||||
// In create-parameter mode we error here because we don't want to support
|
||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||
// both of which work using the `CreateParameter` mode:
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
|
||||
&self.sess,
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
suggestion,
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
AnonymousLifetimeMode::PassThrough |
|
||||
AnonymousLifetimeMode::ReportError |
|
||||
AnonymousLifetimeMode::Replace(_) => {
|
||||
self.sess.buffer_lint_with_diagnostic(
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
CRATE_NODE_ID,
|
||||
path_span,
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
suggestion,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5298,13 +5332,15 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
match self.anonymous_lifetime_mode {
|
||||
// N.B., We intentionally ignore the create-parameter mode here
|
||||
// and instead "pass through" to resolve-lifetimes, which will then
|
||||
// report an error. This is because we don't want to support
|
||||
// impl elision for deprecated forms like
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
AnonymousLifetimeMode::CreateParameter |
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
// We should have emitted E0726 when processing this path above
|
||||
self.sess.delay_span_bug(
|
||||
span,
|
||||
"expected 'implicit elided lifetime not allowed' error",
|
||||
);
|
||||
let id = self.sess.next_node_id();
|
||||
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
|
||||
}
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
|
@ -477,6 +477,48 @@ pub enum BuiltinLintDiagnostics {
|
||||
RedundantImport(Vec<(Span, bool)>, ast::Ident),
|
||||
}
|
||||
|
||||
pub(crate) fn add_elided_lifetime_in_path_suggestion(
|
||||
sess: &Session,
|
||||
db: &mut DiagnosticBuilder<'_>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
anon_lts: String,
|
||||
) {
|
||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||
(insertion_span, anon_lts)
|
||||
} else {
|
||||
// When possible, prefer a suggestion that replaces the whole
|
||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||
// at a point (which makes for an ugly/confusing label)
|
||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
||||
// But our spans can get out of whack due to macros; if the place we think
|
||||
// we want to insert `'_` isn't even within the path expression's span, we
|
||||
// should bail out of making any suggestion rather than panicking on a
|
||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||
// FIXME: can we do better?
|
||||
if insertion_span.lo().0 < path_span.lo().0 {
|
||||
return;
|
||||
}
|
||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||
if insertion_index > snippet.len() {
|
||||
return;
|
||||
}
|
||||
let (before, after) = snippet.split_at(insertion_index);
|
||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||
} else {
|
||||
(insertion_span, anon_lts)
|
||||
}
|
||||
};
|
||||
db.span_suggestion(
|
||||
replace_span,
|
||||
&format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
}
|
||||
|
||||
impl BuiltinLintDiagnostics {
|
||||
pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder<'_>) {
|
||||
match self {
|
||||
@ -521,36 +563,14 @@ impl BuiltinLintDiagnostics {
|
||||
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
n, path_span, incl_angl_brckt, insertion_span, anon_lts
|
||||
) => {
|
||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||
(insertion_span, anon_lts)
|
||||
} else {
|
||||
// When possible, prefer a suggestion that replaces the whole
|
||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||
// at a point (which makes for an ugly/confusing label)
|
||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
||||
// But our spans can get out of whack due to macros; if the place we think
|
||||
// we want to insert `'_` isn't even within the path expression's span, we
|
||||
// should bail out of making any suggestion rather than panicking on a
|
||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||
// FIXME: can we do better?
|
||||
if insertion_span.lo().0 < path_span.lo().0 {
|
||||
return;
|
||||
}
|
||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||
if insertion_index > snippet.len() {
|
||||
return;
|
||||
}
|
||||
let (before, after) = snippet.split_at(insertion_index);
|
||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||
} else {
|
||||
(insertion_span, anon_lts)
|
||||
}
|
||||
};
|
||||
db.span_suggestion(
|
||||
replace_span,
|
||||
&format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable
|
||||
add_elided_lifetime_in_path_suggestion(
|
||||
sess,
|
||||
db,
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
anon_lts,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
|
||||
|
16
src/test/ui/async-fn-path-elision.rs
Normal file
16
src/test/ui/async-fn-path-elision.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// edition:2018
|
||||
|
||||
#![feature(async_await, await_macro)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct HasLifetime<'a>(&'a bool);
|
||||
|
||||
async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here
|
||||
if *lt.0 {}
|
||||
}
|
||||
|
||||
fn no_error(lt: HasLifetime) {
|
||||
if *lt.0 {}
|
||||
}
|
||||
|
||||
fn main() {}
|
8
src/test/ui/async-fn-path-elision.stderr
Normal file
8
src/test/ui/async-fn-path-elision.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error[E0726]: implicit elided lifetime not allowed here
|
||||
--> $DIR/async-fn-path-elision.rs:8:20
|
||||
|
|
||||
LL | async fn error(lt: HasLifetime) {
|
||||
| ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -5,7 +5,7 @@ trait MyTrait { }
|
||||
struct Foo<'a> { x: &'a u32 }
|
||||
|
||||
impl MyTrait for Foo {
|
||||
//~^ ERROR missing lifetime specifier
|
||||
//~^ ERROR implicit elided lifetime not allowed here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,9 +1,8 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
error[E0726]: implicit elided lifetime not allowed here
|
||||
--> $DIR/path-elided.rs:7:18
|
||||
|
|
||||
LL | impl MyTrait for Foo {
|
||||
| ^^^ expected lifetime parameter
|
||||
| ^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
|
@ -3,7 +3,7 @@
|
||||
trait MyTrait<'a> { }
|
||||
|
||||
impl MyTrait for u32 {
|
||||
//~^ ERROR missing lifetime specifier
|
||||
//~^ ERROR implicit elided lifetime not allowed here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,9 +1,8 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
error[E0726]: implicit elided lifetime not allowed here
|
||||
--> $DIR/trait-elided.rs:5:6
|
||||
|
|
||||
LL | impl MyTrait for u32 {
|
||||
| ^^^^^^^ expected lifetime parameter
|
||||
| ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
|
@ -5,7 +5,8 @@ trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names
|
||||
|
||||
impl<'self> Serializable<str> for &'self str { //~ ERROR lifetimes cannot use keyword names
|
||||
//~^ ERROR lifetimes cannot use keyword names
|
||||
//~| ERROR missing lifetime specifier
|
||||
//~| ERROR implicit elided lifetime not allowed here
|
||||
//~| ERROR the size for values of type `str` cannot be known at compilation time
|
||||
fn serialize(val : &'self str) -> Vec<u8> { //~ ERROR lifetimes cannot use keyword names
|
||||
vec![1]
|
||||
}
|
||||
|
@ -29,23 +29,32 @@ LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:9:25
|
||||
--> $DIR/issue-10412.rs:10:25
|
||||
|
|
||||
LL | fn serialize(val : &'self str) -> Vec<u8> {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:12:37
|
||||
--> $DIR/issue-10412.rs:13:37
|
||||
|
|
||||
LL | fn deserialize(repr: &[u8]) -> &'self str {
|
||||
| ^^^^^
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
error[E0726]: implicit elided lifetime not allowed here
|
||||
--> $DIR/issue-10412.rs:6:13
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
||||
| ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/issue-10412.rs:6:13
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `str`
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user