about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJake Goulding <jake.goulding@gmail.com>2025-07-10 18:36:22 -0400
committerJosh Stone <jistone@redhat.com>2025-07-24 09:53:53 -0700
commitc06b5868245bb2b4775397b68cfb609fa4b0ce14 (patch)
tree81b7c7d84adb16f27bf6dcb0282f382d111eae62
parent20c571f4ca4689572df8c27fdde8eaa36d77a11d (diff)
downloadrust-c06b5868245bb2b4775397b68cfb609fa4b0ce14.tar.gz
rust-c06b5868245bb2b4775397b68cfb609fa4b0ce14.zip
Reword mismatched-lifetime-syntaxes text based on feedback
Key changes include:

- Removal of the word "syntax" from the lint message. More accurately,
  it could have been something like "syntax group" or "syntax
  category", but avoiding it completely is easier.
- The primary lint message now reflects exactly which mismatch is
  occurring, instead of trying to be general. A new `help` line is
  general across the mismatch kinds.
- Suggestions have been reduced to be more minimal, no longer also
  changing non-idiomatic but unrelated aspects.
- Suggestion text no longer mentions changes when those changes don't
  occur in that specific suggestion.

(cherry picked from commit 553074431875701f66107049339dc1e67f0cdeba)
-rw-r--r--compiler/rustc_lint/messages.ftl53
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lifetime_syntax.rs145
-rw-r--r--compiler/rustc_lint/src/lints.rs64
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr11
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.full.stderr11
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.rs2
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs2
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr7
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs2
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr9
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs4
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr18
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs104
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr497
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.rs4
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.stderr18
-rw-r--r--tests/ui/self/self_lifetime-async.rs4
-rw-r--r--tests/ui/self/self_lifetime-async.stderr18
-rw-r--r--tests/ui/self/self_lifetime.rs4
-rw-r--r--tests/ui/self/self_lifetime.stderr18
26 files changed, 674 insertions, 413 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 8d9f2385b71..5fece464270 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -508,27 +508,50 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi
 
 lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
 
-lint_mismatched_lifetime_syntaxes =
-    lifetime flowing from input to output with different syntax can be confusing
-    .label_mismatched_lifetime_syntaxes_inputs =
-        {$n_inputs ->
-            [one] this lifetime flows
-            *[other] these lifetimes flow
-        } to the output
-    .label_mismatched_lifetime_syntaxes_outputs =
-        the {$n_outputs ->
-            [one] lifetime gets
-            *[other] lifetimes get
-        } resolved as `{$lifetime_name}`
+lint_mismatched_lifetime_syntaxes_eliding_while_named =
+    eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_help =
+    the same lifetime is referred to in inconsistent ways, making the signature confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named =
+    hiding or eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_elided =
+    hiding a lifetime that's elided elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_named =
+    hiding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_input_elided =
+    the lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_input_hidden =
+    the lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_input_named =
+    the lifetime is named here
+
+lint_mismatched_lifetime_syntaxes_output_elided =
+    the same lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_output_hidden =
+    the same lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_output_named =
+    the same lifetime is named here
 
 lint_mismatched_lifetime_syntaxes_suggestion_explicit =
-    one option is to consistently use `{$lifetime_name}`
+    consistently use `{$lifetime_name}`
 
 lint_mismatched_lifetime_syntaxes_suggestion_implicit =
-    one option is to consistently remove the lifetime
+    remove the lifetime name from references
 
 lint_mismatched_lifetime_syntaxes_suggestion_mixed =
-    one option is to remove the lifetime for references and use the anonymous lifetime for paths
+    remove the lifetime name from references and use `'_` for type paths
+
+lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths =
+    use `'_` for type paths
 
 lint_missing_unsafe_on_extern = extern blocks should be unsafe
     .suggestion = needs `unsafe` before the extern keyword
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 20568f35a47..27ce614d8c9 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,7 +55,7 @@ mod invalid_from_utf8;
 mod late;
 mod let_underscore;
 mod levels;
-mod lifetime_syntax;
+pub mod lifetime_syntax;
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 95b7b69bd5a..2a5a34cdc6e 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
     }
 }
 
-fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
-    // Categorize lifetimes into source/syntax buckets.
-    let mut n_hidden = 0;
-    let mut n_elided = 0;
-    let mut n_named = 0;
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum LifetimeSyntaxCategory {
+    Hidden,
+    Elided,
+    Named,
+}
 
-    for info in input_info.iter().chain(output_info) {
+impl LifetimeSyntaxCategory {
+    fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> {
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
-
         match syntax_source {
-            // Ignore any other kind of lifetime.
-            (_, Other) => continue,
-
             // E.g. `&T`.
-            (Implicit, Reference | OutlivesBound | PreciseCapturing) |
+            (Implicit, Reference) |
             // E.g. `&'_ T`.
-            (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitAnonymous, Reference) |
             // E.g. `ContainsLifetime<'_>`.
-            (ExplicitAnonymous, Path { .. }) => n_elided += 1,
+            (ExplicitAnonymous, Path { .. }) |
+            // E.g. `+ '_`, `+ use<'_>`.
+            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Elided)
+            }
 
             // E.g. `ContainsLifetime`.
-            (Implicit, Path { .. }) => n_hidden += 1,
+            (Implicit, Path { .. }) => {
+                Some(Self::Hidden)
+            }
 
             // E.g. `&'a T`.
-            (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitBound, Reference) |
             // E.g. `ContainsLifetime<'a>`.
-            (ExplicitBound, Path { .. }) => n_named += 1,
-        };
+            (ExplicitBound, Path { .. }) |
+            // E.g. `+ 'a`, `+ use<'a>`.
+            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Named)
+            }
+
+            (Implicit, OutlivesBound | PreciseCapturing) |
+            (_, Other) => {
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug, Default)]
+pub struct LifetimeSyntaxCategories<T> {
+    pub hidden: T,
+    pub elided: T,
+    pub named: T,
+}
+
+impl<T> LifetimeSyntaxCategories<T> {
+    fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T {
+        use LifetimeSyntaxCategory::*;
+
+        match category {
+            Elided => &mut self.elided,
+            Hidden => &mut self.hidden,
+            Named => &mut self.named,
+        }
+    }
+}
+
+impl<T> LifetimeSyntaxCategories<Vec<T>> {
+    pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
+        LifetimeSyntaxCategories {
+            hidden: self.hidden.len(),
+            elided: self.elided.len(),
+            named: self.named.len(),
+        }
+    }
+
+    pub fn flatten(&self) -> impl Iterator<Item = &T> {
+        let Self { hidden, elided, named } = self;
+        [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten()
+    }
+}
+
+impl std::ops::Add for LifetimeSyntaxCategories<usize> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Self {
+            hidden: self.hidden + rhs.hidden,
+            elided: self.elided + rhs.elided,
+            named: self.named + rhs.named,
+        }
+    }
+}
+
+fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
+    let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default();
+
+    for info in input_info.iter().chain(output_info) {
+        if let Some(category) = info.lifetime_syntax_category() {
+            *syntax_counts.select(category) += 1;
+        }
     }
 
-    let syntax_counts = (n_hidden, n_elided, n_named);
     tracing::debug!(?syntax_counts);
 
-    matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _))
+    matches!(
+        syntax_counts,
+        LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ }
+    )
 }
 
 fn emit_mismatch_diagnostic<'tcx>(
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
+        let syntax_source = info.syntax_source();
 
         if let (_, Other) = syntax_source {
             // Ignore any other kind of lifetime.
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
             // E.g. `&'_ T`.
             (ExplicitAnonymous, Reference) => {
                 suggest_change_to_implicit.push(info);
-                suggest_change_to_mixed_implicit.push(info);
                 suggest_change_to_explicit_bound.push(info);
             }
 
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
         }
     }
 
+    let categorize = |infos: &[Info<'_>]| {
+        let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
+        for info in infos {
+            if let Some(category) = info.lifetime_syntax_category() {
+                categories.select(category).push(info.reporting_span());
+            }
+        }
+        categories
+    };
+
+    let inputs = categorize(input_info);
+    let outputs = categorize(output_info);
+
     let make_implicit_suggestions =
         |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
 
-    let inputs = input_info.iter().map(|info| info.reporting_span()).collect();
-    let outputs = output_info.iter().map(|info| info.reporting_span()).collect();
-
     let explicit_bound_suggestion = bound_lifetime.map(|info| {
         build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
     });
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
         ?explicit_anonymous_suggestion,
     );
 
-    let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned();
-
     // We can produce a number of suggestions which may overwhelm
     // the user. Instead, we order the suggestions based on Rust
     // idioms. The "best" choice is shown to the user and the
@@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>(
 
     cx.emit_span_lint(
         MISMATCHED_LIFETIME_SYNTAXES,
-        Vec::clone(&inputs),
-        lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions },
+        inputs.flatten().copied().collect::<Vec<_>>(),
+        lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions },
     );
 }
 
@@ -441,6 +520,14 @@ struct Info<'tcx> {
 }
 
 impl<'tcx> Info<'tcx> {
+    fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) {
+        (self.lifetime.syntax, self.lifetime.source)
+    }
+
+    fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> {
+        LifetimeSyntaxCategory::new(self.syntax_source())
+    }
+
     fn lifetime_name(&self) -> &str {
         self.lifetime.ident.as_str()
     }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index c4a6695efe9..1728f7d2902 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -22,6 +22,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
 
 use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
 use crate::errors::{OverruledAttributeSub, RequestedLevel};
+use crate::lifetime_syntax::LifetimeSyntaxCategories;
 use crate::{LateContext, fluent_generated as fluent};
 
 // array_into_iter.rs
@@ -3176,30 +3177,59 @@ pub(crate) struct ReservedMultihash {
 
 #[derive(Debug)]
 pub(crate) struct MismatchedLifetimeSyntaxes {
-    pub lifetime_name: String,
-    pub inputs: Vec<Span>,
-    pub outputs: Vec<Span>,
+    pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
+    pub outputs: LifetimeSyntaxCategories<Vec<Span>>,
 
     pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
 }
 
 impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
     fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
-        diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes);
+        let counts = self.inputs.len() + self.outputs.len();
+        let message = match counts {
+            LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => {
+                panic!("No lifetime mismatch detected")
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named
+            }
 
-        diag.arg("lifetime_name", self.lifetime_name);
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named
+            }
+        };
+        diag.primary_message(message);
 
-        diag.arg("n_inputs", self.inputs.len());
-        for input in self.inputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs);
-            diag.span_label(input, a);
+        for s in self.inputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden);
+        }
+        for s in self.inputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided);
+        }
+        for s in self.inputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named);
         }
 
-        diag.arg("n_outputs", self.outputs.len());
-        for output in self.outputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs);
-            diag.span_label(output, a);
+        for s in self.outputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden);
+        }
+        for s in self.outputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided);
         }
+        for s in self.outputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named);
+        }
+
+        diag.help(fluent::lint_mismatched_lifetime_syntaxes_help);
 
         let mut suggestions = self.suggestions.into_iter();
         if let Some(s) = suggestions.next() {
@@ -3267,6 +3297,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
             }
 
             Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
+                let message = if implicit_suggestions.is_empty() {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
+                } else {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed
+                };
+
                 let implicit_suggestions =
                     implicit_suggestions.into_iter().map(|s| (s, String::new()));
 
@@ -3274,7 +3310,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
                     implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
 
                 diag.multipart_suggestion_with_style(
-                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
+                    message,
                     suggestions,
                     Applicability::MaybeIncorrect,
                     style(tool_only),
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 65f3f05d6cb..578641e910d 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -312,7 +312,7 @@ mod issue_9218 {
 
     // Inferred to be `&'a str`, afaik.
     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-        //~^ ERROR: lifetime flowing from input to output with different syntax
+        //~^ ERROR: eliding a lifetime that's named elsewhere is confusing
         todo!()
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 600343754e1..fd9ceddfe11 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -231,18 +231,19 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
 LL |     fn good(v1: &String, v2: &String) {
    |                              ^^^^^^^ help: change this to: `&str`
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> tests/ui/ptr_arg.rs:314:36
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-   |                                    ^^     ^^           ---- the lifetime gets resolved as `'a`
+   |                                    ^^     ^^           ---- the same lifetime is elided here
    |                                    |      |
-   |                                    |      these lifetimes flow to the output
-   |                                    these lifetimes flow to the output
+   |                                    |      the lifetime is named here
+   |                                    the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
    |                                                         ++
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
index f68fdb3b651..32fa46b92b3 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
@@ -1,14 +1,15 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/issue-71348.rs:18:40
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
-   |                                        ^^           -- ------------------------ the lifetimes get resolved as `'a`
+   |                                        ^^           -- ------------------------ the same lifetime is hidden here
    |                                        |            |
-   |                                        |            the lifetimes get resolved as `'a`
-   |                                        this lifetime flows to the output
+   |                                        |            the same lifetime is named here
+   |                                        the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<'a, N>>::Target
    |                                                                     +++
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs
index c6563c80305..9053f362ce4 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.rs
+++ b/tests/ui/const-generics/type-dependent/issue-71348.rs
@@ -17,7 +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
-    //[full]~^^ WARNING lifetime flowing from input to output with different syntax
+    //[full]~^^ WARNING hiding a lifetime that's named elsewhere is confusing
     where
         Self: Get<'a, N>,
     {
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
index 1ac3c593dbe..1b8a5d4ca99 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
     v.into_iter()
 }
 
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
index b9d8674992c..3651226e0c3 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
@@ -1,11 +1,12 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-   |                               ^^ this lifetime flows to the output               ---- the lifetime gets resolved as `'a`
+   |                               ^^ the lifetime is named here                      ---- the same lifetime is elided here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &'a u32)> {
    |                                                                                   ++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
index 1804003d367..9162a38f510 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
@@ -4,7 +4,7 @@ struct Foo;
 
 impl Foo {
     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         unsafe { &mut *(x as *mut _) }
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
index 7c7411651d0..5a7a5a6ebf9 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
@@ -1,17 +1,18 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/example-from-issue48686.rs:6:21
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-   |                     ^^^^^^^                      ------- the lifetime gets resolved as `'static`
+   |                     ^^^^^^^                      ------- the same lifetime is elided here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/example-from-issue48686.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
    |                                                   +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
index 3d5aab5c829..ecc790be5a0 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
@@ -1,26 +1,26 @@
 #![deny(mismatched_lifetime_syntaxes)]
 
 fn ampersand<'a>(x: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets<'a>(x: &'a u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma<'a>(x: &'a u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
index 681b3c97052..af56a0a0ea5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:3:22
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
-   |                      ^^        --- the lifetime gets resolved as `'a`
+   |                      ^^        --- the same lifetime is elided here
    |                      |
-   |                      this lifetime flows to the output
+   |                      the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/missing-lifetime-kind.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 {
    |                                 ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:10:21
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets {
-   |                     ^^        -------- the lifetime gets resolved as `'a`
+   |                     ^^        -------- the same lifetime is hidden here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> {
    |                                       ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:17:18
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
-   |                  ^^        --------- the lifetime gets resolved as `'a`
+   |                  ^^        --------- the same lifetime is hidden here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> {
    |                                  +++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:22:23
    |
 LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-   |                       ^^         -- the lifetime gets resolved as `'a`
+   |                       ^^         -- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 {
 LL + fn underscore<'a>(x: &'a u8) -> &'a u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
index cc398ab7888..449b2a3c0a8 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
@@ -6,13 +6,13 @@
 #[warn(mismatched_lifetime_syntaxes)]
 mod foo {
     fn bar(x: &'static u8) -> &u8 {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         x
     }
 
     #[deny(mismatched_lifetime_syntaxes)]
     fn baz(x: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         x
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
index da691225c17..cf0a29678fa 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
@@ -1,35 +1,37 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:8:16
    |
 LL |     fn bar(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:6:8
    |
 LL | #[warn(mismatched_lifetime_syntaxes)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn bar(x: &'static u8) -> &'static u8 {
    |                                +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:14:16
    |
 LL |     fn baz(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:13:12
    |
 LL |     #[deny(mismatched_lifetime_syntaxes)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn baz(x: &'static u8) -> &'static u8 {
    |                                +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
index 47ae258f138..c41cf44e1c5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
@@ -14,26 +14,26 @@ impl Trait for () {
 }
 
 fn ampersand(x: &'static u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets(x: &'static u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma(x: &'static u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore(x: &'static u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
index 5b9a986bcbe..d60bec6f7e4 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:16:18
    |
 LL | fn ampersand(x: &'static u8) -> &u8 {
-   |                  ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                  ^^^^^^^        --- the same lifetime is elided here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/static.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL | fn ampersand(x: &'static u8) -> &'static u8 {
    |                                  +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:23:17
    |
 LL | fn brackets(x: &'static u8) -> Brackets {
-   |                 ^^^^^^^        -------- the lifetime gets resolved as `'static`
+   |                 ^^^^^^^        -------- the same lifetime is hidden here
    |                 |
-   |                 this lifetime flows to the output
+   |                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn brackets(x: &'static u8) -> Brackets<'static> {
    |                                        +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:30:14
    |
 LL | fn comma(x: &'static u8) -> Comma<u8> {
-   |              ^^^^^^^        --------- the lifetime gets resolved as `'static`
+   |              ^^^^^^^        --------- the same lifetime is hidden here
    |              |
-   |              this lifetime flows to the output
+   |              the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn comma(x: &'static u8) -> Comma<'static, u8> {
    |                                   ++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:35:19
    |
 LL | fn underscore(x: &'static u8) -> &'_ u8 {
-   |                   ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                   ^^^^^^^         -- the same lifetime is elided here
    |                   |
-   |                   this lifetime flows to the output
+   |                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL - fn underscore(x: &'static u8) -> &'_ u8 {
 LL + fn underscore(x: &'static u8) -> &'static u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
index b98423afb17..f6260c47202 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
@@ -5,109 +5,111 @@ struct ContainsLifetime<'a>(&'a u8);
 
 struct S(u8);
 
+// ref to ref
+
 fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
-// ---
+// path to path
 
 fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_explicit_anonymous_path<'a>(
     v: ContainsLifetime<'a>,
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
 ) -> ContainsLifetime<'_> {
     v
 }
 
-// ---
+// ref to path
 
 fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
-// ---
+// path to ref
 
 fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 impl S {
     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     // ---
 
     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 }
@@ -122,43 +124,43 @@ mod static_suggestions {
     struct S(u8);
 
     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     impl S {
         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
 
         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
     }
@@ -170,23 +172,23 @@ mod impl_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_precise_capture<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ) -> impl FnOnce() + use<'_> {
         move || _ = v
     }
@@ -200,13 +202,13 @@ mod dyn_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         Box::new(iter::once(v))
     }
 
     fn explicit_bound_path_to_dyn_trait_bound<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
         Box::new(iter::once(v))
     }
@@ -214,10 +216,28 @@ mod dyn_trait {
 
 /// These tests serve to exercise edge cases of the lint formatting
 mod diagnostic_output {
+    #[derive(Copy, Clone)]
+    struct ContainsLifetime<'a>(&'a u8);
+
+    fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        v.0
+    }
+
     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         (v, v)
     }
+
+    fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+        //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing
+        (v.0, v)
+    }
+
+    fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        (v, v, ContainsLifetime(v))
+    }
 }
 
 /// Trait functions are represented differently in the HIR. Make sure
@@ -228,20 +248,20 @@ mod trait_functions {
 
     trait TheTrait {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 
     impl TheTrait for &u8 {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(v)
         }
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(self)
         }
     }
@@ -255,7 +275,7 @@ mod foreign_functions {
 
     extern "Rust" {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
index 108b3f14169..20b7561c594 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
@@ -1,538 +1,613 @@
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:8:47
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:10:47
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-   |                                               ^^        --- the lifetime gets resolved as `'a`
+   |                                               ^^        --- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
+   |                                               the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/mismatched-lifetime-syntaxes.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 {
    |                                                          ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:13:57
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:15:57
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-   |                                                         ^^         -- the lifetime gets resolved as `'a`
+   |                                                         ^^         -- the same lifetime is elided here
    |                                                         |
-   |                                                         this lifetime flows to the output
+   |                                                         the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
 LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:20:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:22:48
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-   |                                                ^^^^^^^^^^^^^^^^                      -- the lifetime gets resolved as `'_`
+   |                                                ^^^^^^^^^^^^^^^^                      -- the same lifetime is elided here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is hidden here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:25:65
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:27:65
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'_`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is elided here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:30:65
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:32:65
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'a`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:36:25
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:38:25
    |
 LL |     v: ContainsLifetime<'a>,
-   |                         ^^ this lifetime flows to the output
+   |                         ^^ the lifetime is named here
 LL |
 LL | ) -> ContainsLifetime<'_> {
-   |                       -- the lifetime gets resolved as `'a`
+   |                       -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - ) -> ContainsLifetime<'_> {
 LL + ) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:44:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:46:37
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                     ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                     ^^^     ---------------- the same lifetime is hidden here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                             ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:49:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:51:48
    |
 LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'_`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<'_> {
+   |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:54:48
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:56:48
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'a`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:59:58
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:61:58
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-   |                                                          ^^                         -- the lifetime gets resolved as `'a`
+   |                                                          ^^                         -- the same lifetime is elided here
    |                                                          |
-   |                                                          this lifetime flows to the output
+   |                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
 LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:66:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:68:37
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-   |                                     ^^^^^^^^^^^^^^^^     --- the lifetime gets resolved as `'_`
+   |                                     ^^^^^^^^^^^^^^^^     --- the same lifetime is elided here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is hidden here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 {
    |                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:71:47
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:73:47
    |
 LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-   |                                               ^^^^^^^^^^^^^^^^      -- the lifetime gets resolved as `'_`
+   |                                               ^^^^^^^^^^^^^^^^      -- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
-   |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   |                                               the lifetime is hidden here
    |
-LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 {
+   |                                                               ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:76:64
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:78:64
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-   |                                                                ^^      --- the lifetime gets resolved as `'a`
+   |                                                                ^^      --- the same lifetime is elided here
    |                                                                |
-   |                                                                this lifetime flows to the output
+   |                                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:81:74
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:83:74
    |
 LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-   |                                                                          ^^       -- the lifetime gets resolved as `'a`
+   |                                                                          ^^       -- the same lifetime is elided here
    |                                                                          |
-   |                                                                          this lifetime flows to the output
+   |                                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
 LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:87:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:89:55
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-   |                                                       ^^          --- the lifetime gets resolved as `'a`
+   |                                                       ^^          --- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 {
    |                                                                    ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:92:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:94:65
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-   |                                                                 ^^           -- the lifetime gets resolved as `'a`
+   |                                                                 ^^           -- the same lifetime is elided here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:99:56
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:101:56
    |
 LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'_`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL -     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-LL +     fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime<'_> {
+   |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:104:56
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:106:56
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'a`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:109:66
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:111:66
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-   |                                                                  ^^                           -- the lifetime gets resolved as `'a`
+   |                                                                  ^^                           -- the same lifetime is elided here
    |                                                                  |
-   |                                                                  this lifetime flows to the output
+   |                                                                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:124:39
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:126:39
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-   |                                       ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                                       ^^^^^^^        --- the same lifetime is elided here
    |                                       |
-   |                                       this lifetime flows to the output
+   |                                       the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 {
    |                                                       +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:129:49
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:131:49
    |
 LL |     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-   |                                                 ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                                                 ^^^^^^^         -- the same lifetime is elided here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
 LL +     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:134:40
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:136:40
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-   |                                        ^^^^^^^        ---------------- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^        ---------------- the same lifetime is hidden here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> {
    |                                                                       +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:139:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:141:50
    |
 LL |     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-   |                                                  ^^^^^^^                         -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^                         -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
 LL +     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:145:40
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:147:40
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-   |                                        ^^^^^^^          --- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^          --- the same lifetime is elided here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &'static u8 {
    |                                                          +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:150:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:152:50
    |
 LL |         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-   |                                                  ^^^^^^^           -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^           -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
 LL +         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:155:41
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:157:41
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-   |                                         ^^^^^^^          ---------------- the lifetime gets resolved as `'static`
+   |                                         ^^^^^^^          ---------------- the same lifetime is hidden here
    |                                         |
-   |                                         this lifetime flows to the output
+   |                                         the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> {
    |                                                                          +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:160:51
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:162:51
    |
 LL |         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-   |                                                   ^^^^^^^                           -- the lifetime gets resolved as `'static`
+   |                                                   ^^^^^^^                           -- the same lifetime is elided here
    |                                                   |
-   |                                                   this lifetime flows to the output
+   |                                                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
 LL +         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:172:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:174:55
    |
 LL |     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-   |                                                       ^^                        -- the lifetime gets resolved as `'a`
+   |                                                       ^^                        -- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:177:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:179:65
    |
 LL |     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-   |                                                                 ^^                            -- the lifetime gets resolved as `'a`
-   |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 ^^ the lifetime is named here -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
 LL +     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:182:72
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:184:72
    |
 LL |     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-   |                                                                        ^^                      -- the lifetime gets resolved as `'a`
+   |                                                                        ^^                      -- the same lifetime is elided here
    |                                                                        |
-   |                                                                        this lifetime flows to the output
+   |                                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:188:29
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:190:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> impl FnOnce() + use<'_> {
-   |                              -- the lifetime gets resolved as `'a`
+   |                              -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     ) -> impl FnOnce() + use<'_> {
 LL +     ) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:202:54
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:204:54
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-   |                                                      ^^                                ---    -- the lifetimes get resolved as `'a`
-   |                                                      |                                 |
-   |                                                      |                                 the lifetimes get resolved as `'a`
-   |                                                      this lifetime flows to the output
+   |                                                      ^^ the lifetime is named here     --- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &'a u8> + '_> {
    |                                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:208:29
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:210:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
-   |                                  ----------------    -- the lifetimes get resolved as `'a`
-   |                                  |
-   |                                  the lifetimes get resolved as `'a`
+   |                                  ---------------- the same lifetime is hidden here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime<'a>> + '_> {
    |                                                  ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:217:33
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:222:33
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+   |                                 ^^      ^^         --- the same lifetime is elided here
+   |                                 |       |
+   |                                 |       the lifetime is named here
+   |                                 the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 {
+   |                                                     ++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:227:33
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-   |                                 ^^         ---  --- the lifetimes get resolved as `'a`
+   |                                 ^^         ---  --- the same lifetime is elided here
    |                                 |          |
-   |                                 |          the lifetimes get resolved as `'a`
-   |                                 this lifetime flows to the output
+   |                                 |          the same lifetime is elided here
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) {
    |                                             ++      ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:230:45
+error: hiding or eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:232:53
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+   |                                                     ^^       ---  ---------------- the same lifetime is hidden here
+   |                                                     |        |
+   |                                                     |        the same lifetime is elided here
+   |                                                     the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, ContainsLifetime<'a>) {
+   |                                                               ++                     ++++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:237:38
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+   |                                      ^^         ---   --                      -- the same lifetime is named here
+   |                                      |          |     |
+   |                                      |          |     the same lifetime is named here
+   |                                      |          the same lifetime is elided here
+   |                                      the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&'a u8, &'a u8, ContainsLifetime<'a>) {
+   |                                                  ++
+
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:250:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:233:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:253:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>;
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:238:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:258:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:243:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:263:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:257:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:277:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: aborting due to 39 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
index ecd669059ed..ce2fb8235cc 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
@@ -4,11 +4,11 @@ struct Foo<'a>(&'a str);
 
 impl<'b> Foo<'b> {
     fn a<'a>(self: Self, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
 }
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
index 5351bf3c94c..7108fa1a290 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:6:30
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &str {
-   |                              ^^         ---- the lifetime gets resolved as `'a`
+   |                              ^^         ---- the same lifetime is elided here
    |                              |
-   |                              this lifetime flows to the output
+   |                              the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &'a str {
    |                                          ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:10:33
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-   |                                 ^^         ---- the lifetime gets resolved as `'a`
+   |                                 ^^         ---- the same lifetime is elided here
    |                                 |
-   |                                 this lifetime flows to the output
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str {
    |                                             ++
diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs
index f839ab03a60..0093971fee4 100644
--- a/tests/ui/self/self_lifetime-async.rs
+++ b/tests/ui/self/self_lifetime-async.rs
@@ -4,13 +4,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr
index a9c1be2e808..43dc96abdc2 100644
--- a/tests/ui/self/self_lifetime-async.stderr
+++ b/tests/ui/self/self_lifetime-async.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:6:29
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                             ^^             --- the lifetime gets resolved as `'b`
+   |                             ^^             --- the same lifetime is elided here
    |                             |
-   |                             this lifetime flows to the output
+   |                             the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                             ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:12:42
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                          ^^        --- the lifetime gets resolved as `'a`
+   |                                          ^^        --- the same lifetime is elided here
    |                                          |
-   |                                          this lifetime flows to the output
+   |                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                                     ++
diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs
index aaa31f85ad5..190809af22f 100644
--- a/tests/ui/self/self_lifetime.rs
+++ b/tests/ui/self/self_lifetime.rs
@@ -5,13 +5,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr
index ec676e69cf6..4f9b2fcd2ad 100644
--- a/tests/ui/self/self_lifetime.stderr
+++ b/tests/ui/self/self_lifetime.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:7:23
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                       ^^             --- the lifetime gets resolved as `'b`
+   |                       ^^             --- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                       ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:13:36
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                    ^^        --- the lifetime gets resolved as `'a`
+   |                                    ^^        --- the same lifetime is elided here
    |                                    |
-   |                                    this lifetime flows to the output
+   |                                    the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                               ++