about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2021-07-11 15:04:57 +0200
committerCamille GILLOT <gillot.camille@gmail.com>2021-11-30 22:55:07 +0100
commit5ea7ea8a5786729d3e8d0d513819f52b4d9047dd (patch)
treef7c72c730650d096e7fdce85d7322eba1dd7a6ab
parentac03470c3ba4959d74ca1b61a57e0bcfb6d2d2f3 (diff)
downloadrust-5ea7ea8a5786729d3e8d0d513819f52b4d9047dd.tar.gz
rust-5ea7ea8a5786729d3e8d0d513819f52b4d9047dd.zip
Lint elided lifetimes in path during lifetime resolution.
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs22
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir/src/intravisit.rs1
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs40
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs26
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.fixed31
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.rs31
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.stderr60
-rw-r--r--src/test/ui/lint/force-warn/allowed-by-default-lint.stderr6
-rw-r--r--src/test/ui/lint/reasons.rs4
-rw-r--r--src/test/ui/lint/reasons.stderr12
13 files changed, 181 insertions, 78 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2b3a538772e..a561475c76a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1928,6 +1928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let param_name = match lt.name {
                     hir::LifetimeName::Param(param_name) => param_name,
                     hir::LifetimeName::Implicit
+                    | hir::LifetimeName::ImplicitMissing
                     | hir::LifetimeName::Underscore
                     | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
                     hir::LifetimeName::ImplicitObjectLifetimeDefault => {
@@ -2322,11 +2323,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &'s mut self,
         span: Span,
         count: usize,
+        param_mode: ParamMode,
     ) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
-        (0..count).map(move |_| self.elided_path_lifetime(span))
+        (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
     }
 
-    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
+    fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
             AnonymousLifetimeMode::CreateParameter => {
                 // We should have emitted E0726 when processing this path above
@@ -2342,7 +2344,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // lifetime. Instead, we simply create an implicit lifetime, which will be checked
             // later, at which point a suitable error will be emitted.
             AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                self.new_implicit_lifetime(span)
+                if param_mode == ParamMode::Explicit {
+                    let id = self.resolver.next_node_id();
+                    self.new_named_lifetime(id, span, hir::LifetimeName::ImplicitMissing)
+                } else {
+                    self.new_implicit_lifetime(span)
+                }
             }
         }
     }
@@ -2536,7 +2543,9 @@ fn lifetimes_from_impl_trait_bounds(
 
         fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
             let name = match lifetime.name {
-                hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+                hir::LifetimeName::Implicit
+                | hir::LifetimeName::ImplicitMissing
+                | hir::LifetimeName::Underscore => {
                     if self.collect_elided_lifetimes {
                         // Use `'_` for both implicit and underscore lifetimes in
                         // `type Foo<'_> = impl SomeTrait<'_>;`.
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 929f427484d..ab87867bb03 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -7,8 +7,6 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, PartialRes, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
-use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
-use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::symbol::Ident;
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
@@ -275,7 +273,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
             let elided_lifetime_span = if generic_args.span.is_empty() {
                 // If there are no brackets, use the identifier span.
-                segment.ident.span
+                path_span
             } else if generic_args.is_empty() {
                 // If there are brackets, but not generic arguments, then use the opening bracket
                 generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
@@ -284,7 +282,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
             };
             generic_args.args = self
-                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
+                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
                 .map(GenericArg::Lifetime)
                 .chain(generic_args.args.into_iter())
                 .collect();
@@ -329,21 +327,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         err.note("assuming a `'static` lifetime...");
                         err.emit();
                     }
-                    AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                        self.resolver.lint_buffer().buffer_lint_with_diagnostic(
-                            ELIDED_LIFETIMES_IN_PATHS,
-                            CRATE_NODE_ID,
-                            path_span,
-                            "hidden lifetime parameters in types are deprecated",
-                            BuiltinLintDiagnostics::ElidedLifetimesInPaths(
-                                expected_lifetimes,
-                                path_span,
-                                incl_angl_brckt,
-                                insertion_sp,
-                                suggestion,
-                            ),
-                        );
-                    }
+                    AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {}
                 }
             }
         }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 5edb52b0b65..64df452c739 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -584,7 +584,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::ImplicitMissing => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c67d3df3ded..e56761ea39a 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -94,6 +94,9 @@ pub enum LifetimeName {
     /// User wrote nothing (e.g., the lifetime in `&u32`).
     Implicit,
 
+    /// User wrote nothing, but should have provided something.
+    ImplicitMissing,
+
     /// Implicit lifetime in a context like `dyn Foo`. This is
     /// distinguished from implicit lifetimes elsewhere because the
     /// lifetime that they default to must appear elsewhere within the
@@ -123,6 +126,7 @@ impl LifetimeName {
         match *self {
             LifetimeName::ImplicitObjectLifetimeDefault
             | LifetimeName::Implicit
+            | LifetimeName::ImplicitMissing
             | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
@@ -134,6 +138,7 @@ impl LifetimeName {
         match self {
             LifetimeName::ImplicitObjectLifetimeDefault
             | LifetimeName::Implicit
+            | LifetimeName::ImplicitMissing
             | LifetimeName::Underscore => true,
 
             // It might seem surprising that `Fresh(_)` counts as
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cff543760f4..5f8e4ba2d13 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -546,6 +546,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
         | LifetimeName::Static
         | LifetimeName::Error
         | LifetimeName::Implicit
+        | LifetimeName::ImplicitMissing
         | LifetimeName::ImplicitObjectLifetimeDefault
         | LifetimeName::Underscore => {}
     }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 8c917fc466d..2186a9a73c5 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1950,6 +1950,41 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
     }
 
+    crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
+        let missing_lifetimes = lifetime_refs
+            .iter()
+            .filter(|a| matches!(a, hir::Lifetime { name: hir::LifetimeName::ImplicitMissing, .. }))
+            .count();
+
+        if missing_lifetimes > 0 {
+            let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+            spans.sort();
+            let mut spans_dedup = spans.clone();
+            spans_dedup.dedup();
+            let spans_with_counts: Vec<_> = spans_dedup
+                .into_iter()
+                .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
+                .collect();
+
+            self.tcx.struct_span_lint_hir(
+                rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+                hir::CRATE_HIR_ID,
+                spans,
+                |lint| {
+                    let mut db = lint.build("hidden lifetime parameters in types are deprecated");
+                    self.add_missing_lifetime_specifiers_label(
+                        &mut db,
+                        spans_with_counts,
+                        &FxHashSet::from_iter([kw::UnderscoreLifetime]),
+                        Vec::new(),
+                        &[],
+                    );
+                    db.emit()
+                },
+            );
+        }
+    }
+
     // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
     // generics. We are disallowing this until we can decide on how we want to handle non-'static
     // lifetimes in const generics. See issue #74052 for discussion.
@@ -2376,7 +2411,10 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         );
         let is_allowed_lifetime = matches!(
             lifetime_ref.name,
-            hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
+            hir::LifetimeName::Implicit
+                | hir::LifetimeName::ImplicitMissing
+                | hir::LifetimeName::Static
+                | hir::LifetimeName::Underscore
         );
 
         if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 85e704874e2..0427317aa90 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 });
                 match lifetime.name {
-                    LifetimeName::Implicit => {
+                    LifetimeName::Implicit | hir::LifetimeName::ImplicitMissing => {
                         // For types like `dyn Foo`, we should
                         // generate a special form of elided.
                         span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
@@ -3057,9 +3057,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
-                Scope::Body { .. } => return,
+                Scope::Body { .. } => break Ok(()),
 
-                Scope::Root => break None,
+                Scope::Root => break Err(None),
 
                 Scope::Binder { s, ref lifetimes, scope_type, .. } => {
                     // collect named lifetimes for suggestions
@@ -3086,7 +3086,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    return;
+                    break Ok(());
                 }
 
                 Scope::Elision { elide: Elide::Exact(l), .. } => {
@@ -3094,7 +3094,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     for lifetime_ref in lifetime_refs {
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    return;
+                    break Ok(());
                 }
 
                 Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
@@ -3119,10 +3119,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             _ => break,
                         }
                     }
-                    break Some(&e[..]);
+                    break Err(Some(&e[..]));
                 }
 
-                Scope::Elision { elide: Elide::Forbid, .. } => break None,
+                Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
@@ -3132,6 +3132,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         };
 
+        let error = match error {
+            Ok(()) => {
+                self.report_elided_lifetime_in_ty(lifetime_refs);
+                return;
+            }
+            Err(error) => error,
+        };
+
         // If we specifically need the `scope_for_path` map, then we're in the
         // diagnostic pass and we don't want to emit more errors.
         if self.map.scope_for_path.is_some() {
@@ -3274,7 +3282,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                 ))
                                 .emit();
                         }
-                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
+                        hir::LifetimeName::Param(_)
+                        | hir::LifetimeName::Implicit
+                        | hir::LifetimeName::ImplicitMissing => {
                             self.resolve_lifetime_ref(lt);
                         }
                         hir::LifetimeName::ImplicitObjectLifetimeDefault => {
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
index 2998f05efba..ca70242ef3d 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
@@ -5,23 +5,24 @@
 #![deny(elided_lifetimes_in_paths)]
 //~^ NOTE the lint level is defined here
 
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
 
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+    x: &'a u32,
+}
 
 fn foo(x: &Foo<'_>) {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
 }
 
 fn bar(x: &Foo<'_>) {}
 
-
 struct Wrapped<'a>(&'a str);
 
 struct WrappedWithBow<'a> {
-    gift: &'a str
+    gift: &'a str,
 }
 
 struct MatchedSet<'a, 'b> {
@@ -31,19 +32,22 @@ struct MatchedSet<'a, 'b> {
 
 fn wrap_gift(gift: &str) -> Wrapped<'_> {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     Wrapped(gift)
 }
 
 fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     WrappedWithBow { gift }
 }
 
 fn inspect_matched_set(set: MatchedSet<'_, '_>) {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected 2 lifetime parameters
+    //~| HELP consider using the `'_` lifetime
     println!("{} {}", set.one, set.another);
 }
 
@@ -55,7 +59,8 @@ macro_rules! autowrapper {
 
         fn $fn_name(gift: &str) -> $type_name<'_> {
             //~^ ERROR hidden lifetime parameters in types are deprecated
-            //~| HELP indicate the anonymous lifetime
+            //~| NOTE expected named lifetime parameter
+            //~| HELP consider using the `'_` lifetime
             $type_name { gift }
         }
     }
@@ -69,7 +74,8 @@ macro_rules! anytuple_ref_ty {
     ($($types:ty),*) => {
         Ref<'_, ($($types),*)>
         //~^ ERROR hidden lifetime parameters in types are deprecated
-        //~| HELP indicate the anonymous lifetime
+        //~| NOTE expected named lifetime parameter
+        //~| HELP consider using the `'_` lifetime
     }
 }
 
@@ -77,7 +83,8 @@ fn main() {
     let honesty = RefCell::new((4, 'e'));
     let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     let generosity = Ref::map(loyalty, |t| &t.0);
 
     let laughter = RefCell::new((true, "magic"));
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
index b729a15a29e..d55eb854ed2 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
@@ -5,23 +5,24 @@
 #![deny(elided_lifetimes_in_paths)]
 //~^ NOTE the lint level is defined here
 
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
 
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+    x: &'a u32,
+}
 
 fn foo(x: &Foo) {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
 }
 
 fn bar(x: &Foo<'_>) {}
 
-
 struct Wrapped<'a>(&'a str);
 
 struct WrappedWithBow<'a> {
-    gift: &'a str
+    gift: &'a str,
 }
 
 struct MatchedSet<'a, 'b> {
@@ -31,19 +32,22 @@ struct MatchedSet<'a, 'b> {
 
 fn wrap_gift(gift: &str) -> Wrapped {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     Wrapped(gift)
 }
 
 fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     WrappedWithBow { gift }
 }
 
 fn inspect_matched_set(set: MatchedSet) {
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected 2 lifetime parameters
+    //~| HELP consider using the `'_` lifetime
     println!("{} {}", set.one, set.another);
 }
 
@@ -55,7 +59,8 @@ macro_rules! autowrapper {
 
         fn $fn_name(gift: &str) -> $type_name {
             //~^ ERROR hidden lifetime parameters in types are deprecated
-            //~| HELP indicate the anonymous lifetime
+            //~| NOTE expected named lifetime parameter
+            //~| HELP consider using the `'_` lifetime
             $type_name { gift }
         }
     }
@@ -69,7 +74,8 @@ macro_rules! anytuple_ref_ty {
     ($($types:ty),*) => {
         Ref<($($types),*)>
         //~^ ERROR hidden lifetime parameters in types are deprecated
-        //~| HELP indicate the anonymous lifetime
+        //~| NOTE expected named lifetime parameter
+        //~| HELP consider using the `'_` lifetime
     }
 }
 
@@ -77,7 +83,8 @@ fn main() {
     let honesty = RefCell::new((4, 'e'));
     let loyalty: Ref<(u32, char)> = honesty.borrow();
     //~^ ERROR hidden lifetime parameters in types are deprecated
-    //~| HELP indicate the anonymous lifetime
+    //~| NOTE expected named lifetime parameter
+    //~| HELP consider using the `'_` lifetime
     let generosity = Ref::map(loyalty, |t| &t.0);
 
     let laughter = RefCell::new((true, "magic"));
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
index 037ce401b3c..c7cfaa9a018 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
@@ -1,60 +1,92 @@
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:13:12
+  --> $DIR/elided-lifetimes.rs:14:12
    |
 LL | fn foo(x: &Foo) {
-   |            ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |            ^^^ expected named lifetime parameter
    |
 note: the lint level is defined here
   --> $DIR/elided-lifetimes.rs:5:9
    |
 LL | #![deny(elided_lifetimes_in_paths)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+   |
+LL | fn foo(x: &Foo<'_>) {
+   |            ~~~~~~~
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:32:29
+  --> $DIR/elided-lifetimes.rs:33:29
    |
 LL | fn wrap_gift(gift: &str) -> Wrapped {
-   |                             ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                             ^^^^^^^ expected named lifetime parameter
+   |
+help: consider using the `'_` lifetime
+   |
+LL | fn wrap_gift(gift: &str) -> Wrapped<'_> {
+   |                             ~~~~~~~~~~~
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:38:38
+  --> $DIR/elided-lifetimes.rs:40:38
    |
 LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
-   |                                      ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                                      ^^^^^^^^^^^^^^ expected named lifetime parameter
+   |
+help: consider using the `'_` lifetime
+   |
+LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
+   |                                      ~~~~~~~~~~~~~~~~~~
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:44:29
+  --> $DIR/elided-lifetimes.rs:47:29
    |
 LL | fn inspect_matched_set(set: MatchedSet) {
-   |                             ^^^^^^^^^^- help: indicate the anonymous lifetimes: `<'_, '_>`
+   |                             ^^^^^^^^^^ expected 2 lifetime parameters
+   |
+help: consider using the `'_` lifetime
+   |
+LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) {
+   |                             ~~~~~~~~~~~~~~~~~~
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:56:36
+  --> $DIR/elided-lifetimes.rs:60:36
    |
 LL |         fn $fn_name(gift: &str) -> $type_name {
-   |                                    ^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                                    ^^^^^^^^^^ expected named lifetime parameter
 ...
 LL | autowrapper!(Autowrapped, autowrap_gift, 'a);
    | -------------------------------------------- in this macro invocation
    |
    = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+   |
+LL |         fn $fn_name(gift: &str) -> $type_name<'_> {
+   |                                    ~~~~~~~~~~~~~~
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:78:18
+  --> $DIR/elided-lifetimes.rs:84:22
    |
 LL |     let loyalty: Ref<(u32, char)> = honesty.borrow();
-   |                  ^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, (u32, char)>`
+   |                      ^ expected named lifetime parameter
+   |
+help: consider using the `'_` lifetime
+   |
+LL |     let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
+   |                      +++
 
 error: hidden lifetime parameters in types are deprecated
-  --> $DIR/elided-lifetimes.rs:70:9
+  --> $DIR/elided-lifetimes.rs:75:13
    |
 LL |         Ref<($($types),*)>
-   |         ^^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, ($($types),*)>`
+   |             ^ expected named lifetime parameter
 ...
 LL |     let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow();
    |                 ---------------------------- in this macro invocation
    |
    = note: this error originates in the macro `anytuple_ref_ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+   |
+LL |         Ref<'_, ($($types),*)>
+   |             +++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
index baa47cbb10f..f5e8b41b163 100644
--- a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
@@ -2,9 +2,13 @@ warning: hidden lifetime parameters in types are deprecated
   --> $DIR/allowed-by-default-lint.rs:9:12
    |
 LL | fn foo(x: &Foo) {}
-   |            ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |            ^^^ expected named lifetime parameter
    |
    = note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
+help: consider using the `'_` lifetime
+   |
+LL | fn foo(x: &Foo<'_>) {}
+   |            ~~~~~~~
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/reasons.rs b/src/test/ui/lint/reasons.rs
index 34cac4968a8..b1792e2e9cb 100644
--- a/src/test/ui/lint/reasons.rs
+++ b/src/test/ui/lint/reasons.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(lint_reasons)]
-
 #![warn(elided_lifetimes_in_paths,
         //~^ NOTE the lint level is defined here
         reason = "explicit anonymous lifetimes aid reasoning about ownership")]
@@ -20,8 +19,9 @@ pub struct CheaterDetectionMechanism {}
 impl fmt::Debug for CheaterDetectionMechanism {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         //~^ WARN hidden lifetime parameters in types are deprecated
+        //~| NOTE expected named lifetime parameter
         //~| NOTE explicit anonymous lifetimes aid
-        //~| HELP indicate the anonymous lifetime
+        //~| HELP consider using the `'_` lifetime
         fmt.debug_struct("CheaterDetectionMechanism").finish()
     }
 }
diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr
index 150237c6be2..f797c89a032 100644
--- a/src/test/ui/lint/reasons.stderr
+++ b/src/test/ui/lint/reasons.stderr
@@ -1,15 +1,19 @@
 warning: hidden lifetime parameters in types are deprecated
-  --> $DIR/reasons.rs:21:29
+  --> $DIR/reasons.rs:20:29
    |
 LL |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-   |                             ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                             ^^^^^^^^^^^^^^ expected named lifetime parameter
    |
    = note: explicit anonymous lifetimes aid reasoning about ownership
 note: the lint level is defined here
-  --> $DIR/reasons.rs:5:9
+  --> $DIR/reasons.rs:4:9
    |
 LL | #![warn(elided_lifetimes_in_paths,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+   |
+LL |     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+   |                             ~~~~~~~~~~~~~~~~~~
 
 warning: variable `Social_exchange_psychology` should have a snake case name
   --> $DIR/reasons.rs:30:9
@@ -20,7 +24,7 @@ LL |     let Social_exchange_psychology = CheaterDetectionMechanism {};
    = note: people shouldn't have to change their usual style habits
            to contribute to our project
 note: the lint level is defined here
-  --> $DIR/reasons.rs:9:5
+  --> $DIR/reasons.rs:8:5
    |
 LL |     nonstandard_style,
    |     ^^^^^^^^^^^^^^^^^