diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 1522d12cbf92e..85d9687c600dc 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -50,12 +50,11 @@ pub enum Delimiter {
     Brace,
     /// `[ ... ]`
     Bracket,
-    /// `/*«*/ ... /*»*/`
+    /// `Ø ... Ø`
     /// An invisible delimiter, that may, for example, appear around tokens coming from a
     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
     /// `$var * 3` where `$var` is `1 + 2`.
-    /// Invisible delimiters are not directly writable in normal Rust code except as comments.
-    /// Therefore, they might not survive a roundtrip of a token stream through a string.
+    /// Invisible delimiters might not survive roundtrip of a token stream through a string.
     Invisible,
 }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 7357ddf2134e4..b80a553b4185c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -590,28 +590,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                     self.nbsp();
                 }
                 self.word("{");
-                let empty = tts.is_empty();
-                if !empty {
+                if !tts.is_empty() {
                     self.space();
                 }
                 self.ibox(0);
                 self.print_tts(tts, convert_dollar_crate);
                 self.end();
-                self.bclose(span, empty);
-            }
-            Some(Delimiter::Invisible) => {
-                self.word("/*«*/");
                 let empty = tts.is_empty();
-                if !empty {
-                    self.space();
-                }
-                self.ibox(0);
-                self.print_tts(tts, convert_dollar_crate);
-                self.end();
-                if !empty {
-                    self.space();
-                }
-                self.word("/*»*/");
+                self.bclose(span, empty);
             }
             Some(delim) => {
                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
@@ -786,8 +772,9 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             token::CloseDelim(Delimiter::Bracket) => "]".into(),
             token::OpenDelim(Delimiter::Brace) => "{".into(),
             token::CloseDelim(Delimiter::Brace) => "}".into(),
-            token::OpenDelim(Delimiter::Invisible) => "/*«*/".into(),
-            token::CloseDelim(Delimiter::Invisible) => "/*»*/".into(),
+            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
+                "".into()
+            }
             token::Pound => "#".into(),
             token::Dollar => "$".into(),
             token::Question => "?".into(),
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 4d2a16aa60984..cb4b154d271a5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -567,15 +567,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         let lifetime =
             self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
         match lifetime.name {
-            hir::LifetimeName::Param(_)
+            hir::LifetimeName::Param(hir::ParamName::Plain(_) | hir::ParamName::Error)
             | hir::LifetimeName::Error
-            | hir::LifetimeName::Static
-            | hir::LifetimeName::Underscore => {
+            | hir::LifetimeName::Static => {
                 let lifetime_span = lifetime.span;
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+            hir::LifetimeName::Param(hir::ParamName::Fresh(_))
+            | hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::Underscore => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index c98989b23c1a5..076b1b1caed72 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -14,3 +14,21 @@ parser-add-paren = try adding parentheses
 parser-forgot-paren = perhaps you forgot parentheses?
 
 parser-expect-path = expected a path
+
+parser-maybe-recover-from-bad-qpath-stage-2 =
+    missing angle brackets in associated item path
+    .suggestion = try: `{$ty}`
+
+parser-incorrect-semicolon =
+    expected item, found `;`
+    .suggestion = remove this semicolon
+    .help = {$name} declarations are not followed by a semicolon
+
+parser-incorrect-use-of-await =
+    incorrect use of `await`
+    .parentheses-suggestion = `await` is not a method call, remove the parentheses
+    .postfix-suggestion = `await` is a postfix operation
+
+parser-in-in-typo =
+    expected iterable, found keyword `in`
+    .suggestion = remove the duplicated `in`
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bda7affe52983..dbe6fe6ea8402 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -131,6 +131,17 @@ impl LifetimeName {
         }
     }
 
+    pub fn is_anonymous(&self) -> bool {
+        match *self {
+            LifetimeName::ImplicitObjectLifetimeDefault
+            | LifetimeName::Implicit
+            | LifetimeName::Underscore
+            | LifetimeName::Param(ParamName::Fresh(_))
+            | LifetimeName::Error => true,
+            LifetimeName::Static | LifetimeName::Param(_) => false,
+        }
+    }
+
     pub fn is_elided(&self) -> bool {
         match self {
             LifetimeName::ImplicitObjectLifetimeDefault
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index e156930cc89fd..579d7efb56803 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -72,7 +72,7 @@ use rustc_middle::ty::{
     subst::{GenericArgKind, Subst, SubstsRef},
     Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, iter};
@@ -161,35 +161,45 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
             {
                 sp = param.span;
             }
-            (format!("the lifetime `{}` as defined here", br.name), sp)
+            let text = if br.has_name() {
+                format!("the lifetime `{}` as defined here", br.name)
+            } else {
+                format!("the anonymous lifetime as defined here")
+            };
+            (text, sp)
         }
-        ty::ReFree(ty::FreeRegion {
-            bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
-        }) => {
-            let mut sp = sm.guess_head_span(tcx.def_span(scope));
-            if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+        ty::ReFree(ref fr) => {
+            if !fr.bound_region.is_named()
+                && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
             {
-                sp = param.span;
-            }
-            (format!("the lifetime `{}` as defined here", name), sp)
-        }
-        ty::ReFree(ref fr) => match fr.bound_region {
-            ty::BrAnon(idx) => {
-                if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) {
-                    ("the anonymous lifetime defined here".to_string(), ty.span)
-                } else {
-                    (
+                ("the anonymous lifetime defined here".to_string(), ty.span)
+            } else {
+                match fr.bound_region {
+                    ty::BoundRegionKind::BrNamed(_, name) => {
+                        let mut sp = sm.guess_head_span(tcx.def_span(scope));
+                        if let Some(param) =
+                            tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                        {
+                            sp = param.span;
+                        }
+                        let text = if name == kw::UnderscoreLifetime {
+                            format!("the anonymous lifetime as defined here")
+                        } else {
+                            format!("the lifetime `{}` as defined here", name)
+                        };
+                        (text, sp)
+                    }
+                    ty::BrAnon(idx) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope),
-                    )
+                        tcx.def_span(scope)
+                    ),
+                    _ => (
+                        format!("the lifetime `{}` as defined here", region),
+                        sm.guess_head_span(tcx.def_span(scope)),
+                    ),
                 }
             }
-            _ => (
-                format!("the lifetime `{}` as defined here", region),
-                sm.guess_head_span(tcx.def_span(scope)),
-            ),
-        },
+        }
         _ => bug!(),
     }
 }
@@ -2552,7 +2562,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
                 | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
                 _,
-            ) => {
+            ) if name != kw::UnderscoreLifetime => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(
                     self.tcx.sess,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index cb72cb41a7c00..b744594ddb7e6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -12,6 +12,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::{GenericParamKind, Ty};
 use rustc_middle::ty::Region;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -169,7 +170,7 @@ pub fn suggest_adding_lifetime_params<'tcx>(
         return false;
     };
 
-    if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
+    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
         return false;
     };
 
@@ -188,32 +189,37 @@ pub fn suggest_adding_lifetime_params<'tcx>(
         _ => return false,
     };
 
-    let (suggestion_param_name, introduce_new) = generics
+    let suggestion_param_name = generics
         .params
         .iter()
-        .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
-        .map(|name| (name, false))
-        .unwrap_or_else(|| ("'a".to_string(), true));
-
-    let mut suggestions = vec![
-        if let hir::LifetimeName::Underscore = lifetime_sub.name {
-            (lifetime_sub.span, suggestion_param_name.clone())
+        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+        .map(|p| p.name.ident().name)
+        .find(|i| *i != kw::UnderscoreLifetime);
+    let introduce_new = suggestion_param_name.is_none();
+    let suggestion_param_name =
+        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+    debug!(?lifetime_sup.span);
+    debug!(?lifetime_sub.span);
+    let make_suggestion = |span: rustc_span::Span| {
+        if span.is_empty() {
+            (span, format!("{}, ", suggestion_param_name))
+        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
+            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
         } else {
-            (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-        if let hir::LifetimeName::Underscore = lifetime_sup.name {
-            (lifetime_sup.span, suggestion_param_name.clone())
-        } else {
-            (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-    ];
+            (span, suggestion_param_name.clone())
+        }
+    };
+    let mut suggestions =
+        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
 
     if introduce_new {
-        let new_param_suggestion = match &generics.params {
-            [] => (generics.span, format!("<{}>", suggestion_param_name)),
-            [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
-        };
+        let new_param_suggestion =
+            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
+                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+            } else {
+                (generics.span, format!("<{}>", suggestion_param_name))
+            };
 
         suggestions.push(new_param_suggestion);
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3de5273d8c78c..375ad8d3736dc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -4,6 +4,7 @@ use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_middle::ty;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
@@ -67,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let is_impl_item = region_info.is_impl_item;
 
         match br {
-            ty::BrAnon(_) => {}
+            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
             _ => {
                 /* not an anonymous region */
                 debug!("try_report_named_anon_conflict: not an anonymous region");
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4c0bc2e4337c7..64c63e3d567d0 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2177,61 +2177,47 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         define_scoped_cx!(self);
 
         let mut region_index = self.region_index;
+        let mut next_name = |this: &Self| loop {
+            let name = name_by_region_index(region_index);
+            region_index += 1;
+            if !this.used_region_names.contains(&name) {
+                break name;
+            }
+        };
+
         // If we want to print verbosely, then print *all* binders, even if they
         // aren't named. Eventually, we might just want this as the default, but
         // this is not *quite* right and changes the ordering of some output
         // anyways.
         let (new_value, map) = if self.tcx().sess.verbose() {
             // anon index + 1 (BrEnv takes 0) -> name
-            let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
+            let mut region_map: FxHashMap<_, _> = Default::default();
             let bound_vars = value.bound_vars();
             for var in bound_vars {
+                let ty::BoundVariableKind::Region(var) = var else { continue };
                 match var {
-                    ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
+                    ty::BrAnon(_) | ty::BrEnv => {
                         start_or_continue(&mut self, "for<", ", ");
+                        let name = next_name(&self);
                         do_continue(&mut self, name);
+                        region_map.insert(var, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name));
                     }
-                    ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
+                    ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
                         start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
+                        let name = next_name(&self);
                         do_continue(&mut self, name);
-                        region_map.insert(i + 1, name);
+                        region_map.insert(var, ty::BrNamed(def_id, name));
                     }
-                    ty::BoundVariableKind::Region(ty::BrEnv) => {
+                    ty::BrNamed(_, name) => {
                         start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
                         do_continue(&mut self, name);
-                        region_map.insert(0, name);
                     }
-                    _ => continue,
                 }
             }
             start_or_continue(&mut self, "", "> ");
 
             self.tcx.replace_late_bound_regions(value.clone(), |br| {
-                let kind = match br.kind {
-                    ty::BrNamed(_, _) => br.kind,
-                    ty::BrAnon(i) => {
-                        let name = region_map[&(i + 1)];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                    ty::BrEnv => {
-                        let name = region_map[&0];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                };
+                let kind = region_map[&br.kind];
                 self.tcx.mk_region(ty::ReLateBound(
                     ty::INNERMOST,
                     ty::BoundRegion { var: br.var, kind },
@@ -2242,21 +2228,20 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             let mut name = |br: ty::BoundRegion| {
                 start_or_continue(&mut self, "for<", ", ");
                 let kind = match br.kind {
-                    ty::BrNamed(_, name) => {
-                        do_continue(&mut self, name);
-                        br.kind
-                    }
                     ty::BrAnon(_) | ty::BrEnv => {
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
+                        let name = next_name(&self);
                         do_continue(&mut self, name);
                         ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
+                    ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                        let name = next_name(&self);
+                        do_continue(&mut self, name);
+                        ty::BrNamed(def_id, name)
+                    }
+                    ty::BrNamed(_, name) => {
+                        do_continue(&mut self, name);
+                        br.kind
+                    }
                 };
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
             };
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index ee8e41620019a..a4cdfdf55f9df 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -285,6 +285,54 @@ pub enum BadTypePlusSub {
     },
 }
 
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+struct BadQPathStage2 {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect")]
+    span: Span,
+    ty: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-semicolon")]
+struct IncorrectSemicolon<'a> {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable")]
+    span: Span,
+    #[help]
+    opt_help: Option<()>,
+    name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectUseOfAwait {
+    #[primary_span]
+    #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectAwait {
+    #[primary_span]
+    span: Span,
+    #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+    sugg_span: (Span, Applicability),
+    expr: String,
+    question_mark: &'static str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-in-in-typo")]
+struct InInTypo {
+    #[primary_span]
+    span: Span,
+    #[suggestion(applicability = "machine-applicable")]
+    sugg_span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -1451,15 +1499,10 @@ impl<'a> Parser<'a> {
         path.span = ty_span.to(self.prev_token.span);
 
         let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
-        self.struct_span_err(path.span, "missing angle brackets in associated item path")
-            .span_suggestion(
-                // This is a best-effort recovery.
-                path.span,
-                "try",
-                format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(BadQPathStage2 {
+            span: path.span,
+            ty: format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
+        });
 
         let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`.
         Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
@@ -1468,13 +1511,10 @@ impl<'a> Parser<'a> {
     pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
         if self.token.kind == TokenKind::Semi {
             self.bump();
-            let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
-            err.span_suggestion_short(
-                self.prev_token.span,
-                "remove this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+
+            let mut err =
+                IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" };
+
             if !items.is_empty() {
                 let previous_item = &items[items.len() - 1];
                 let previous_item_kind_name = match previous_item.kind {
@@ -1487,10 +1527,11 @@ impl<'a> Parser<'a> {
                     _ => None,
                 };
                 if let Some(name) = previous_item_kind_name {
-                    err.help(&format!("{name} declarations are not followed by a semicolon"));
+                    err.opt_help = Some(());
+                    err.name = name;
                 }
             }
-            err.emit();
+            self.sess.emit_err(err);
             true
         } else {
             false
@@ -1604,18 +1645,20 @@ impl<'a> Parser<'a> {
     }
 
     fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
-        let expr_str =
-            self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr));
-        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
-        let sp = lo.to(hi);
-        let app = match expr.kind {
+        let span = lo.to(hi);
+        let applicability = match expr.kind {
             ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
             _ => Applicability::MachineApplicable,
         };
-        self.struct_span_err(sp, "incorrect use of `await`")
-            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
-            .emit();
-        sp
+
+        self.sess.emit_err(IncorrectAwait {
+            span,
+            sugg_span: (span, applicability),
+            expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)),
+            question_mark: if is_question { "?" } else { "" },
+        });
+
+        span
     }
 
     /// If encountering `future.await()`, consumes and emits an error.
@@ -1626,16 +1669,10 @@ impl<'a> Parser<'a> {
             // future.await()
             let lo = self.token.span;
             self.bump(); // (
-            let sp = lo.to(self.token.span);
+            let span = lo.to(self.token.span);
             self.bump(); // )
-            self.struct_span_err(sp, "incorrect use of `await`")
-                .span_suggestion(
-                    sp,
-                    "`await` is not a method call, remove the parentheses",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+
+            self.sess.emit_err(IncorrectUseOfAwait { span });
         }
     }
 
@@ -1907,14 +1944,10 @@ impl<'a> Parser<'a> {
     pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
         if self.eat_keyword(kw::In) {
             // a common typo: `for _ in in bar {}`
-            self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`")
-                .span_suggestion_short(
-                    in_span.until(self.prev_token.span),
-                    "remove the duplicated `in`",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(InInTypo {
+                span: self.prev_token.span,
+                sugg_span: in_span.until(self.prev_token.span),
+            });
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 7499e5efdeeab..de5367ca27c3a 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -8,10 +8,11 @@ use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
+use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -29,7 +30,6 @@ use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_ty_utils::representability::{self, Representability};
 
-use rustc_hir::def::DefKind;
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -93,7 +93,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     fcx.return_type_pre_known = return_type_pre_known;
 
     let tcx = fcx.tcx;
-    let sess = tcx.sess;
     let hir = tcx.hir();
 
     let declared_ret_ty = fn_sig.output();
@@ -259,85 +258,123 @@ pub(super) fn check_fn<'a, 'tcx>(
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
         && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(panic_info_did) = tcx.lang_items().panic_info() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
-
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_panic_info = match *inputs[0].kind() {
-                    ty::Ref(region, ty, mutbl) => match *ty.kind() {
-                        ty::Adt(ref adt, _) => {
-                            adt.did() == panic_info_did
-                                && mutbl == hir::Mutability::Not
-                                && !region.is_static()
-                        }
-                        _ => false,
-                    },
-                    _ => false,
-                };
-
-                if !arg_is_panic_info {
-                    sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-                }
-
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(span, "should have no type parameters");
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
-            }
-        } else {
-            sess.err("language item required, but not found: `panic_info`");
-        }
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
     // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
     if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
         && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
+        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+    }
 
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_alloc_layout = match inputs[0].kind() {
-                    ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-                    _ => false,
-                };
+    (fcx, gen_ty)
+}
 
-                if !arg_is_alloc_layout {
-                    sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-                }
+fn check_panic_info_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
 
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(
-                                span,
-                        "`#[alloc_error_handler]` function should have no type parameters",
-                            );
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let span = tcx.def_span(fn_id);
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_panic_info = match *inputs[0].kind() {
+        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+            ty::Adt(ref adt, _) => {
+                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
             }
-        } else {
-            sess.err("language item required, but not found: `alloc_layout`");
-        }
+            _ => false,
+        },
+        _ => false,
+    };
+
+    if !arg_is_panic_info {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
     }
 
-    (fcx, gen_ty)
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no const parameters");
+    }
+}
+
+fn check_alloc_error_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+        tcx.sess.err("language item required, but not found: `alloc_layout`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.def_span(fn_id);
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_alloc_layout = match inputs[0].kind() {
+        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+        _ => false,
+    };
+
+    if !arg_is_alloc_layout {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess
+            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+    }
 }
 
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 277bc1cf0f065..4d17307ddb968 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -660,8 +660,24 @@ fn compare_number_of_generics<'tcx>(
                     _ => None,
                 })
                 .collect();
-            let spans = impl_item.generics.spans();
-            let span = spans.primary_span();
+            let spans = if impl_item.generics.params.is_empty() {
+                vec![impl_item.generics.span]
+            } else {
+                impl_item
+                    .generics
+                    .params
+                    .iter()
+                    .filter(|p| {
+                        matches!(
+                            p.kind,
+                            hir::GenericParamKind::Type { .. }
+                                | hir::GenericParamKind::Const { .. }
+                        )
+                    })
+                    .map(|p| p.span)
+                    .collect::<Vec<Span>>()
+            };
+            let span = spans.first().copied();
 
             let mut err = tcx.sess.struct_span_err_with_code(
                 spans,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 41f3b1fa3dddb..e2c692b5299f4 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1175,14 +1175,33 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// This conversion does not allocate on the heap and happens in place.
     ///
     /// This is also available via [`From`].
-    #[unstable(feature = "box_into_pin", issue = "62370")]
+    ///
+    /// # Notes
+    ///
+    /// It's not recommended that crates add an impl like `From<Box<T>> for Pin<T>`,
+    /// as it'll introduce an ambiguity when calling `Pin::from`.
+    /// A demonstration of such a poor impl is shown below.
+    ///
+    /// ```compile_fail
+    /// # use std::pin::Pin;
+    /// struct Foo; // A type defined in this crate.
+    /// impl From<Box<()>> for Pin<Foo> {
+    ///     fn from(_: Box<()>) -> Pin<Foo> {
+    ///         Pin::new(Foo)
+    ///     }
+    /// }
+    ///
+    /// let foo = Box::new(());
+    /// let bar = Pin::from(foo);
+    /// ```
+    #[stable(feature = "box_into_pin", since = "1.63.0")]
     #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     pub const fn into_pin(boxed: Self) -> Pin<Self>
     where
         A: 'static,
     {
         // It's not possible to move or replace the insides of a `Pin<Box<T>>`
-        // when `T: !Unpin`,  so it's safe to pin it directly without any
+        // when `T: !Unpin`, so it's safe to pin it directly without any
         // additional requirements.
         unsafe { Pin::new_unchecked(boxed) }
     }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 6f7c6305afc14..f1c5eaad868e9 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -703,12 +703,11 @@ pub enum Delimiter {
     /// `[ ... ]`
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     Bracket,
-    /// `/*«*/ ... /*»*/`
+    /// `Ø ... Ø`
     /// An invisible delimiter, that may, for example, appear around tokens coming from a
     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
     /// `$var * 3` where `$var` is `1 + 2`.
-    /// Invisible delimiters are not directly writable in normal Rust code except as comments.
-    /// Therefore, they might not survive a roundtrip of a token stream through a string.
+    /// Invisible delimiters might not survive roundtrip of a token stream through a string.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     None,
 }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 6a8e4787676e1..5b43e4910e981 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -10,7 +10,7 @@ use std::fmt;
 use rustc_ast::ast;
 use rustc_hir::{def::CtorKind, def_id::DefId};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Pos;
+use rustc_span::{Pos, Symbol};
 use rustc_target::spec::abi::Abi as RustcAbi;
 
 use rustdoc_json_types::*;
@@ -29,7 +29,9 @@ impl JsonRenderer<'_> {
             .get(&item.item_id)
             .into_iter()
             .flatten()
-            .map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into())))
+            .map(|clean::ItemLink { link, did, .. }| {
+                (link.clone(), from_item_id((*did).into(), self.tcx))
+            })
             .collect();
         let docs = item.attrs.collapsed_doc_value();
         let attrs = item
@@ -45,7 +47,7 @@ impl JsonRenderer<'_> {
             _ => from_clean_item(item, self.tcx),
         };
         Some(Item {
-            id: from_item_id(item_id),
+            id: from_item_id_with_name(item_id, self.tcx, name),
             crate_id: item_id.krate().as_u32(),
             name: name.map(|sym| sym.to_string()),
             span: self.convert_span(span),
@@ -84,7 +86,7 @@ impl JsonRenderer<'_> {
             Inherited => Visibility::Default,
             Restricted(did) if did.is_crate_root() => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
-                parent: from_item_id(did.into()),
+                parent: from_item_id(did.into(), self.tcx),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
@@ -173,22 +175,39 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     }
 }
 
-pub(crate) fn from_item_id(item_id: ItemId) -> Id {
-    struct DisplayDefId(DefId);
+/// It generates an ID as follows:
+///
+/// "CRATE_ID:ITEM_ID[:NAME_ID]" (if there is no name, NAME_ID is not generated).
+pub(crate) fn from_item_id(item_id: ItemId, tcx: TyCtxt<'_>) -> Id {
+    from_item_id_with_name(item_id, tcx, None)
+}
+
+// FIXME: this function (and appending the name at the end of the ID) should be removed when
+// reexports are not inlined anymore for json format. It should be done in #93518.
+pub(crate) fn from_item_id_with_name(item_id: ItemId, tcx: TyCtxt<'_>, name: Option<Symbol>) -> Id {
+    struct DisplayDefId<'a>(DefId, TyCtxt<'a>, Option<Symbol>);
 
-    impl fmt::Display for DisplayDefId {
+    impl<'a> fmt::Display for DisplayDefId<'a> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "{}:{}", self.0.krate.as_u32(), u32::from(self.0.index))
+            let name = match self.2 {
+                Some(name) => format!(":{}", name.as_u32()),
+                None => self
+                    .1
+                    .opt_item_name(self.0)
+                    .map(|n| format!(":{}", n.as_u32()))
+                    .unwrap_or_default(),
+            };
+            write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
         }
     }
 
     match item_id {
-        ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did))),
+        ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did, tcx, name))),
         ItemId::Blanket { for_, impl_id } => {
-            Id(format!("b:{}-{}", DisplayDefId(impl_id), DisplayDefId(for_)))
+            Id(format!("b:{}-{}", DisplayDefId(impl_id, tcx, None), DisplayDefId(for_, tcx, name)))
         }
         ItemId::Auto { for_, trait_ } => {
-            Id(format!("a:{}-{}", DisplayDefId(trait_), DisplayDefId(for_)))
+            Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
         }
         ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
     }
@@ -201,7 +220,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
     let header = item.fn_header(tcx);
 
     match *item.kind {
-        ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items) }),
+        ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx) }),
         ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
         StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
         UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
@@ -255,7 +274,7 @@ impl FromWithTcx<clean::Struct> for Struct {
             struct_type: from_ctor_kind(struct_type),
             generics: generics.into_tcx(tcx),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -268,7 +287,7 @@ impl FromWithTcx<clean::Union> for Union {
         Union {
             generics: generics.into_tcx(tcx),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -413,7 +432,7 @@ impl FromWithTcx<clean::Type> for Type {
         match ty {
             clean::Type::Path { path } => Type::ResolvedPath {
                 name: path.whole_name(),
-                id: from_item_id(path.def_id().into()),
+                id: from_item_id(path.def_id().into(), tcx),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: Vec::new(),
             },
@@ -422,7 +441,7 @@ impl FromWithTcx<clean::Type> for Type {
 
                 Type::ResolvedPath {
                     name: first_trait.whole_name(),
-                    id: from_item_id(first_trait.def_id().into()),
+                    id: from_item_id(first_trait.def_id().into(), tcx),
                     args: first_trait
                         .segments
                         .last()
@@ -517,7 +536,7 @@ impl FromWithTcx<clean::Trait> for Trait {
         Trait {
             is_auto,
             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
-            items: ids(items),
+            items: ids(items, tcx),
             generics: generics.into_tcx(tcx),
             bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             implementations: Vec::new(), // Added in JsonRenderer::item
@@ -550,7 +569,7 @@ impl FromWithTcx<clean::Impl> for Impl {
                 .collect(),
             trait_,
             for_: for_.into_tcx(tcx),
-            items: ids(items),
+            items: ids(items, tcx),
             negative: negative_polarity,
             synthetic,
             blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
@@ -593,21 +612,21 @@ impl FromWithTcx<clean::Enum> for Enum {
         Enum {
             generics: generics.into_tcx(tcx),
             variants_stripped,
-            variants: ids(variants),
+            variants: ids(variants, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
 }
 
 impl FromWithTcx<clean::VariantStruct> for Struct {
-    fn from_tcx(struct_: clean::VariantStruct, _tcx: TyCtxt<'_>) -> Self {
+    fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
         let fields_stripped = struct_.has_stripped_entries();
         let clean::VariantStruct { struct_type, fields } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
             generics: Default::default(),
             fields_stripped,
-            fields: ids(fields),
+            fields: ids(fields, tcx),
             impls: Vec::new(),
         }
     }
@@ -630,25 +649,25 @@ impl FromWithTcx<clean::Variant> for Variant {
                     })
                     .collect(),
             ),
-            Struct(s) => Variant::Struct(ids(s.fields)),
+            Struct(s) => Variant::Struct(ids(s.fields, tcx)),
         }
     }
 }
 
 impl FromWithTcx<clean::Import> for Import {
-    fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self {
+    fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
         use clean::ImportKind::*;
         match import.kind {
             Simple(s) => Import {
                 source: import.source.path.whole_name(),
                 name: s.to_string(),
-                id: import.source.did.map(ItemId::from).map(from_item_id),
+                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
                 glob: false,
             },
             Glob => Import {
                 source: import.source.path.whole_name(),
                 name: import.source.path.last().to_string(),
-                id: import.source.did.map(ItemId::from).map(from_item_id),
+                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
                 glob: true,
             },
         }
@@ -742,6 +761,10 @@ impl FromWithTcx<ItemType> for ItemKind {
     }
 }
 
-fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
-    items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_item_id(i.item_id)).collect()
+fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id> {
+    items
+        .into_iter()
+        .filter(|x| !x.is_stripped())
+        .map(|i| from_item_id_with_name(i.item_id, tcx, i.name))
+        .collect()
 }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 08f61056d853f..f338050bee0f9 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -16,6 +16,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_span::def_id::LOCAL_CRATE;
 
 use rustdoc_json_types as types;
 
@@ -25,7 +26,7 @@ use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
-use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::json::conversions::{from_item_id, from_item_id_with_name, IntoWithTcx};
 use crate::{clean, try_err};
 
 #[derive(Clone)]
@@ -54,7 +55,7 @@ impl<'tcx> JsonRenderer<'tcx> {
                     .map(|i| {
                         let item = &i.impl_item;
                         self.item(item.clone()).unwrap();
-                        from_item_id(item.item_id)
+                        from_item_id_with_name(item.item_id, self.tcx, item.name)
                     })
                     .collect()
             })
@@ -86,7 +87,7 @@ impl<'tcx> JsonRenderer<'tcx> {
 
                         if item.item_id.is_local() || is_primitive_impl {
                             self.item(item.clone()).unwrap();
-                            Some(from_item_id(item.item_id))
+                            Some(from_item_id_with_name(item.item_id, self.tcx, item.name))
                         } else {
                             None
                         }
@@ -105,10 +106,11 @@ impl<'tcx> JsonRenderer<'tcx> {
                 if !id.is_local() {
                     let trait_item = &trait_item.trait_;
                     trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
+                    let item_id = from_item_id(id.into(), self.tcx);
                     Some((
-                        from_item_id(id.into()),
+                        item_id.clone(),
                         types::Item {
-                            id: from_item_id(id.into()),
+                            id: item_id,
                             crate_id: id.krate.as_u32(),
                             name: self
                                 .cache
@@ -176,6 +178,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         // Flatten items that recursively store other items
         item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
+        let name = item.name;
         let item_id = item.item_id;
         if let Some(mut new_item) = self.convert_item(item) {
             if let types::ItemEnum::Trait(ref mut t) = new_item.inner {
@@ -187,7 +190,10 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
             } else if let types::ItemEnum::Union(ref mut u) = new_item.inner {
                 u.impls = self.get_impls(item_id.expect_def_id())
             }
-            let removed = self.index.borrow_mut().insert(from_item_id(item_id), new_item.clone());
+            let removed = self
+                .index
+                .borrow_mut()
+                .insert(from_item_id_with_name(item_id, self.tcx, name), new_item.clone());
 
             // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
             // to make sure the items are unique. The main place this happens is when an item, is
@@ -211,13 +217,15 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
             self.get_impls(*primitive);
         }
 
+        let e = ExternalCrate { crate_num: LOCAL_CRATE };
+
         let mut index = (*self.index).clone().into_inner();
         index.extend(self.get_trait_items());
         // This needs to be the default HashMap for compatibility with the public interface for
         // rustdoc-json-types
         #[allow(rustc::default_hash_types)]
         let output = types::Crate {
-            root: types::Id(String::from("0:0")),
+            root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
             crate_version: self.cache.crate_version.clone(),
             includes_private: self.cache.document_private,
             index: index.into_iter().collect(),
@@ -229,7 +237,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
-                        from_item_id(k.into()),
+                        from_item_id(k.into(), self.tcx),
                         types::ItemSummary {
                             crate_id: k.krate.as_u32(),
                             path: path.iter().map(|s| s.to_string()).collect(),
diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
new file mode 100644
index 0000000000000..fd6ac8372d976
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
@@ -0,0 +1,17 @@
+// Regression test for https://github.com/rust-lang/rust/issues/97432.
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+// @has same_type_reexported_more_than_once.json
+// @set trait_id = - "$.index[*][?(@.name=='Trait')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $trait_id
+pub use inner::Trait;
+// @set reexport_id = - "$.index[*][?(@.name=='Reexport')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id
+pub use inner::Trait as Reexport;
+
+mod inner {
+    pub trait Trait {}
+}
diff --git a/src/test/ui/async-await/issue-76547.base.stderr b/src/test/ui/async-await/issue-76547.base.stderr
index 34705d4838e76..109883fbeb7cb 100644
--- a/src/test/ui/async-await/issue-76547.base.stderr
+++ b/src/test/ui/async-await/issue-76547.base.stderr
@@ -5,6 +5,12 @@ LL | async fn fut(bufs: &mut [&mut [u8]]) {
    |                    ---------------- these two types are declared with different lifetimes...
 LL |     ListFut(bufs).await
    |             ^^^^ ...but data from `bufs` flows into `bufs` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+   |             ++++        ++       ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:39:14
@@ -13,6 +19,12 @@ LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    |                     ---------------- these two types are declared with different lifetimes...
 LL |     ListFut2(bufs).await
    |              ^^^^ ...but data from `bufs` flows into `bufs` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+   |              ++++        ++       ++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/async-await/issue-76547.nll.stderr b/src/test/ui/async-await/issue-76547.nll.stderr
index bc30da1e389b3..0a5a52cb79e4c 100644
--- a/src/test/ui/async-await/issue-76547.nll.stderr
+++ b/src/test/ui/async-await/issue-76547.nll.stderr
@@ -7,6 +7,11 @@ LL | async fn fut(bufs: &mut [&mut [u8]]) {
    |                    let's call the lifetime of this reference `'1`
 LL |     ListFut(bufs).await
    |             ^^^^ this usage requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+   |             ++++        ++       ++
 
 error: lifetime may not live long enough
   --> $DIR/issue-76547.rs:39:14
@@ -17,6 +22,11 @@ LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    |                     let's call the lifetime of this reference `'1`
 LL |     ListFut2(bufs).await
    |              ^^^^ this usage requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+   |              ++++        ++       ++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/async-await/issues/issue-63388-1.base.stderr b/src/test/ui/async-await/issues/issue-63388-1.base.stderr
index 2ff85a27a4645..f5409a7ca5d29 100644
--- a/src/test/ui/async-await/issues/issue-63388-1.base.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-1.base.stderr
@@ -1,14 +1,12 @@
-error[E0623]: lifetime mismatch
+error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:19:9
    |
 LL |         &'a self, foo: &dyn Foo
-   |                        -------- this parameter and the return type are declared with different lifetimes...
-LL |     ) -> &dyn Foo
-   |          --------
+   |                        -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
 ...
 LL |         foo
-   |         ^^^ ...but data from `foo` is returned here
+   |         ^^^ lifetime `'a` required
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0623`.
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr
index eee0cee278b9c..9263a81bb6af4 100644
--- a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr
@@ -1,17 +1,16 @@
-error: lifetime may not live long enough
+error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:17:5
    |
-LL |       async fn do_sth<'a>(
-   |                       -- lifetime `'a` defined here
 LL |           &'a self, foo: &dyn Foo
-   |                          - let's call the lifetime of this reference `'1`
+   |                          -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
 LL |       ) -> &dyn Foo
 LL | /     {
 LL | |
 LL | |         foo
 LL | |
 LL | |     }
-   | |_____^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   | |_____^ lifetime `'a` required
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/async-await/issues/issue-63388-1.rs b/src/test/ui/async-await/issues/issue-63388-1.rs
index c45d2a42177ce..f00f929540640 100644
--- a/src/test/ui/async-await/issues/issue-63388-1.rs
+++ b/src/test/ui/async-await/issues/issue-63388-1.rs
@@ -15,9 +15,9 @@ impl Xyz {
         &'a self, foo: &dyn Foo
     ) -> &dyn Foo
     {
-        //[nll]~^ ERROR lifetime may not live long enough
+        //[nll]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
         foo
-        //[base]~^ ERROR lifetime mismatch
+        //[base]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
     }
 }
 
diff --git a/src/test/ui/error-codes/E0308-2.stderr b/src/test/ui/error-codes/E0308-2.stderr
index 5c1dcb4d4f9b3..de54a417253d4 100644
--- a/src/test/ui/error-codes/E0308-2.stderr
+++ b/src/test/ui/error-codes/E0308-2.stderr
@@ -6,7 +6,7 @@ LL | impl Eq for &dyn DynEq {}
    |
    = note: expected trait `<&dyn DynEq as PartialEq>`
               found trait `<&(dyn DynEq + 'static) as PartialEq>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/E0308-2.rs:9:13
    |
 LL | impl Eq for &dyn DynEq {}
diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
index 1458bf0c4a493..76d39c88b61c3 100644
--- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
+++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
@@ -8,7 +8,7 @@ LL |     type A = u32;
    |           ^ lifetimes do not match type in trait
 
 error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/parameter_number_and_kind_impl.rs:17:12
+  --> $DIR/parameter_number_and_kind_impl.rs:17:16
    |
 LL |     type B<'a, 'b>;
    |            --  --
@@ -16,9 +16,7 @@ LL |     type B<'a, 'b>;
    |            expected 0 type parameters
 ...
 LL |     type B<'a, T> = Vec<T>;
-   |            ^^  ^
-   |            |
-   |            found 1 type parameter
+   |                ^ found 1 type parameter
 
 error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
   --> $DIR/parameter_number_and_kind_impl.rs:19:11
diff --git a/src/test/ui/issues/issue-17905-2.stderr b/src/test/ui/issues/issue-17905-2.stderr
index c68265f71f259..88b5fbec6cf03 100644
--- a/src/test/ui/issues/issue-17905-2.stderr
+++ b/src/test/ui/issues/issue-17905-2.stderr
@@ -11,7 +11,7 @@ note: the anonymous lifetime defined here...
    |
 LL |     fn say(self: &Pair<&str, isize>) {
    |                        ^^^^
-note: ...does not necessarily outlive the lifetime `'_` as defined here
+note: ...does not necessarily outlive the anonymous lifetime as defined here
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
@@ -25,7 +25,7 @@ LL |     fn say(self: &Pair<&str, isize>) {
    |
    = note: expected struct `Pair<&str, _>`
               found struct `Pair<&str, _>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
diff --git a/src/test/ui/issues/issue-65230.stderr b/src/test/ui/issues/issue-65230.stderr
index bfeb38d6471e4..fcabcdea74fc2 100644
--- a/src/test/ui/issues/issue-65230.stderr
+++ b/src/test/ui/issues/issue-65230.stderr
@@ -6,7 +6,7 @@ LL | impl T1 for &dyn T2 {}
    |
    = note: expected trait `<&dyn T2 as T0>`
               found trait `<&(dyn T2 + 'static) as T0>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/issue-65230.rs:8:13
    |
 LL | impl T1 for &dyn T2 {}
diff --git a/src/test/ui/nll/issue-52742.base.stderr b/src/test/ui/nll/issue-52742.base.stderr
index 259f378f70b5c..7b1fac082e42f 100644
--- a/src/test/ui/nll/issue-52742.base.stderr
+++ b/src/test/ui/nll/issue-52742.base.stderr
@@ -4,7 +4,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         self.y = b.z
    |                  ^^^
    |
-note: ...the reference is valid for the lifetime `'_` as defined here...
+note: ...the reference is valid for the anonymous lifetime as defined here...
   --> $DIR/issue-52742.rs:15:10
    |
 LL | impl Foo<'_, '_> {
diff --git a/src/test/ui/nll/issue-52742.nll.stderr b/src/test/ui/nll/issue-52742.nll.stderr
index 6828418a78ec1..1a2165e0a9dac 100644
--- a/src/test/ui/nll/issue-52742.nll.stderr
+++ b/src/test/ui/nll/issue-52742.nll.stderr
@@ -2,7 +2,7 @@ error: lifetime may not live long enough
   --> $DIR/issue-52742.rs:17:9
    |
 LL |     fn take_bar(&mut self, b: Bar<'_>) {
-   |                 ---------         -- let's call this `'1`
+   |                 ---------  - has type `Bar<'1>`
    |                 |
    |                 has type `&mut Foo<'_, '2>`
 LL |         self.y = b.z
diff --git a/src/test/ui/nll/issue-55394.base.stderr b/src/test/ui/nll/issue-55394.base.stderr
index cc87954732c4e..2ec6a7af3f257 100644
--- a/src/test/ui/nll/issue-55394.base.stderr
+++ b/src/test/ui/nll/issue-55394.base.stderr
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |         Foo { bar }
    |               ^^^
-note: but, the lifetime must be valid for the lifetime `'_` as defined here...
+note: but, the lifetime must be valid for the anonymous lifetime as defined here...
   --> $DIR/issue-55394.rs:11:10
    |
 LL | impl Foo<'_> {
diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
index a2e30e2e93b5a..2bc34f3c6bfc0 100644
--- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs
+++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
@@ -12,15 +12,6 @@ use std::str::FromStr;
 
 #[proc_macro]
 pub fn expand_expr_is(input: TokenStream) -> TokenStream {
-    expand_expr_is_inner(input, false)
-}
-
-#[proc_macro]
-pub fn expand_expr_is_trim(input: TokenStream) -> TokenStream {
-    expand_expr_is_inner(input, true)
-}
-
-fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream {
     let mut iter = input.into_iter();
     let mut expected_tts = Vec::new();
     loop {
@@ -31,18 +22,14 @@ fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream
         }
     }
 
-    // If requested, trim the "invisible" delimiters at the start and end.
-    let expected = expected_tts.into_iter().collect::<TokenStream>().to_string();
-    let expected = if trim_invisible {
-        let len1 = "/*«*/ ".len();
-        let len2 = " /*»*/".len();
-        &expected[len1..expected.len() - len2]
-    } else {
-        &expected[..]
-    };
-    let expanded = iter.collect::<TokenStream>().expand_expr().unwrap().to_string();
-
-    assert_eq!(expected, expanded);
+    let expected = expected_tts.into_iter().collect::<TokenStream>();
+    let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
+    assert!(
+        expected.to_string() == expanded.to_string(),
+        "assert failed\nexpected: `{}`\nexpanded: `{}`",
+        expected.to_string(),
+        expanded.to_string()
+    );
 
     TokenStream::new()
 }
diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout
index 3d0e7eaff00d8..4de8746a1b460 100644
--- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout
+++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): self
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ self /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
@@ -14,10 +13,8 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
 ]
 PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30,
 std::option::Option, pub(in some::path) , [a b c], -30
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/, /*«*/ { "a" } /*»*/, /*«*/ let a = 1 /*»*/, /*«*/
-String /*»*/, my_name, /*«*/ 'a /*»*/, /*«*/ my_val = 30 /*»*/, /*«*/
-std :: option :: Option /*»*/, /*«*/ pub(in some :: path) /*»*/, [a b c],
-/*«*/ - 30 /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30,
+std :: option :: Option, pub(in some :: path), [a b c], - 30
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
@@ -298,7 +295,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): (a, b)
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ (a, b) /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/capture-unglued-token.stdout b/src/test/ui/proc-macro/capture-unglued-token.stdout
index 5fe6ff72b4544..7e6b540332c79 100644
--- a/src/test/ui/proc-macro/capture-unglued-token.stdout
+++ b/src/test/ui/proc-macro/capture-unglued-token.stdout
@@ -1,5 +1,5 @@
 PRINT-BANG INPUT (DISPLAY): Vec<u8>
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ Vec < u8 > /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 >
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/expand-expr.rs b/src/test/ui/proc-macro/expand-expr.rs
index edcb30f892cdf..d1146d9703062 100644
--- a/src/test/ui/proc-macro/expand-expr.rs
+++ b/src/test/ui/proc-macro/expand-expr.rs
@@ -2,9 +2,9 @@
 
 extern crate expand_expr;
 
-use expand_expr::{check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is};
-use expand_expr::{expand_expr_is_trim, recursive_expand};
-
+use expand_expr::{
+    check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand,
+};
 
 // Check builtin macros can be expanded.
 
@@ -47,21 +47,21 @@ macro_rules! echo_expr {
 
 macro_rules! simple_lit {
     ($l:literal) => {
-        expand_expr_is_trim!($l, $l);
-        expand_expr_is_trim!($l, echo_lit!($l));
-        expand_expr_is_trim!($l, echo_expr!($l));
-        expand_expr_is_trim!($l, echo_tts!($l));
-        expand_expr_is_trim!($l, echo_pm!($l));
+        expand_expr_is!($l, $l);
+        expand_expr_is!($l, echo_lit!($l));
+        expand_expr_is!($l, echo_expr!($l));
+        expand_expr_is!($l, echo_tts!($l));
+        expand_expr_is!($l, echo_pm!($l));
         const _: () = {
             macro_rules! mac {
                 () => {
                     $l
                 };
             }
-            expand_expr_is_trim!($l, mac!());
-            expand_expr_is_trim!($l, echo_expr!(mac!()));
-            expand_expr_is_trim!($l, echo_tts!(mac!()));
-            expand_expr_is_trim!($l, echo_pm!(mac!()));
+            expand_expr_is!($l, mac!());
+            expand_expr_is!($l, echo_expr!(mac!()));
+            expand_expr_is!($l, echo_tts!(mac!()));
+            expand_expr_is!($l, echo_pm!(mac!()));
         };
     };
 }
diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
index 04b516fd25424..686d53e887660 100644
--- a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
+++ b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
@@ -1,6 +1,5 @@
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E
-{ V = { let _ = /*«*/ #[allow(warnings)] #[allow(warnings)] 0 /*»*/ ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -124,7 +123,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -204,7 +203,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ {} /*»*/ } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -283,7 +281,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -361,7 +359,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
@@ -452,7 +450,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
index 55818969c7178..0fda6654ff370 100644
--- a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
@@ -96,7 +96,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/ * 2
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
index 6cf8043c34f81..60a400a5deabf 100644
--- a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
+++ b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout
@@ -1,7 +1,7 @@
 PRINT-BANG INPUT (DISPLAY): foo! { #[fake_attr] mod bar {
     #![doc = r" Foo"]
 } }
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] /*«*/ mod bar { #! [doc = r" Foo"] } /*»*/ }
+PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] mod bar { #! [doc = r" Foo"] } }
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "foo",
diff --git a/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout b/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout
index adbd653ead4b7..4b7ed874307d8 100644
--- a/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout
+++ b/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): ;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ ; /*»*/
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
index b912e426d5d99..a3d24dd26fe97 100644
--- a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
+++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
@@ -1,6 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 0 + 1 + 2 /*»*/ + 3
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): /*«*/ /*«*/ /*«*/ 0 /*»*/ + 1 /*»*/ + 2 /*»*/ + 3
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout
index 0d2f33b41750d..6b410f0bfb7e3 100644
--- a/src/test/ui/proc-macro/nodelim-groups.stdout
+++ b/src/test/ui/proc-macro/nodelim-groups.stdout
@@ -1,5 +1,4 @@
 PRINT-BANG INPUT (DISPLAY): "hi" 1 + (25) + 1 (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ 1 + (25) + 1 /*»*/ (1 + 1)
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Literal {
         kind: Str,
@@ -72,9 +71,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ "hello".len() + "world".len() /*»*/ (1 + 1)
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): "hi" /*«*/ /*«*/ "hello".len() /*»*/ + /*«*/ "world".len() /*»*/ /*»*/
-(1 + 1)
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Literal {
         kind: Str,
diff --git a/src/test/ui/proc-macro/nonterminal-expansion.stdout b/src/test/ui/proc-macro/nonterminal-expansion.stdout
index 32981e7011d97..4d884348f2ca4 100644
--- a/src/test/ui/proc-macro/nonterminal-expansion.stdout
+++ b/src/test/ui/proc-macro/nonterminal-expansion.stdout
@@ -1,5 +1,5 @@
 PRINT-ATTR_ARGS INPUT (DISPLAY): a, line!(), b
-PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, /*«*/ line! () /*»*/, b
+PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, line! (), b
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "a",
diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
index ba18ca75d7fe4..c08e5308138c9 100644
--- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -1,5 +1,5 @@
 PRINT-BANG INPUT (DISPLAY): struct S;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ struct S ; /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): struct S ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Group {
         delimiter: None,
diff --git a/src/test/ui/proc-macro/parent-source-spans.rs b/src/test/ui/proc-macro/parent-source-spans.rs
index 71e5065a87a88..354657db4db38 100644
--- a/src/test/ui/proc-macro/parent-source-spans.rs
+++ b/src/test/ui/proc-macro/parent-source-spans.rs
@@ -8,16 +8,16 @@ use parent_source_spans::parent_source_spans;
 
 macro one($a:expr, $b:expr) {
     two!($a, $b);
-    //~^ ERROR first parent: /*«*/ "hello" /*»*/
-    //~| ERROR second parent: /*«*/ "world" /*»*/
+    //~^ ERROR first parent: "hello"
+    //~| ERROR second parent: "world"
 }
 
 macro two($a:expr, $b:expr) {
     three!($a, $b);
-    //~^ ERROR first final: /*«*/ "hello" /*»*/
-    //~| ERROR second final: /*«*/ "world" /*»*/
-    //~| ERROR first final: /*«*/ "yay" /*»*/
-    //~| ERROR second final: /*«*/ "rust" /*»*/
+    //~^ ERROR first final: "hello"
+    //~| ERROR second final: "world"
+    //~| ERROR first final: "yay"
+    //~| ERROR second final: "rust"
 }
 
 // forwarding tokens directly doesn't create a new source chain
@@ -34,16 +34,16 @@ macro four($($tokens:tt)*) {
 
 fn main() {
     one!("hello", "world");
-    //~^ ERROR first grandparent: /*«*/ "hello" /*»*/
-    //~| ERROR second grandparent: /*«*/ "world" /*»*/
-    //~| ERROR first source: /*«*/ "hello" /*»*/
-    //~| ERROR second source: /*«*/ "world" /*»*/
+    //~^ ERROR first grandparent: "hello"
+    //~| ERROR second grandparent: "world"
+    //~| ERROR first source: "hello"
+    //~| ERROR second source: "world"
 
     two!("yay", "rust");
-    //~^ ERROR first parent: /*«*/ "yay" /*»*/
-    //~| ERROR second parent: /*«*/ "rust" /*»*/
-    //~| ERROR first source: /*«*/ "yay" /*»*/
-    //~| ERROR second source: /*«*/ "rust" /*»*/
+    //~^ ERROR first parent: "yay"
+    //~| ERROR second parent: "rust"
+    //~| ERROR first source: "yay"
+    //~| ERROR second source: "rust"
 
     three!("hip", "hop");
     //~^ ERROR first final: "hip"
diff --git a/src/test/ui/proc-macro/parent-source-spans.stderr b/src/test/ui/proc-macro/parent-source-spans.stderr
index e42218ea70117..4548269b50793 100644
--- a/src/test/ui/proc-macro/parent-source-spans.stderr
+++ b/src/test/ui/proc-macro/parent-source-spans.stderr
@@ -1,4 +1,4 @@
-error: first final: /*«*/ "hello" /*»*/
+error: first final: "hello"
   --> $DIR/parent-source-spans.rs:16:12
    |
 LL |     three!($a, $b);
@@ -9,7 +9,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second final: /*«*/ "world" /*»*/
+error: second final: "world"
   --> $DIR/parent-source-spans.rs:16:16
    |
 LL |     three!($a, $b);
@@ -20,7 +20,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first parent: /*«*/ "hello" /*»*/
+error: first parent: "hello"
   --> $DIR/parent-source-spans.rs:10:5
    |
 LL |     two!($a, $b);
@@ -31,7 +31,7 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second parent: /*«*/ "world" /*»*/
+error: second parent: "world"
   --> $DIR/parent-source-spans.rs:10:5
    |
 LL |     two!($a, $b);
@@ -42,31 +42,31 @@ LL |     one!("hello", "world");
    |
    = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first grandparent: /*«*/ "hello" /*»*/
+error: first grandparent: "hello"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: second grandparent: /*«*/ "world" /*»*/
+error: second grandparent: "world"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: first source: /*«*/ "hello" /*»*/
+error: first source: "hello"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: second source: /*«*/ "world" /*»*/
+error: second source: "world"
   --> $DIR/parent-source-spans.rs:36:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: first final: /*«*/ "yay" /*»*/
+error: first final: "yay"
   --> $DIR/parent-source-spans.rs:16:12
    |
 LL |     three!($a, $b);
@@ -77,7 +77,7 @@ LL |     two!("yay", "rust");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: second final: /*«*/ "rust" /*»*/
+error: second final: "rust"
   --> $DIR/parent-source-spans.rs:16:16
    |
 LL |     three!($a, $b);
@@ -88,25 +88,25 @@ LL |     two!("yay", "rust");
    |
    = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: first parent: /*«*/ "yay" /*»*/
+error: first parent: "yay"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: second parent: /*«*/ "rust" /*»*/
+error: second parent: "rust"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: first source: /*«*/ "yay" /*»*/
+error: first source: "yay"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: second source: /*«*/ "rust" /*»*/
+error: second source: "rust"
   --> $DIR/parent-source-spans.rs:42:5
    |
 LL |     two!("yay", "rust");
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 570a08cb58768..5b8b9bb68ad1e 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -2,9 +2,9 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                          -                     ^^^^^^^^
+   |                          -----                 ^^^^^^^^
    |                          |
-   |                          hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
+   |                          hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
    |
 help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
    |
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr
index 7985bf266d8e8..d2106630dfed7 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr
@@ -5,6 +5,12 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                                    ----     ----   ^ ...but data from `f` is returned here
    |                                    |
    |                                    this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+   |               ++++            ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
@@ -13,6 +19,12 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |                                     ----              -----------------          ^ ...but data from `f` is returned here
    |                                     |
    |                                     this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |               ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr
index 8a55a7c34d77b..3fd58725d02b7 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr
@@ -6,6 +6,11 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                          |         |
    |                          |         let's call the lifetime of this reference `'1`
    |                          let's call the lifetime of this reference `'2`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+   |               ++++            ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
@@ -15,6 +20,11 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |                          |          |
    |                          |          let's call the lifetime of this reference `'1`
    |                          let's call the lifetime of this reference `'2`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |               ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
diff --git a/src/test/ui/self/elision/lt-ref-self-async.base.stderr b/src/test/ui/self/elision/lt-ref-self-async.base.stderr
index b43854906149a..0e2bbcc3c04db 100644
--- a/src/test/ui/self/elision/lt-ref-self-async.base.stderr
+++ b/src/test/ui/self/elision/lt-ref-self-async.base.stderr
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:24:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:30:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:36:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:42:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:48:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr
index 2ba9a6596f62d..1c889838e7082 100644
--- a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr
+++ b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:24:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:30:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:36:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:42:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:48:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-self-async.base.stderr b/src/test/ui/self/elision/ref-mut-self-async.base.stderr
index 851337552c9ad..8ffc0d6224212 100644
--- a/src/test/ui/self/elision/ref-mut-self-async.base.stderr
+++ b/src/test/ui/self/elision/ref-mut-self-async.base.stderr
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                      ++++  ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:24:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:30:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:36:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:42:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:48:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr
index cdd464039cda0..9beafcd4ff994 100644
--- a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr
+++ b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                      ++++  ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:24:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:30:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:36:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++                ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:42:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:48:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++                 ++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.base.stderr b/src/test/ui/self/elision/ref-mut-struct-async.base.stderr
index 0de11c248758f..fefb3fc194439 100644
--- a/src/test/ui/self/elision/ref-mut-struct-async.base.stderr
+++ b/src/test/ui/self/elision/ref-mut-struct-async.base.stderr
@@ -7,6 +7,12 @@ LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                                               this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++                 ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:22:9
@@ -17,6 +23,12 @@ LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:28:9
@@ -27,6 +39,12 @@ LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:34:9
@@ -37,6 +55,12 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u
    |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:40:9
@@ -47,6 +71,12 @@ LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u
    |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr
index 0ef410c8df1eb..7fbecbe76a548 100644
--- a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr
+++ b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr
@@ -7,6 +7,11 @@ LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++                 ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:22:9
@@ -17,6 +22,11 @@ LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:28:9
@@ -27,6 +37,11 @@ LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++                  ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:34:9
@@ -37,6 +52,11 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:40:9
@@ -47,6 +67,11 @@ LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++                   ++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/elision/ref-self-async.base.stderr b/src/test/ui/self/elision/ref-self-async.base.stderr
index fa13b69bb21a3..2b142b089d51b 100644
--- a/src/test/ui/self/elision/ref-self-async.base.stderr
+++ b/src/test/ui/self/elision/ref-self-async.base.stderr
@@ -7,6 +7,12 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:34:9
@@ -17,6 +23,12 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:40:9
@@ -27,6 +39,12 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:46:9
@@ -37,6 +55,12 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:52:9
@@ -47,6 +71,12 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:58:9
@@ -57,6 +87,12 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:64:9
@@ -67,6 +103,12 @@ LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                                ++++             ++                  ++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/self/elision/ref-self-async.nll.stderr b/src/test/ui/self/elision/ref-self-async.nll.stderr
index 77faaa866505f..f4e531a817c3d 100644
--- a/src/test/ui/self/elision/ref-self-async.nll.stderr
+++ b/src/test/ui/self/elision/ref-self-async.nll.stderr
@@ -7,6 +7,11 @@ LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                      ++++  ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:34:9
@@ -17,6 +22,11 @@ LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                      ++++        ++           ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:40:9
@@ -27,6 +37,11 @@ LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:46:9
@@ -37,6 +52,11 @@ LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                          ++++            ++            ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:52:9
@@ -47,6 +67,11 @@ LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:58:9
@@ -57,6 +82,11 @@ LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                             let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                              ++++                ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:64:9
@@ -67,6 +97,11 @@ LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                            let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                                ++++             ++                  ++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/self/elision/ref-struct-async.base.stderr b/src/test/ui/self/elision/ref-struct-async.base.stderr
index 8da673d44354e..88ddca89804f6 100644
--- a/src/test/ui/self/elision/ref-struct-async.base.stderr
+++ b/src/test/ui/self/elision/ref-struct-async.base.stderr
@@ -7,6 +7,12 @@ LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++             ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:22:9
@@ -17,6 +23,12 @@ LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:28:9
@@ -27,6 +39,12 @@ LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:34:9
@@ -37,6 +55,12 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++               ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:40:9
@@ -47,6 +71,12 @@ LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
    |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                            ++++                ++               ++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/elision/ref-struct-async.nll.stderr b/src/test/ui/self/elision/ref-struct-async.nll.stderr
index ad07c70df8778..83c20329c3dad 100644
--- a/src/test/ui/self/elision/ref-struct-async.nll.stderr
+++ b/src/test/ui/self/elision/ref-struct-async.nll.stderr
@@ -7,6 +7,11 @@ LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                        ++++        ++             ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:22:9
@@ -17,6 +22,11 @@ LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:28:9
@@ -27,6 +37,11 @@ LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                       let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                            ++++            ++              ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:34:9
@@ -37,6 +52,11 @@ LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                               let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                                ++++                ++               ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:40:9
@@ -47,6 +67,11 @@ LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                           let's call the lifetime of this reference `'2`
 LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                            ++++                ++               ++
 
 error: aborting due to 5 previous errors