Rollup merge of #129207 - GrigorenkoPV:elided-is-named, r=cjgillot

Lint that warns when an elided lifetime ends up being a named lifetime

As suggested in https://github.com/rust-lang/rust/issues/48686#issuecomment-1817334575

Fixes #48686
This commit is contained in:
Matthias Krüger 2024-09-01 03:58:03 +02:00 committed by GitHub
commit 1063c0dd37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 628 additions and 61 deletions

View File

@ -837,7 +837,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
}
LifetimeRes::Static | LifetimeRes::Error => return None,
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
res, ident, ident.span
@ -1656,7 +1656,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
// Opaques do not capture `'static`
LifetimeRes::Static | LifetimeRes::Error => {
LifetimeRes::Static { .. } | LifetimeRes::Error => {
continue;
}
@ -2069,7 +2069,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::LifetimeName::Param(param)
}
LifetimeRes::Infer => hir::LifetimeName::Infer,
LifetimeRes::Static => hir::LifetimeName::Static,
LifetimeRes::Static { .. } => hir::LifetimeName::Static,
LifetimeRes::Error => hir::LifetimeName::Error,
res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}",

View File

@ -27,7 +27,7 @@ impl<'ast> LifetimeCollectVisitor<'ast> {
self.collected_lifetimes.insert(lifetime);
}
}
LifetimeRes::Static | LifetimeRes::Error => {
LifetimeRes::Static { .. } | LifetimeRes::Error => {
self.collected_lifetimes.insert(lifetime);
}
LifetimeRes::Infer => {}

View File

@ -863,8 +863,13 @@ pub enum LifetimeRes {
/// This variant is used for anonymous lifetimes that we did not resolve during
/// late resolution. Those lifetimes will be inferred by typechecking.
Infer,
/// Explicit `'static` lifetime.
Static,
/// `'static` lifetime.
Static {
/// We do not want to emit `elided_named_lifetimes`
/// when we are inside of a const item or a static,
/// because it would get too annoying.
suppress_elision_warning: bool,
},
/// Resolution failure.
Error,
/// HACK: This is used to recover the NodeId of an elided lifetime.

View File

@ -252,6 +252,10 @@ lint_duplicate_macro_attribute =
lint_duplicate_matcher_binding = duplicate matcher binding
lint_elided_named_lifetime = elided lifetime has a name
.label_elided = this elided lifetime gets resolved as `{$name}`
.label_named = lifetime `{$name}` declared here
lint_enum_intrinsics_mem_discriminant =
the return value of `mem::discriminant` is unspecified when called with a non-enum type
.note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum

View File

@ -10,6 +10,7 @@ use rustc_errors::{
use rustc_middle::middle::stability;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::Session;
use rustc_span::symbol::kw;
use rustc_span::BytePos;
use tracing::debug;
@ -441,5 +442,17 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
}
BuiltinLintDiag::ElidedIsStatic { elided } => {
lints::ElidedNamedLifetime { elided, name: kw::StaticLifetime, named_declaration: None }
.decorate_lint(diag)
}
BuiltinLintDiag::ElidedIsParam { elided, param: (param_name, param_span) } => {
lints::ElidedNamedLifetime {
elided,
name: param_name,
named_declaration: Some(param_span),
}
.decorate_lint(diag)
}
}
}

View File

@ -2611,6 +2611,16 @@ pub(crate) struct ElidedLifetimesInPaths {
pub subdiag: ElidedLifetimeInPathSubdiag,
}
#[derive(LintDiagnostic)]
#[diag(lint_elided_named_lifetime)]
pub(crate) struct ElidedNamedLifetime {
#[label(lint_label_elided)]
pub elided: Span,
pub name: Symbol,
#[label(lint_label_named)]
pub named_declaration: Option<Span>,
}
#[derive(LintDiagnostic)]
#[diag(lint_invalid_crate_type_value)]
pub(crate) struct UnknownCrateTypes {

View File

@ -42,6 +42,7 @@ declare_lint_pass! {
DUPLICATE_MACRO_ATTRIBUTES,
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
ELIDED_LIFETIMES_IN_PATHS,
ELIDED_NAMED_LIFETIMES,
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
EXPORTED_PRIVATE_DEPENDENCIES,
FFI_UNWIND_CALLS,
@ -1862,6 +1863,38 @@ declare_lint! {
"hidden lifetime parameters in types are deprecated"
}
declare_lint! {
/// The `elided_named_lifetimes` lint detects when an elided
/// lifetime ends up being a named lifetime, such as `'static`
/// or some lifetime parameter `'a`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(elided_named_lifetimes)]
/// struct Foo;
/// impl Foo {
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
/// unsafe { &mut *(x as *mut _) }
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Lifetime elision is quite useful, because it frees you from having
/// to give each lifetime its own name, but sometimes it can produce
/// somewhat surprising resolutions. In safe code, it is mostly okay,
/// because the borrow checker prevents any unsoundness, so the worst
/// case scenario is you get a confusing error message in some other place.
/// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
pub ELIDED_NAMED_LIFETIMES,
Warn,
"detects when an elided lifetime gets resolved to be `'static` or some named parameter"
}
declare_lint! {
/// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
/// objects.

View File

@ -589,6 +589,13 @@ pub enum BuiltinLintDiag {
},
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
ElidedLifetimesInPaths(usize, Span, bool, Span),
ElidedIsStatic {
elided: Span,
},
ElidedIsParam {
elided: Span,
param: (Symbol, Span),
},
UnknownCrateTypes {
span: Span,
candidate: Option<Symbol>,

View File

@ -1557,14 +1557,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if ident.name == kw::StaticLifetime {
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Static,
LifetimeRes::Static { suppress_elision_warning: false },
LifetimeElisionCandidate::Named,
);
return;
}
if ident.name == kw::UnderscoreLifetime {
return self.resolve_anonymous_lifetime(lifetime, false);
return self.resolve_anonymous_lifetime(lifetime, lifetime.id, false);
}
let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
@ -1667,13 +1667,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
fn resolve_anonymous_lifetime(
&mut self,
lifetime: &Lifetime,
id_for_lint: NodeId,
elided: bool,
) {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
let kind =
if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore };
let missing_lifetime =
MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 };
let missing_lifetime = MissingLifetime {
id: lifetime.id,
span: lifetime.ident.span,
kind,
count: 1,
id_for_lint,
};
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
debug!(?rib.kind);
@ -1697,7 +1707,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if lifetimes_in_scope.is_empty() {
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Static,
// We are inside a const item, so do not warn.
LifetimeRes::Static { suppress_elision_warning: true },
elision_candidate,
);
return;
@ -1800,7 +1811,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
LifetimeElisionCandidate::Ignore,
);
self.resolve_anonymous_lifetime(&lt, true);
self.resolve_anonymous_lifetime(&lt, anchor_id, true);
}
#[instrument(level = "debug", skip(self))]
@ -1916,6 +1927,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
};
let missing_lifetime = MissingLifetime {
id: node_ids.start,
id_for_lint: segment_id,
span: elided_lifetime_span,
kind,
count: expected_lifetimes,
@ -2039,8 +2051,44 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
}
match candidate {
LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => {
debug_assert_eq!(id, missing.id);
match res {
LifetimeRes::Static { suppress_elision_warning } => {
if !suppress_elision_warning {
self.r.lint_buffer.buffer_lint(
lint::builtin::ELIDED_NAMED_LIFETIMES,
missing.id_for_lint,
missing.span,
BuiltinLintDiag::ElidedIsStatic { elided: missing.span },
);
}
}
LifetimeRes::Param { param, binder: _ } => {
let tcx = self.r.tcx();
self.r.lint_buffer.buffer_lint(
lint::builtin::ELIDED_NAMED_LIFETIMES,
missing.id_for_lint,
missing.span,
BuiltinLintDiag::ElidedIsParam {
elided: missing.span,
param: (tcx.item_name(param.into()), tcx.source_span(param)),
},
);
}
LifetimeRes::Fresh { .. }
| LifetimeRes::Infer
| LifetimeRes::Error
| LifetimeRes::ElidedAnchor { .. } => {}
}
}
LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {}
}
match res {
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => {
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
candidates.push((res, candidate));
}
@ -2558,9 +2606,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
self.with_static_rib(def_kind, |this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
});
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Static {
suppress_elision_warning: true,
}),
|this| {
this.visit_ty(ty);
},
);
if let Some(expr) = expr {
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
@ -2589,7 +2642,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
this.visit_generics(generics);
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Static),
LifetimeRibKind::Elided(LifetimeRes::Static {
suppress_elision_warning: true,
}),
|this| this.visit_ty(ty),
);

View File

@ -102,6 +102,13 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
pub(super) struct MissingLifetime {
/// Used to overwrite the resolution with the suggestion, to avoid cascading errors.
pub id: NodeId,
/// As we cannot yet emit lints in this crate and have to buffer them instead,
/// we need to associate each lint with some `NodeId`,
/// however for some `MissingLifetime`s their `NodeId`s are "fake",
/// in a sense that they are temporary and not get preserved down the line,
/// which means that the lints for those nodes will not get emitted.
/// To combat this, we can try to use some other `NodeId`s as a fallback option.
pub id_for_lint: NodeId,
/// Where to suggest adding the lifetime.
pub span: Span,
/// How the lifetime was introduced, to have the correct space and comma.
@ -3028,7 +3035,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
maybe_static = true;
in_scope_lifetimes = vec![(
Ident::with_dummy_span(kw::StaticLifetime),
(DUMMY_NODE_ID, LifetimeRes::Static),
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
)];
}
} else if elided_len == 0 {
@ -3040,7 +3047,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
maybe_static = true;
in_scope_lifetimes = vec![(
Ident::with_dummy_span(kw::StaticLifetime),
(DUMMY_NODE_ID, LifetimeRes::Static),
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
)];
}
} else if num_params == 1 {

View File

@ -2313,7 +2313,7 @@ impl<'b> Pattern for &'b String {
}
#[inline]
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str>
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
where
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
{

View File

@ -110,43 +110,43 @@ impl<'a> Argument<'a> {
}
#[inline(always)]
pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> {
Self::new(x, Display::fmt)
}
#[inline(always)]
pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> {
Self::new(x, Debug::fmt)
}
#[inline(always)]
pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'_> {
pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> {
Self::new(x, |_, _| Ok(()))
}
#[inline(always)]
pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> {
Self::new(x, Octal::fmt)
}
#[inline(always)]
pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> {
Self::new(x, LowerHex::fmt)
}
#[inline(always)]
pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> {
Self::new(x, UpperHex::fmt)
}
#[inline(always)]
pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> {
Self::new(x, Pointer::fmt)
}
#[inline(always)]
pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> {
Self::new(x, Binary::fmt)
}
#[inline(always)]
pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> {
Self::new(x, LowerExp::fmt)
}
#[inline(always)]
pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> {
Self::new(x, UpperExp::fmt)
}
#[inline(always)]

View File

@ -1,3 +1,14 @@
error: elided lifetime has a name
--> tests/ui/needless_lifetimes.rs:266:52
|
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `-D elided-named-lifetimes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
error: the following explicit lifetimes could be elided: 'a, 'b
--> tests/ui/needless_lifetimes.rs:17:23
|
@ -553,5 +564,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 {
LL + fn one_input(x: &u8) -> &u8 {
|
error: aborting due to 46 previous errors
error: aborting due to 47 previous errors

View File

@ -1,3 +1,12 @@
error: elided lifetime has a name
--> tests/ui/ptr_arg.rs:295:56
|
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `-D elided-named-lifetimes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
--> tests/ui/ptr_arg.rs:13:14
|
@ -212,5 +221,5 @@ error: using a reference to `Cow` is not recommended
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
error: aborting due to 24 previous errors
error: aborting due to 25 previous errors

View File

@ -117,7 +117,7 @@ impl Attrs {
}
impl Attrs {
pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'_> {
pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'attrs> {
AttrQuery { attrs: self, key }
}
@ -594,7 +594,7 @@ impl<'attr> AttrQuery<'attr> {
/// #[doc(html_root_url = "url")]
/// ^^^^^^^^^^^^^ key
/// ```
pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&str> {
pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&'attr str> {
self.tt_values().find_map(|tt| {
let name = tt.token_trees.iter()
.skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == *key))

View File

@ -197,7 +197,7 @@ impl Body {
pub fn blocks<'a>(
&'a self,
db: &'a dyn DefDatabase,
) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
}

View File

@ -9,7 +9,7 @@ trait Foo {}
impl Xyz {
async fn do_sth<'a>(
&'a self, foo: &dyn Foo
) -> &dyn Foo
) -> &dyn Foo //~ WARNING elided lifetime has a name
{
//~^ ERROR explicit lifetime required in the type of `foo` [E0621]
foo

View File

@ -1,3 +1,14 @@
warning: elided lifetime has a name
--> $DIR/issue-63388-1.rs:12:10
|
LL | async fn do_sth<'a>(
| -- lifetime `'a` declared here
LL | &'a self, foo: &dyn Foo
LL | ) -> &dyn Foo
| ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0621]: explicit lifetime required in the type of `foo`
--> $DIR/issue-63388-1.rs:13:5
|
@ -10,6 +21,6 @@ LL | | foo
LL | | }
| |_____^ lifetime `'a` required
error: aborting due to 1 previous error
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0621`.

View File

@ -0,0 +1,10 @@
warning: elided lifetime has a name
--> $DIR/issue-71348.rs:18:68
|
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: 1 warning emitted

View File

@ -1,3 +1,11 @@
warning: elided lifetime has a name
--> $DIR/issue-71348.rs:18:68
|
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error: `&'static str` is forbidden as the type of a const generic parameter
--> $DIR/issue-71348.rs:10:24
|
@ -30,5 +38,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable
LL + #![feature(unsized_const_params)]
|
error: aborting due to 2 previous errors
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -17,6 +17,7 @@ trait Get<'a, const N: &'static str> {
impl Foo {
fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
//[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
//~^^ WARNING elided lifetime has a name
where
Self: Get<'a, N>,
{

View File

@ -44,8 +44,8 @@ impl<T> Foo<T> {
impl<'a, T> Foo<T> {
const fn new_lt(t: T) -> Self { Foo(t) }
const fn into_inner_lt(self) -> T { self.0 } //~ destructor of
const fn get_lt(&'a self) -> &T { &self.0 }
const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
const fn get_lt(&'a self) -> &T { &self.0 } //~ WARNING elided lifetime has a name
const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } //~ WARNING elided lifetime has a name
//~^ mutable references
//~| mutable references
//~| mutable references

View File

@ -1,3 +1,23 @@
warning: elided lifetime has a name
--> $DIR/min_const_fn.rs:47:34
|
LL | impl<'a, T> Foo<T> {
| -- lifetime `'a` declared here
...
LL | const fn get_lt(&'a self) -> &T { &self.0 }
| ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: elided lifetime has a name
--> $DIR/min_const_fn.rs:48:42
|
LL | impl<'a, T> Foo<T> {
| -- lifetime `'a` declared here
...
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
| ^ this elided lifetime gets resolved as `'a`
error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:37:25
|
@ -228,7 +248,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
| |
| the destructor for this type cannot be evaluated in constant functions
error: aborting due to 24 previous errors
error: aborting due to 24 previous errors; 2 warnings emitted
Some errors have detailed explanations: E0493, E0658.
For more information about an error, try `rustc --explain E0493`.

View File

@ -1,5 +1,5 @@
//@ run-rustfix
#![allow(dead_code)]
#![allow(dead_code, elided_named_lifetimes)]
#![deny(no_mangle_generic_items)]
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled

View File

@ -1,5 +1,5 @@
//@ run-rustfix
#![allow(dead_code)]
#![allow(dead_code, elided_named_lifetimes)]
#![deny(no_mangle_generic_items)]
#[no_mangle]

View File

@ -13,6 +13,7 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
//~| WARNING elided lifetime has a name
|x| x
}

View File

@ -1,5 +1,5 @@
error[E0106]: missing lifetime specifier
--> $DIR/impl-fn-hrtb-bounds.rs:19:38
--> $DIR/impl-fn-hrtb-bounds.rs:20:38
|
LL | fn d() -> impl Fn() -> (impl Debug + '_) {
| ^^ expected named lifetime parameter
@ -10,6 +10,14 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
| ~~~~~~~
warning: elided lifetime has a name
--> $DIR/impl-fn-hrtb-bounds.rs:14:52
|
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
--> $DIR/impl-fn-hrtb-bounds.rs:4:41
|
@ -46,7 +54,7 @@ note: lifetime declared here
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
| ^^
error: aborting due to 4 previous errors
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0106, E0657.
For more information about an error, try `rustc --explain E0106`.

View File

@ -3,6 +3,7 @@ use std::fmt::Debug;
fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
//~^ ERROR cannot resolve opaque type
//~| WARNING elided lifetime has a name
|x| x
//~^ ERROR expected generic lifetime parameter, found `'_`
}

View File

@ -1,9 +1,17 @@
warning: elided lifetime has a name
--> $DIR/impl-fn-predefined-lifetimes.rs:4:48
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/impl-fn-predefined-lifetimes.rs:6:9
--> $DIR/impl-fn-predefined-lifetimes.rs:7:9
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
| -- this generic parameter must be used with a generic lifetime parameter
LL |
...
LL | |x| x
| ^
@ -13,7 +21,7 @@ error[E0720]: cannot resolve opaque type
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
error: aborting due to 2 previous errors
error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0720, E0792.
For more information about an error, try `rustc --explain E0720`.

View File

@ -1,6 +1,7 @@
//@ check-pass
pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
//~^ WARNING elided lifetime has a name
v.into_iter()
}

View File

@ -0,0 +1,10 @@
warning: elided lifetime has a name
--> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82
|
LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: 1 warning emitted

View File

@ -47,5 +47,6 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
// This is ok because both `'a` are for the same parameter.
fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
//~^ WARNING elided lifetime has a name
fn main() {}

View File

@ -105,6 +105,16 @@ help: consider using the `'a` lifetime
LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
| ++
error: aborting due to 7 previous errors
warning: elided lifetime has a name
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29
|
LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error: aborting due to 7 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0106`.

View File

@ -4,6 +4,7 @@ struct Foo {
impl Foo {
fn foo<'a>(&'a self, x: &i32) -> &i32 {
//~^ WARNING elided lifetime has a name
if true { &self.field } else { x } //~ ERROR explicit lifetime

View File

@ -1,12 +1,22 @@
warning: elided lifetime has a name
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36
|
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:8:36
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36
|
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
LL |
...
LL | if true { &self.field } else { x }
| ^ lifetime `'a` required
error: aborting due to 1 previous error
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0621`.

View File

@ -0,0 +1,12 @@
#![deny(elided_named_lifetimes)]
struct Foo;
impl Foo {
pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
//~^ ERROR elided lifetime has a name
unsafe { &mut *(x as *mut _) }
}
}
fn main() {}

View File

@ -0,0 +1,14 @@
error: elided lifetime has a name
--> $DIR/example-from-issue48686.rs:6:50
|
LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
| ^ this elided lifetime gets resolved as `'static`
|
note: the lint level is defined here
--> $DIR/example-from-issue48686.rs:1:9
|
LL | #![deny(elided_named_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,27 @@
#![deny(elided_named_lifetimes)]
fn ampersand<'a>(x: &'a u8) -> &u8 {
//~^ ERROR elided lifetime has a name
x
}
struct Brackets<'a>(&'a u8);
fn brackets<'a>(x: &'a u8) -> Brackets {
//~^ ERROR elided lifetime has a name
Brackets(x)
}
struct Comma<'a, T>(&'a T);
fn comma<'a>(x: &'a u8) -> Comma<u8> {
//~^ ERROR elided lifetime has a name
Comma(x)
}
fn underscore<'a>(x: &'a u8) -> &'_ u8 {
//~^ ERROR elided lifetime has a name
x
}
fn main() {}

View File

@ -0,0 +1,40 @@
error: elided lifetime has a name
--> $DIR/missing-lifetime-kind.rs:3:32
|
LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
note: the lint level is defined here
--> $DIR/missing-lifetime-kind.rs:1:9
|
LL | #![deny(elided_named_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: elided lifetime has a name
--> $DIR/missing-lifetime-kind.rs:10:31
|
LL | fn brackets<'a>(x: &'a u8) -> Brackets {
| -- ^^^^^^^^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
error: elided lifetime has a name
--> $DIR/missing-lifetime-kind.rs:17:33
|
LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
error: elided lifetime has a name
--> $DIR/missing-lifetime-kind.rs:22:34
|
LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
| -- ^^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
error: aborting due to 4 previous errors

View File

@ -0,0 +1,17 @@
#![allow(elided_named_lifetimes)]
#[warn(elided_named_lifetimes)]
mod foo {
fn bar(x: &'static u8) -> &u8 {
//~^ WARNING elided lifetime has a name
x
}
#[deny(elided_named_lifetimes)]
fn baz(x: &'static u8) -> &u8 {
//~^ ERROR elided lifetime has a name
x
}
}
fn main() {}

View File

@ -0,0 +1,26 @@
warning: elided lifetime has a name
--> $DIR/not-tied-to-crate.rs:5:31
|
LL | fn bar(x: &'static u8) -> &u8 {
| ^ this elided lifetime gets resolved as `'static`
|
note: the lint level is defined here
--> $DIR/not-tied-to-crate.rs:3:8
|
LL | #[warn(elided_named_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: elided lifetime has a name
--> $DIR/not-tied-to-crate.rs:11:31
|
LL | fn baz(x: &'static u8) -> &u8 {
| ^ this elided lifetime gets resolved as `'static`
|
note: the lint level is defined here
--> $DIR/not-tied-to-crate.rs:10:12
|
LL | #[deny(elided_named_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -0,0 +1,46 @@
#![deny(elided_named_lifetimes)]
use std::borrow::Cow;
const A: &[u8] = &[];
static B: &str = "hello";
trait Trait {
const C: &u8 = &0;
}
impl Trait for () {
const C: &u8 = &1;
}
fn ampersand(x: &'static u8) -> &u8 {
//~^ ERROR elided lifetime has a name
x
}
struct Brackets<'a>(&'a u8);
fn brackets(x: &'static u8) -> Brackets {
//~^ ERROR elided lifetime has a name
Brackets(x)
}
struct Comma<'a, T>(&'a T);
fn comma(x: &'static u8) -> Comma<u8> {
//~^ ERROR elided lifetime has a name
Comma(x)
}
fn underscore(x: &'static u8) -> &'_ u8 {
//~^ ERROR elided lifetime has a name
x
}
const NESTED: &Vec<&Box<Cow<str>>> = &vec![];
fn main() {
const HELLO: &str = "Hello";
static WORLD: &str = "world";
println!("{HELLO}, {WORLD}!")
}

View File

@ -0,0 +1,32 @@
error: elided lifetime has a name
--> $DIR/static.rs:16:33
|
LL | fn ampersand(x: &'static u8) -> &u8 {
| ^ this elided lifetime gets resolved as `'static`
|
note: the lint level is defined here
--> $DIR/static.rs:1:9
|
LL | #![deny(elided_named_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: elided lifetime has a name
--> $DIR/static.rs:23:32
|
LL | fn brackets(x: &'static u8) -> Brackets {
| ^^^^^^^^ this elided lifetime gets resolved as `'static`
error: elided lifetime has a name
--> $DIR/static.rs:30:34
|
LL | fn comma(x: &'static u8) -> Comma<u8> {
| ^ this elided lifetime gets resolved as `'static`
error: elided lifetime has a name
--> $DIR/static.rs:35:35
|
LL | fn underscore(x: &'static u8) -> &'_ u8 {
| ^^ this elided lifetime gets resolved as `'static`
error: aborting due to 4 previous errors

View File

@ -46,6 +46,8 @@ fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait {
}
fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
//~^ WARNING elided lifetime has a name
// Same as `load1` but with an explicit name thrown in for fun.
ss

View File

@ -1,5 +1,15 @@
warning: elided lifetime has a name
--> $DIR/object-lifetime-default-elision.rs:48:40
|
LL | fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error: lifetime may not live long enough
--> $DIR/object-lifetime-default-elision.rs:71:5
--> $DIR/object-lifetime-default-elision.rs:73:5
|
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
| -- -- lifetime `'b` defined here
@ -11,5 +21,5 @@ LL | ss
|
= help: consider adding the following bound: `'a: 'b`
error: aborting due to 1 previous error
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -4,9 +4,11 @@ struct Foo<'a>(&'a str);
impl<'b> Foo<'b> {
fn a<'a>(self: Self, a: &'a str) -> &str {
//~^ WARNING elided lifetime has a name
a
}
fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
//~^ WARNING elided lifetime has a name
a
}
}

View File

@ -0,0 +1,16 @@
warning: elided lifetime has a name
--> $DIR/ignore-non-reference-lifetimes.rs:6:41
|
LL | fn a<'a>(self: Self, a: &'a str) -> &str {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: elided lifetime has a name
--> $DIR/ignore-non-reference-lifetimes.rs:10:44
|
LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
warning: 2 warnings emitted

View File

@ -1,6 +1,6 @@
//@ edition:2018
//@ run-rustfix
#![allow(non_snake_case, dead_code)]
#![allow(non_snake_case, dead_code, elided_named_lifetimes)]
use std::pin::Pin;

View File

@ -1,6 +1,6 @@
//@ edition:2018
//@ run-rustfix
#![allow(non_snake_case, dead_code)]
#![allow(non_snake_case, dead_code, elided_named_lifetimes)]
use std::pin::Pin;

View File

@ -4,11 +4,13 @@
struct Foo<'a>(&'a ());
impl<'a> Foo<'a> {
async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
//~^ WARNING elided lifetime has a name
}
type Alias = Foo<'static>;
impl Alias {
async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
//~^ WARNING elided lifetime has a name
}
fn main() {}

View File

@ -0,0 +1,18 @@
warning: elided lifetime has a name
--> $DIR/self_lifetime-async.rs:6:44
|
LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
| -- ^ this elided lifetime gets resolved as `'b`
| |
| lifetime `'b` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: elided lifetime has a name
--> $DIR/self_lifetime-async.rs:12:52
|
LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
warning: 2 warnings emitted

View File

@ -5,11 +5,13 @@
struct Foo<'a>(&'a ());
impl<'a> Foo<'a> {
fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
//~^ WARNING elided lifetime has a name
}
type Alias = Foo<'static>;
impl Alias {
fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
//~^ WARNING elided lifetime has a name
}
fn main() {}

View File

@ -0,0 +1,18 @@
warning: elided lifetime has a name
--> $DIR/self_lifetime.rs:7:38
|
LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
| -- ^ this elided lifetime gets resolved as `'b`
| |
| lifetime `'b` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
warning: elided lifetime has a name
--> $DIR/self_lifetime.rs:13:46
|
LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
warning: 2 warnings emitted

View File

@ -64,6 +64,7 @@ mod in_path {
// This must not err, as the `&` actually resolves to `'a`.
fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) {
//~^ WARNING elided lifetime has a name
f("f");
}

View File

@ -124,6 +124,14 @@ LL - fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() }
|
warning: elided lifetime has a name
--> $DIR/impl-trait-missing-lifetime-gated.rs:66:57
|
LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0658]: anonymous lifetimes in `impl Trait` are unstable
--> $DIR/impl-trait-missing-lifetime-gated.rs:6:35
|
@ -244,7 +252,7 @@ help: consider introducing a named lifetime parameter
LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() }
| ++++ +++
error: aborting due to 16 previous errors
error: aborting due to 16 previous errors; 1 warning emitted
Some errors have detailed explanations: E0106, E0658.
For more information about an error, try `rustc --explain E0106`.

View File

@ -100,6 +100,7 @@ where
// This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions:
fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
//~^ WARNING elided lifetime has a name
where
G: Get<T>,
{

View File

@ -6,6 +6,14 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| |
| help: consider introducing lifetime `'a` here: `'a,`
warning: elided lifetime has a name
--> $DIR/missing-lifetimes-in-signature.rs:102:64
|
LL | fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
@ -125,7 +133,7 @@ help: consider adding an explicit lifetime bound
LL | G: Get<T> + 'a,
| ++++
error: aborting due to 8 previous errors
error: aborting due to 8 previous errors; 1 warning emitted
Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700.
For more information about an error, try `rustc --explain E0261`.

View File

@ -2,7 +2,7 @@
type Opaque2<T> = impl Sized;
type Opaque<'a, T> = Opaque2<T>;
fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x } //~ WARNING elided lifetime has a name
//~^ ERROR: hidden type for `Opaque2<T>` captures lifetime that does not appear in bounds
fn main() {}

View File

@ -1,3 +1,13 @@
warning: elided lifetime has a name
--> $DIR/missing_lifetime_bound.rs:5:41
|
LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `#[warn(elided_named_lifetimes)]` on by default
error[E0700]: hidden type for `Opaque2<T>` captures lifetime that does not appear in bounds
--> $DIR/missing_lifetime_bound.rs:5:47
|
@ -9,6 +19,6 @@ LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
| |
| hidden type `&'a i32` captures the lifetime `'a` as defined here
error: aborting due to 1 previous error
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0700`.