Skip to content

Stop errorring for elided lifetimes in path. #96957

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0726.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#### Note: this error code is no longer emitted by the compiler.

An argument lifetime was elided in an async function.

Erroneous code example:
Expand All @@ -7,7 +9,7 @@ the Rust compiler to know, on usage, the lifespan of the type. When the
lifetime is not explicitly mentioned and the Rust Compiler cannot determine
the lifetime of your type, the following error occurs.

```compile_fail,E0726
```compile_fail
use futures::executor::block_on;
struct Content<'a> {
title: &'a str,
Expand Down
133 changes: 63 additions & 70 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,7 @@ enum LifetimeRibKind {
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
AnonConst,

/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
/// For **Dyn Bound** cases, pass responsibility to
/// `resolve_lifetime` code.
///
/// For **Deprecated** cases, report an error.
/// Create a new anonymous region parameter and reference that.
AnonymousCreateParameter(NodeId),

/// Give a hard error when either `&` or `'_` is written. Used to
Expand Down Expand Up @@ -1301,7 +1295,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let rib = &mut self.lifetime_ribs[i];
match rib.kind {
LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
let region =
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
self.record_lifetime_res(lifetime.id, region);
return;
}
LifetimeRibKind::AnonymousReportError => {
Expand Down Expand Up @@ -1358,7 +1354,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}

#[tracing::instrument(level = "debug", skip(self))]
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
fn create_fresh_lifetime(
&mut self,
id: NodeId,
ident: Ident,
item_node_id: NodeId,
) -> LifetimeRes {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
debug!(?ident.span);
let item_def_id = self.r.local_def_id(item_node_id);
Expand All @@ -1373,12 +1374,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!(?def_id);

let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
self.record_lifetime_res(id, region);
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
ident,
def_node_id,
region,
));
region
}

#[tracing::instrument(level = "debug", skip(self))]
Expand Down Expand Up @@ -1428,16 +1429,43 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
| PathSource::Struct
| PathSource::TupleStruct(..) => false,
};
let mut res = LifetimeRes::Error;

let node_ids = self.r.next_node_ids(expected_lifetimes);
self.record_lifetime_res(
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
);

if !missing {
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(
id,
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true },
);
}
continue;
}

let elided_lifetime_span = if segment.has_generic_args {
// If there are brackets, but not generic arguments, then use the opening bracket
segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
} else {
// If there are no brackets, use the identifier span.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
};

for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
// 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>) { ... }
LifetimeRibKind::AnonymousCreateParameter(_) => {
LifetimeRibKind::AnonymousCreateParameter(binder) => {
let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
let res = self.create_fresh_lifetime(id, ident, binder);
self.record_lifetime_res(id, res);
}
break;
}
// `PassThrough` is the normal case.
Expand All @@ -1447,75 +1475,40 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
res = LifetimeRes::Anonymous { binder, elided: true };
let res = LifetimeRes::Anonymous { binder, elided: true };
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(id, res);
}
break;
}
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
// FIXME(cjgillot) This resolution is wrong, but this does not matter
// since these cases are erroneous anyway. Lifetime resolution should
// emit a "missing lifetime specifier" diagnostic.
res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(id, res);
}
break;
}
_ => {}
}
}

let node_ids = self.r.next_node_ids(expected_lifetimes);
self.record_lifetime_res(
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
segment_id,
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
);
for i in 0..expected_lifetimes {
let id = node_ids.start.plus(i);
self.record_lifetime_res(id, res);
}

if !missing {
continue;
}

let elided_lifetime_span = if segment.has_generic_args {
// If there are brackets, but not generic arguments, then use the opening bracket
segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
} else {
// If there are no brackets, use the identifier span.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
};
if let LifetimeRes::Error = res {
let sess = self.r.session;
let mut err = rustc_errors::struct_span_err!(
sess,
path_span,
E0726,
"implicit elided lifetime not allowed here"
);
rustc_errors::add_elided_lifetime_in_path_suggestion(
sess.source_map(),
&mut err,
elided_lifetime_span,
"hidden lifetime parameters in types are deprecated",
lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
expected_lifetimes,
path_span,
!segment.has_generic_args,
elided_lifetime_span,
);
err.note("assuming a `'static` lifetime...");
err.emit();
} else {
self.r.lint_buffer.buffer_lint_with_diagnostic(
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
segment_id,
elided_lifetime_span,
"hidden lifetime parameters in types are deprecated",
lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
expected_lifetimes,
path_span,
!segment.has_generic_args,
elided_lifetime_span,
),
);
}
),
);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/async-await/async-fn-path-elision.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// edition:2018
#![deny(elided_lifetimes_in_paths)]

struct HasLifetime<'a>(&'a bool);

async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here
async fn error(lt: HasLifetime) { //~ ERROR hidden lifetime parameters in types are deprecated
if *lt.0 {}
}

fn no_error(lt: HasLifetime) {
fn also_error(lt: HasLifetime) { //~ ERROR hidden lifetime parameters in types are deprecated
if *lt.0 {}
}

Expand Down
24 changes: 19 additions & 5 deletions src/test/ui/async-await/async-fn-path-elision.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
error[E0726]: implicit elided lifetime not allowed here
--> $DIR/async-fn-path-elision.rs:5:20
error: hidden lifetime parameters in types are deprecated
--> $DIR/async-fn-path-elision.rs:6:20
|
LL | async fn error(lt: HasLifetime) {
| ^^^^^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
note: the lint level is defined here
--> $DIR/async-fn-path-elision.rs:2:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
help: indicate the anonymous lifetime
|
LL | async fn error(lt: HasLifetime<'_>) {
| ++++

error: aborting due to previous error
error: hidden lifetime parameters in types are deprecated
--> $DIR/async-fn-path-elision.rs:10:19
|
LL | fn also_error(lt: HasLifetime) {
| ^^^^^^^^^^^ expected lifetime parameter
|
help: indicate the anonymous lifetime
|
LL | fn also_error(lt: HasLifetime<'_>) {
| ++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0726`.
4 changes: 2 additions & 2 deletions src/test/ui/impl-header-lifetime-elision/path-elided.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![allow(warnings)]
#![deny(elided_lifetimes_in_paths)]

trait MyTrait { }

struct Foo<'a> { x: &'a u32 }

impl MyTrait for Foo {
//~^ ERROR implicit elided lifetime not allowed here
//~^ ERROR hidden lifetime parameters in types are deprecated [elided_lifetimes_in_paths]
}

fn main() {}
9 changes: 6 additions & 3 deletions src/test/ui/impl-header-lifetime-elision/path-elided.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
error[E0726]: implicit elided lifetime not allowed here
error: hidden lifetime parameters in types are deprecated
--> $DIR/path-elided.rs:7:18
|
LL | impl MyTrait for Foo {
| ^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
note: the lint level is defined here
--> $DIR/path-elided.rs:1:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
help: indicate the anonymous lifetime
|
LL | impl MyTrait for Foo<'_> {
| ++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0726`.
4 changes: 2 additions & 2 deletions src/test/ui/impl-header-lifetime-elision/trait-elided.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![allow(warnings)]
#![deny(elided_lifetimes_in_paths)]

trait MyTrait<'a> {}

impl MyTrait for u32 {}
//~^ ERROR implicit elided lifetime not allowed here
//~^ ERROR hidden lifetime parameters in types are deprecated [elided_lifetimes_in_paths]

fn main() {}
9 changes: 6 additions & 3 deletions src/test/ui/impl-header-lifetime-elision/trait-elided.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
error[E0726]: implicit elided lifetime not allowed here
error: hidden lifetime parameters in types are deprecated
--> $DIR/trait-elided.rs:5:6
|
LL | impl MyTrait for u32 {}
| ^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
note: the lint level is defined here
--> $DIR/trait-elided.rs:1:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
help: indicate the anonymous lifetime
|
LL | impl MyTrait<'_> for u32 {}
| ++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0726`.
1 change: 0 additions & 1 deletion src/test/ui/issues/issue-10412.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ trait Serializable<'self, T> {
impl<'self> Serializable<str> for &'self str {
//~^ ERROR lifetimes cannot use keyword names
//~| ERROR lifetimes cannot use keyword names
//~| ERROR implicit elided lifetime not allowed here
//~| ERROR the size for values of type `str` cannot be known at compilation time [E0277]
fn serialize(val: &'self str) -> Vec<u8> {
//~^ ERROR lifetimes cannot use keyword names
Expand Down
21 changes: 4 additions & 17 deletions src/test/ui/issues/issue-10412.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,17 @@ LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^

error: lifetimes cannot use keyword names
--> $DIR/issue-10412.rs:12:24
--> $DIR/issue-10412.rs:11:24
|
LL | fn serialize(val: &'self str) -> Vec<u8> {
| ^^^^^

error: lifetimes cannot use keyword names
--> $DIR/issue-10412.rs:16:37
--> $DIR/issue-10412.rs:15:37
|
LL | fn deserialize(repr: &[u8]) -> &'self str {
| ^^^^^

error[E0726]: implicit elided lifetime not allowed here
--> $DIR/issue-10412.rs:7:13
|
LL | impl<'self> Serializable<str> for &'self str {
| ^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
= note: assuming a `'static` lifetime...
help: indicate the anonymous lifetime
|
LL | impl<'self> Serializable<'_, str> for &'self str {
| +++

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/issue-10412.rs:7:13
|
Expand All @@ -69,7 +57,6 @@ help: consider relaxing the implicit `Sized` restriction
LL | trait Serializable<'self, T: ?Sized> {
| ++++++++

error: aborting due to 9 previous errors
error: aborting due to 8 previous errors

Some errors have detailed explanations: E0277, E0726.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0277`.
5 changes: 3 additions & 2 deletions src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// check-pass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's surprising that this change is only picked up in this test. I would have expected it to be picked up in a parsing or lowering test or something.

Regardless, this change will need a lang (probably) FCP. FWIW, I personally don't think allowing elided lifetimes in impl headers is the right move. It's 1) inconsistent with the general trend of not allow elided lifetime parameters and 2) unspecified on if it would be 'static (as is assumed today under error conditions or some new lifetime (which would be the case if you did '_.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also maybe a bit confused here. I guess the ELIDED_LIFETIMES_IN_PATHS lint is allow by default, but was erroring. Is that what you're cleaning up?

// Regression test for #80468.

#![crate_type = "lib"]
Expand All @@ -10,8 +11,8 @@ pub struct Wrapper<T: Trait>(T);
#[repr(transparent)]
pub struct Ref<'a>(&'a u8);

impl Trait for Ref {} //~ ERROR: implicit elided lifetime not allowed here
impl Trait for Ref {}

extern "C" {
pub fn repro(_: Wrapper<Ref>); //~ ERROR: incompatible lifetime on type
pub fn repro(_: Wrapper<Ref>);
}
Loading