about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2022-11-06 11:40:31 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2022-11-24 17:48:59 +0000
commit1c737d69979b36a33e80241c12565e5228bd75a5 (patch)
treeea8d77c5b86b3a27e52f8de920c1f235c5aecb07
parent41090346d844b625ac58004066184d34a9d24f99 (diff)
downloadrust-1c737d69979b36a33e80241c12565e5228bd75a5.tar.gz
rust-1c737d69979b36a33e80241c12565e5228bd75a5.zip
Use kw::Empty for elided lifetimes in path.
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs40
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs14
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs11
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--src/librustdoc/clean/mod.rs28
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs66
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr162
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs14
12 files changed, 281 insertions, 83 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c6558f582eb..b3d56d57642 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2101,7 +2101,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::LifetimeName::Param(param)
             }
             LifetimeRes::Fresh { param, .. } => {
-                debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
                 let param = self.local_def_id(param);
                 hir::LifetimeName::Param(param)
             }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 27b44c0b6a2..dc85b5e95ea 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -309,7 +309,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let id = NodeId::from_u32(i);
                 let l = self.lower_lifetime(&Lifetime {
                     id,
-                    ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
+                    ident: Ident::new(kw::Empty, elided_lifetime_span),
                 });
                 GenericArg::Lifetime(l)
             }),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 4ac783729e6..0f216457c87 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -29,14 +29,15 @@ use std::fmt;
 #[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
 pub struct Lifetime {
     pub hir_id: HirId,
-    pub ident: Ident,
 
     /// Either "`'a`", referring to a named lifetime definition,
-    /// or "``" (i.e., `kw::Empty`), for elision placeholders.
+    /// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`),
+    /// or "``" (i.e., `kw::Empty`) when appearing in path.
     ///
-    /// HIR lowering inserts these placeholders in type paths that
-    /// refer to type definitions needing lifetime parameters,
-    /// `&T` and `&mut T`, and trait objects without `... + 'a`.
+    /// See `Lifetime::suggestion_position` for practical use.
+    pub ident: Ident,
+
+    /// Semantics of this lifetime.
     pub res: LifetimeName,
 }
 
@@ -135,6 +136,19 @@ impl fmt::Display for Lifetime {
     }
 }
 
+pub enum LifetimeSuggestionPosition {
+    /// The user wrote `'a` or `'_`.
+    Normal,
+    /// The user wrote `&type` or `&mut type`.
+    Ampersand,
+    /// The user wrote `Path` and omitted the `<'_>`.
+    ElidedPath,
+    /// The user wrote `Path<T>`, and omitted the `'_,`.
+    ElidedPathArgument,
+    /// The user wrote `dyn Trait` and omitted the `+ '_`.
+    ObjectDefault,
+}
+
 impl Lifetime {
     pub fn is_elided(&self) -> bool {
         self.res.is_elided()
@@ -144,6 +158,22 @@ impl Lifetime {
         self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
     }
 
+    pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
+        if self.ident.name == kw::Empty {
+            if self.ident.span.is_empty() {
+                (LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
+            } else {
+                (LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
+            }
+        } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault {
+            (LifetimeSuggestionPosition::ObjectDefault, self.ident.span)
+        } else if self.ident.span.is_empty() {
+            (LifetimeSuggestionPosition::Ampersand, self.ident.span)
+        } else {
+            (LifetimeSuggestionPosition::Normal, self.ident.span)
+        }
+    }
+
     pub fn is_static(&self) -> bool {
         self.res == LifetimeName::Static
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 892bd237e26..ca71f42f344 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -19,7 +19,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::DefId;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use std::fmt;
 
@@ -1218,13 +1218,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                 (generics.span, "<'a>".to_owned())
                             };
 
-                            let lifetime_sugg = match lifetime_ref.ident.name {
-                                kw::Empty => "'a, ".to_owned(),
-                                kw::UnderscoreLifetime => "'a ".to_owned(),
-                                _ => "'a ".to_owned(),
+                            let lifetime_sugg = match lifetime_ref.suggestion_position() {
+                                (hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
+                                (hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
+                                (hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
+                                (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
+                                (hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
                             };
                             let suggestions = vec![
-                                (lifetime_ref.ident.span.shrink_to_hi(), lifetime_sugg),
+                                lifetime_sugg,
                                 new_param_sugg,
                             ];
 
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 19754d1453f..a8da93e4c69 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -3,7 +3,7 @@ use crate::ty::{EarlyBinder, SubstsRef};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
 use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
@@ -78,6 +78,15 @@ impl GenericParamDef {
         }
     }
 
+    pub fn is_anonymous_lifetime(&self) -> bool {
+        match self.kind {
+            GenericParamDefKind::Lifetime => {
+                self.name == kw::UnderscoreLifetime || self.name == kw::Empty
+            }
+            _ => false,
+        }
+    }
+
     pub fn default_value<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 5ef5013cac1..af90f644aa0 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -530,7 +530,7 @@ impl ty::EarlyBoundRegion {
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
     pub fn has_name(&self) -> bool {
-        self.name != kw::UnderscoreLifetime
+        self.name != kw::UnderscoreLifetime && self.name != kw::Empty
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index bddcdd0b693..8064ab8035e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1963,17 +1963,13 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
 
         match *region {
-            ty::ReEarlyBound(ref data) => {
-                data.name != kw::Empty && data.name != kw::UnderscoreLifetime
-            }
+            ty::ReEarlyBound(ref data) => data.has_name(),
 
             ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
             | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
             | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
-                if let ty::BrNamed(_, name) = br {
-                    if name != kw::Empty && name != kw::UnderscoreLifetime {
-                        return true;
-                    }
+                if br.is_named() {
+                    return true;
                 }
 
                 if let Some((region, _)) = highlight.highlight_bound_region {
@@ -2049,11 +2045,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
             | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
             | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
-                if let ty::BrNamed(_, name) = br {
-                    if name != kw::Empty && name != kw::UnderscoreLifetime {
-                        p!(write("{}", name));
-                        return Ok(self);
-                    }
+                if let ty::BrNamed(_, name) = br && br.is_named() {
+                    p!(write("{}", name));
+                    return Ok(self);
                 }
 
                 if let Some((region, counter)) = highlight.highlight_bound_region {
@@ -2266,7 +2260,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
 
                         (name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
                     }
-                    ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                    ty::BrNamed(def_id, kw::UnderscoreLifetime | kw::Empty) => {
                         let name = next_name(&self);
 
                         if let Some(lt_idx) = lifetime_idx {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e7a751fa0af..40eef3f8dec 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -83,7 +83,9 @@ pub struct BoundRegion {
 impl BoundRegionKind {
     pub fn is_named(&self) -> bool {
         match *self {
-            BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime,
+            BoundRegionKind::BrNamed(_, name) => {
+                name != kw::UnderscoreLifetime && name != kw::Empty
+            }
             _ => false,
         }
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 25ee4463f0d..9c2a55fb6c2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -182,9 +182,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
         .collect_referenced_late_bound_regions(&poly_trait_ref)
         .into_iter()
         .filter_map(|br| match br {
-            ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => {
-                Some(GenericParamDef::lifetime(name))
-            }
+            ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
             _ => None,
         })
         .collect();
@@ -233,16 +231,11 @@ pub(crate) fn clean_middle_const<'tcx>(
 pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
     match *region {
         ty::ReStatic => Some(Lifetime::statik()),
+        _ if !region.has_name() => None,
         ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
-            if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
-        }
-        ty::ReEarlyBound(ref data) => {
-            if data.name != kw::UnderscoreLifetime {
-                Some(Lifetime(data.name))
-            } else {
-                None
-            }
+            Some(Lifetime(name))
         }
+        ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
         ty::ReLateBound(..)
         | ty::ReFree(..)
         | ty::ReVar(..)
@@ -396,7 +389,7 @@ fn clean_projection_predicate<'tcx>(
         .collect_referenced_late_bound_regions(&pred)
         .into_iter()
         .filter_map(|br| match br {
-            ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(Lifetime(name)),
+            ty::BrNamed(_, name) if br.is_named() => Some(Lifetime(name)),
             _ => None,
         })
         .collect();
@@ -660,7 +653,7 @@ fn clean_ty_generics<'tcx>(
         .params
         .iter()
         .filter_map(|param| match param.kind {
-            ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None,
+            ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
             ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
             ty::GenericParamDefKind::Type { synthetic, .. } => {
                 if param.name == kw::SelfUpper {
@@ -1460,8 +1453,11 @@ fn maybe_expand_private_type_alias<'tcx>(
                 });
                 if let Some(lt) = lifetime {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
-                    let cleaned =
-                        if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
+                    let cleaned = if !lt.is_anonymous() {
+                        clean_lifetime(lt, cx)
+                    } else {
+                        Lifetime::elided()
+                    };
                     substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
                 }
                 indices.lifetimes += 1;
@@ -1892,7 +1888,7 @@ fn clean_generic_args<'tcx>(
             .args
             .iter()
             .map(|arg| match arg {
-                hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+                hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
                     GenericArg::Lifetime(clean_lifetime(*lt, cx))
                 }
                 hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
index fe291e021bc..9839e973bdf 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
@@ -2,20 +2,62 @@
 // gate-test-anonymous_lifetime_in_impl_trait
 // Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`.
 
-fn f(_: impl Iterator<Item = &'_ ()>) {}
-//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+mod elided {
+    fn f(_: impl Iterator<Item = &()>) {}
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
 
-fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
-//~| ERROR missing lifetime specifier
+    fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+    //~| ERROR missing lifetime specifier
 
-// Anonymous lifetimes in async fn are already allowed.
-// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
-async fn h(_: impl Iterator<Item = &'_ ()>) {}
+    // Anonymous lifetimes in async fn are already allowed.
+    // This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
+    async fn h(_: impl Iterator<Item = &()>) {}
 
-// Anonymous lifetimes in async fn are already allowed.
-// But that lifetime does not participate in resolution.
-async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-//~^ ERROR missing lifetime specifier
+    // Anonymous lifetimes in async fn are already allowed.
+    // But that lifetime does not participate in resolution.
+    async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+    //~^ ERROR missing lifetime specifier
+}
+
+mod underscore {
+    fn f(_: impl Iterator<Item = &'_ ()>) {}
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+
+    fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+    //~| ERROR missing lifetime specifier
+
+    // Anonymous lifetimes in async fn are already allowed.
+    // This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
+    async fn h(_: impl Iterator<Item = &'_ ()>) {}
+
+    // Anonymous lifetimes in async fn are already allowed.
+    // But that lifetime does not participate in resolution.
+    async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+    //~^ ERROR missing lifetime specifier
+}
+
+mod alone_in_path {
+    trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; }
+
+    fn f(_: impl Foo) {}
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+
+    fn g(mut x: impl Foo) -> Option<&()> { x.next() }
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+    //~| ERROR missing lifetime specifier
+}
+
+mod in_path {
+    trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; }
+
+    fn f(_: impl Foo<()>) {}
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+
+    fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
+    //~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+    //~| ERROR missing lifetime specifier
+}
 
 fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
index 9833da13ffc..50806a67255 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
@@ -1,52 +1,172 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:9:54
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                  ^^ expected named lifetime parameter
+LL |     fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+   |                                                      ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                  ~~~~~~~
+LL |     fn g(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
+   |                                                       +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:19:60
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                        ^^ expected named lifetime parameter
+LL |     async fn i(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+   |                                                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                        ~~~~~~~
+LL |     async fn i(mut x: impl Iterator<Item = &()>) -> Option<&'static ()> { x.next() }
+   |                                                             +++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:27:58
+   |
+LL |     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                          ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                          ~~~~~~~
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:37:64
+   |
+LL |     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                                ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                                ~~~~~~~
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:47:37
+   |
+LL |     fn g(mut x: impl Foo) -> Option<&()> { x.next() }
+   |                                     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     fn g(mut x: impl Foo) -> Option<&'static ()> { x.next() }
+   |                                      +++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41
+   |
+LL |     fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
+   |                                         ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     fn g(mut x: impl Foo<()>) -> Option<&'static ()> { x.next() }
+   |                                          +++++++
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35
+   |
+LL |     fn f(_: impl Iterator<Item = &()>) {}
+   |                                   ^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn f<'a>(_: impl Iterator<Item = &'a ()>) {}
+   |         ++++                          ++
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:9:39
+   |
+LL |     fn g(mut x: impl Iterator<Item = &()>) -> Option<&()> { x.next() }
+   |                                       ^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&()> { x.next() }
+   |         ++++                              ++
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:24:35
+   |
+LL |     fn f(_: impl Iterator<Item = &'_ ()>) {}
+   |                                   ^^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn f<'a>(_: impl Iterator<Item = &'a ()>) {}
+   |         ++++                          ~~
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:27:39
+   |
+LL |     fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                       ^^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'_ ()> { x.next() }
+   |         ++++                              ~~
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:44:18
+   |
+LL |     fn f(_: impl Foo) {}
+   |                  ^^^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn f<'a>(_: impl Foo<'a>) {}
+   |         ++++            ++++
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:47:22
+   |
+LL |     fn g(mut x: impl Foo) -> Option<&()> { x.next() }
+   |                      ^^^ expected named lifetime parameter
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+help: consider introducing a named lifetime parameter
+   |
+LL |     fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() }
+   |         ++++                ++++
 
 error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22
    |
-LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
-   |                               ^^ expected named lifetime parameter
+LL |     fn f(_: impl Foo<()>) {}
+   |                      ^ expected named lifetime parameter
    |
    = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
 help: consider introducing a named lifetime parameter
    |
-LL | fn f<'a>(_: impl Iterator<Item = &'_'a  ()>) {}
-   |     ++++                            ++
+LL |     fn f<'a>(_: impl Foo<'a, ()>) {}
+   |         ++++             +++
 
 error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                               ^^ expected named lifetime parameter
+LL |     fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
+   |                          ^ expected named lifetime parameter
    |
    = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
 help: consider introducing a named lifetime parameter
    |
-LL | fn g<'a>(x: impl Iterator<Item = &'_'a  ()>) -> Option<&'_ ()> { x.next() }
-   |     ++++                            ++
+LL |     fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() }
+   |         ++++                 +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0106, E0658.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 5df8b486f33..220941dcd5d 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -10,8 +10,8 @@ use rustc_hir::lang_items;
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem,
-    TraitItemKind, Ty, TyKind, WherePredicate,
+    ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn,
+    TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
@@ -595,7 +595,9 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
         .params
         .iter()
         .filter_map(|par| match par.kind {
-            GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+            GenericParamKind::Lifetime {
+                kind: LifetimeParamKind::Explicit,
+            } => Some((par.name.ident().name, par.span)),
             _ => None,
         })
         .collect();
@@ -620,7 +622,9 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
         .params
         .iter()
         .filter_map(|par| match par.kind {
-            GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+            GenericParamKind::Lifetime {
+                kind: LifetimeParamKind::Explicit,
+            } => Some((par.name.ident().name, par.span)),
             _ => None,
         })
         .collect();
@@ -647,7 +651,7 @@ struct BodyLifetimeChecker {
 impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        if lifetime.ident.name != kw::UnderscoreLifetime && lifetime.ident.name != kw::StaticLifetime {
+        if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
             self.lifetimes_used_in_body = true;
         }
     }