about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-07-17 12:03:43 +0000
committerbors <bors@rust-lang.org>2025-07-17 12:03:43 +0000
commitbf5e6cc7a7a7eb03e3ed9b875d76530eddd47d5f (patch)
tree14e46016d2fa42234a493c015b51ed5e2b9d3c0d
parent8c12d76304fcceaeaad0d67209e5727e94f5f2b8 (diff)
parent52868368dd2b5783881a1f42b1ec56d5c4d3d75b (diff)
downloadrust-bf5e6cc7a7a7eb03e3ed9b875d76530eddd47d5f.tar.gz
rust-bf5e6cc7a7a7eb03e3ed9b875d76530eddd47d5f.zip
Auto merge of #144058 - matthiaskrgr:rollup-xezozsk, r=matthiaskrgr
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#143326 (Remove deprecated `Error::description` impl from `c_str::FromBytesWithNulError`)
 - rust-lang/rust#143431 (Use relative visibility when noting sealed trait to reduce false positive)
 - rust-lang/rust#143550 (resolve: Use interior mutability for extern module map)
 - rust-lang/rust#143631 (update to literal-escaper-0.0.5)
 - rust-lang/rust#143793 (Opaque type collection: Guard against endlessly recursing free alias types)
 - rust-lang/rust#143880 (tests: Test line debuginfo for linebreaked function parameters)
 - rust-lang/rust#143914 (Reword mismatched-lifetime-syntaxes text based on feedback)
 - rust-lang/rust#143926 (Remove deprecated fields in bootstrap)
 - rust-lang/rust#143955 (Make frame spans appear on a separate trace line)
 - rust-lang/rust#143975 (type_id_eq: check that the hash fully matches the type)
 - rust-lang/rust#143984 (Fix ice for feature-gated `cfg` attributes applied to the crate)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_ast/Cargo.toml2
-rw-r--r--compiler/rustc_ast/src/util/literal.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs53
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs27
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs99
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs7
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs22
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_lint/messages.ftl53
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lifetime_syntax.rs149
-rw-r--r--compiler/rustc_lint/src/lints.rs72
-rw-r--r--compiler/rustc_parse/Cargo.toml2
-rw-r--r--compiler/rustc_parse_format/Cargo.toml2
-rw-r--r--compiler/rustc_proc_macro/Cargo.toml2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs71
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs46
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs9
-rw-r--r--compiler/rustc_resolve/src/ident.rs6
-rw-r--r--compiler/rustc_resolve/src/imports.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs44
-rw-r--r--compiler/rustc_resolve/src/lib.rs83
-rw-r--r--compiler/rustc_resolve/src/macros.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs20
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs11
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/core/src/ffi/c_str.rs26
-rw-r--r--library/proc_macro/Cargo.toml2
-rw-r--r--library/proc_macro/src/lib.rs6
-rw-r--r--src/bootstrap/src/core/config/config.rs8
-rw-r--r--src/bootstrap/src/core/config/toml/llvm.rs16
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs20
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr11
-rw-r--r--src/tools/lint-docs/Cargo.toml2
-rw-r--r--src/tools/miri/src/bin/log/tracing_chrome.rs72
-rw-r--r--tests/codegen/fn-parameters-on-different-lines-debuginfo.rs22
-rw-r--r--tests/ui/check-cfg/cfg-crate-features.rs13
-rw-r--r--tests/ui/check-cfg/cfg-crate-features.stderr33
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.full.stderr11
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.rs2
-rw-r--r--tests/ui/consts/const_transmute_type_id4.rs2
-rw-r--r--tests/ui/consts/const_transmute_type_id4.stderr2
-rw-r--r--tests/ui/consts/const_transmute_type_id5.rs9
-rw-r--r--tests/ui/consts/const_transmute_type_id5.stderr6
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs2
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr7
-rw-r--r--tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs18
-rw-r--r--tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr11
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs2
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr9
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs4
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr18
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs104
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr497
-rw-r--r--tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs13
-rw-r--r--tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr20
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.rs4
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.stderr18
-rw-r--r--tests/ui/self/self_lifetime-async.rs4
-rw-r--r--tests/ui/self/self_lifetime-async.stderr18
-rw-r--r--tests/ui/self/self_lifetime.rs4
-rw-r--r--tests/ui/self/self_lifetime.stderr18
74 files changed, 1205 insertions, 746 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b8a8d7b7d23..7d2fca8bb3f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3136,9 +3136,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.4"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
+checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
 
 [[package]]
 name = "rustc-main"
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 5de2e69072f..155e14a3796 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2024"
 # tidy-alphabetical-start
 bitflags = "2.4.1"
 memchr = "2.7.4"
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_ast_ir = { path = "../rustc_ast_ir" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index fa7878873e5..2dfd695d880 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -126,11 +126,11 @@ impl LitKind {
             token::CStr => {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
-                unescape_c_str(s, |_span, c| match c {
+                unescape_c_str(s, |_span, res| match res {
                     Ok(MixedUnit::Char(c)) => {
-                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                        buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
                     }
-                    Ok(MixedUnit::HighByte(b)) => buf.push(b),
+                    Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
                     Err(err) => {
                         assert!(!err.is_fatal(), "failed to unescape C string literal")
                     }
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index a56855b3bd3..6373cf6e08a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -9,7 +9,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
-use crate::context::{AcceptContext, Stage};
+use crate::context::{AcceptContext, ShouldEmit, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
 use crate::{
     CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
@@ -90,7 +90,7 @@ fn parse_cfg_entry_version<S: Stage>(
     list: &MetaItemListParser<'_>,
     meta_span: Span,
 ) -> Option<CfgEntry> {
-    try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features()));
+    try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
     let Some(version) = list.single() else {
         cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span });
         return None;
@@ -119,7 +119,9 @@ fn parse_cfg_entry_target<S: Stage>(
     list: &MetaItemListParser<'_>,
     meta_span: Span,
 ) -> Option<CfgEntry> {
-    if !cx.features().cfg_target_compact() {
+    if let Some(features) = cx.features_option()
+        && !features.cfg_target_compact()
+    {
         feature_err(
             cx.sess(),
             sym::cfg_target_compact,
@@ -186,12 +188,13 @@ pub fn eval_config_entry(
     cfg_entry: &CfgEntry,
     id: NodeId,
     features: Option<&Features>,
+    emit_lints: ShouldEmit,
 ) -> EvalConfigResult {
     match cfg_entry {
         CfgEntry::All(subs, ..) => {
             let mut all = None;
             for sub in subs {
-                let res = eval_config_entry(sess, sub, id, features);
+                let res = eval_config_entry(sess, sub, id, features, emit_lints);
                 // We cannot short-circuit because `eval_config_entry` emits some lints
                 if !res.as_bool() {
                     all.get_or_insert(res);
@@ -202,7 +205,7 @@ pub fn eval_config_entry(
         CfgEntry::Any(subs, span) => {
             let mut any = None;
             for sub in subs {
-                let res = eval_config_entry(sess, sub, id, features);
+                let res = eval_config_entry(sess, sub, id, features, emit_lints);
                 // We cannot short-circuit because `eval_config_entry` emits some lints
                 if res.as_bool() {
                     any.get_or_insert(res);
@@ -214,7 +217,7 @@ pub fn eval_config_entry(
             })
         }
         CfgEntry::Not(sub, span) => {
-            if eval_config_entry(sess, sub, id, features).as_bool() {
+            if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() {
                 EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
             } else {
                 EvalConfigResult::True
@@ -228,24 +231,28 @@ pub fn eval_config_entry(
             }
         }
         CfgEntry::NameValue { name, name_span, value, span } => {
-            match sess.psess.check_config.expecteds.get(name) {
-                Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => {
-                    id.emit_span_lint(
-                        sess,
-                        UNEXPECTED_CFGS,
-                        *span,
-                        BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
-                    );
+            if let ShouldEmit::ErrorsAndLints = emit_lints {
+                match sess.psess.check_config.expecteds.get(name) {
+                    Some(ExpectedValues::Some(values))
+                        if !values.contains(&value.map(|(v, _)| v)) =>
+                    {
+                        id.emit_span_lint(
+                            sess,
+                            UNEXPECTED_CFGS,
+                            *span,
+                            BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
+                        );
+                    }
+                    None if sess.psess.check_config.exhaustive_names => {
+                        id.emit_span_lint(
+                            sess,
+                            UNEXPECTED_CFGS,
+                            *span,
+                            BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
+                        );
+                    }
+                    _ => { /* not unexpected */ }
                 }
-                None if sess.psess.check_config.exhaustive_names => {
-                    id.emit_span_lint(
-                        sess,
-                        UNEXPECTED_CFGS,
-                        *span,
-                        BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
-                    );
-                }
-                _ => { /* not unexpected */ }
             }
 
             if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index ee5a44a75f4..1449680e35b 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -226,7 +226,7 @@ impl Stage for Early {
         sess: &'sess Session,
         diag: impl for<'x> Diagnostic<'x>,
     ) -> ErrorGuaranteed {
-        if self.emit_errors {
+        if self.emit_errors.should_emit() {
             sess.dcx().emit_err(diag)
         } else {
             sess.dcx().create_err(diag).delay_as_bug()
@@ -257,7 +257,7 @@ pub struct Early {
     /// Whether to emit errors or delay them as a bug
     /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
     /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
-    pub emit_errors: bool,
+    pub emit_errors: ShouldEmit,
 }
 /// used when parsing attributes during ast lowering
 pub struct Late;
@@ -558,6 +558,25 @@ pub enum OmitDoc {
     Skip,
 }
 
+#[derive(Copy, Clone)]
+pub enum ShouldEmit {
+    /// The operation will emit errors and lints.
+    /// This is usually what you need.
+    ErrorsAndLints,
+    /// The operation will emit *not* errors and lints.
+    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
+    Nothing,
+}
+
+impl ShouldEmit {
+    pub fn should_emit(&self) -> bool {
+        match self {
+            ShouldEmit::ErrorsAndLints => true,
+            ShouldEmit::Nothing => false,
+        }
+    }
+}
+
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
 pub struct AttributeParser<'sess, S: Stage = Late> {
@@ -600,7 +619,7 @@ impl<'sess> AttributeParser<'sess, Early> {
             tools: Vec::new(),
             parse_only: Some(sym),
             sess,
-            stage: Early { emit_errors: false },
+            stage: Early { emit_errors: ShouldEmit::Nothing },
         };
         let mut parsed = p.parse_attribute_list(
             attrs,
@@ -623,7 +642,7 @@ impl<'sess> AttributeParser<'sess, Early> {
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
-        emit_errors: bool,
+        emit_errors: ShouldEmit,
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
         template: &AttributeTemplate,
     ) -> T {
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 2102a26108b..dc54cb6b840 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -95,7 +95,7 @@ pub use attributes::cfg_old::*;
 pub use attributes::util::{
     find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
 };
-pub use context::{AttributeParser, Early, Late, OmitDoc};
+pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit};
 pub use lints::emit_attribute_lint;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 22d29eda913..e24a355891d 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -4,8 +4,9 @@
 
 use std::assert_matches::assert_matches;
 
-use rustc_abi::{FieldIdx, Size};
+use rustc_abi::{FieldIdx, HasDataLayout, Size};
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
+use rustc_middle::mir::interpret::{read_target_uint, write_target_uint};
 use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
 }
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Generates a value of `TypeId` for `ty` in-place.
-    pub(crate) fn write_type_id(
+    fn write_type_id(
         &mut self,
         ty: Ty<'tcx>,
         dest: &PlaceTy<'tcx, M::Provenance>,
@@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Here we rely on `TypeId` being a newtype around an array of pointers, so we
         // first project to its only field and then the array elements.
         let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
-        let first = self.project_field(dest, FieldIdx::ZERO)?;
-        let mut elem_iter = self.project_array_fields(&first)?;
+        let arr = self.project_field(dest, FieldIdx::ZERO)?;
+        let mut elem_iter = self.project_array_fields(&arr)?;
         while let Some((_, elem)) = elem_iter.next(self)? {
             // Decorate this part of the hash with provenance; leave the integer part unchanged.
             let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?;
@@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         interp_ok(())
     }
 
+    /// Read a value of type `TypeId`, returning the type it represents.
+    pub(crate) fn read_type_id(
+        &self,
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Ty<'tcx>> {
+        // `TypeId` is a newtype around an array of pointers. All pointers must have the same
+        // provenance, and that provenance represents the type.
+        let ptr_size = self.pointer_size().bytes_usize();
+        let arr = self.project_field(op, FieldIdx::ZERO)?;
+
+        let mut ty_and_hash = None;
+        let mut elem_iter = self.project_array_fields(&arr)?;
+        while let Some((idx, elem)) = elem_iter.next(self)? {
+            let elem = self.read_pointer(&elem)?;
+            let (elem_ty, elem_hash) = self.get_ptr_type_id(elem)?;
+            // If this is the first element, remember the type and its hash.
+            // If this is not the first element, ensure it is consistent with the previous ones.
+            let full_hash = match ty_and_hash {
+                None => {
+                    let hash = self.tcx.type_id_hash(elem_ty).as_u128();
+                    let mut hash_bytes = [0u8; 16];
+                    write_target_uint(self.data_layout().endian, &mut hash_bytes, hash).unwrap();
+                    ty_and_hash = Some((elem_ty, hash_bytes));
+                    hash_bytes
+                }
+                Some((ty, hash_bytes)) => {
+                    if ty != elem_ty {
+                        throw_ub_format!(
+                            "invalid `TypeId` value: not all bytes carry the same type id metadata"
+                        );
+                    }
+                    hash_bytes
+                }
+            };
+            // Ensure the elem_hash matches the corresponding part of the full hash.
+            let hash_frag = &full_hash[(idx as usize) * ptr_size..][..ptr_size];
+            if read_target_uint(self.data_layout().endian, hash_frag).unwrap() != elem_hash.into() {
+                throw_ub_format!(
+                    "invalid `TypeId` value: the hash does not match the type id metadata"
+                );
+            }
+        }
+
+        interp_ok(ty_and_hash.unwrap().0)
+    }
+
     /// Returns `true` if emulation happened.
     /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
     /// intrinsic handling.
@@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_type_id(tp_ty, dest)?;
             }
             sym::type_id_eq => {
-                // Both operands are `TypeId`, which is a newtype around an array of pointers.
-                // Project until we have the array elements.
-                let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?;
-                let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?;
-
-                let mut a_fields = self.project_array_fields(&a_fields)?;
-                let mut b_fields = self.project_array_fields(&b_fields)?;
-
-                let mut provenance_a = None;
-                let mut provenance_b = None;
-                let mut provenance_matches = true;
-
-                while let Some((i, a)) = a_fields.next(self)? {
-                    let (_, b) = b_fields.next(self)?.unwrap();
-
-                    let a = self.deref_pointer(&a)?;
-                    let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
-
-                    let b = self.deref_pointer(&b)?;
-                    let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
-
-                    if *provenance_a.get_or_insert(a) != a {
-                        throw_ub_format!(
-                            "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
-                        )
-                    }
-                    if *provenance_b.get_or_insert(b) != b {
-                        throw_ub_format!(
-                            "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
-                        )
-                    }
-                    provenance_matches &= a == b;
-
-                    if offset_a != offset_b && provenance_matches {
-                        throw_ub_format!(
-                            "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents"
-                        )
-                    }
-                }
-
-                self.write_scalar(Scalar::from_bool(provenance_matches), dest)?;
+                let a_ty = self.read_type_id(&args[0])?;
+                let b_ty = self.read_type_id(&args[1])?;
+                self.write_scalar(Scalar::from_bool(a_ty == b_ty), dest)?;
             }
             sym::variant_count => {
                 let tp_ty = instance.args.type_at(0);
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 5f9f43a320b..b2cbbc21430 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -997,12 +997,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn get_ptr_type_id(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
-    ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> {
+    ) -> InterpResult<'tcx, (Ty<'tcx>, u64)> {
         let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?;
         let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else {
-            throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id")
+            throw_ub_format!("invalid `TypeId` value: not all bytes carry type id metadata")
         };
-        interp_ok((ty, offset))
+        interp_ok((ty, offset.bytes()))
     }
 
     pub fn get_ptr_fn(
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index b6ba069526c..2e99bb4209f 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_mir_dataflow::impls::always_storage_live_locals;
 use rustc_span::Span;
+use tracing::field::Empty;
 use tracing::{info_span, instrument, trace};
 
 use super::{
@@ -396,7 +397,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Finish things up.
         M::after_stack_push(self)?;
         self.frame_mut().loc = Left(mir::Location::START);
-        let span = info_span!("frame", "{}", instance);
+        // `tracing_separate_thread` is used to instruct the chrome_tracing [tracing::Layer] in Miri
+        // to put the "frame" span on a separate trace thread/line than other spans, to make the
+        // visualization in https://ui.perfetto.dev easier to interpret. It is set to a value of
+        // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it.
+        let span = info_span!("frame", tracing_separate_thread = Empty, "{}", instance);
         self.frame_mut().tracing_span.enter(span);
 
         interp_ok(())
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index ce3006c2604..1928cfd9048 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1062,7 +1062,7 @@ pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
     fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId;
 
-    fn resolve_dollar_crates(&mut self);
+    fn resolve_dollar_crates(&self);
     fn visit_ast_fragment_with_placeholders(
         &mut self,
         expn_id: LocalExpnId,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 6922ddfd6bd..83a8d601afe 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -12,7 +12,7 @@ use rustc_ast::{
 };
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr,
+    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr,
 };
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
@@ -167,7 +167,9 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
         .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
         .take_while(|attr| {
             !is_cfg(attr)
-                || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool()
+                || strip_unconfigured
+                    .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing)
+                    .as_bool()
         })
         .collect()
 }
@@ -401,10 +403,18 @@ impl<'a> StripUnconfigured<'a> {
 
     /// Determines if a node with the given attributes should be included in this configuration.
     fn in_cfg(&self, attrs: &[Attribute]) -> bool {
-        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool())
+        attrs.iter().all(|attr| {
+            !is_cfg(attr)
+                || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool()
+        })
     }
 
-    pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult {
+    pub(crate) fn cfg_true(
+        &self,
+        attr: &Attribute,
+        node: NodeId,
+        emit_errors: ShouldEmit,
+    ) -> EvalConfigResult {
         // We need to run this to do basic validation of the attribute, such as that lits are valid, etc
         // FIXME(jdonszelmann) this should not be necessary in the future
         match validate_attr::parse_meta(&self.sess.psess, attr) {
@@ -428,7 +438,7 @@ impl<'a> StripUnconfigured<'a> {
             attr.span,
             node,
             self.features,
-            true,
+            emit_errors,
             parse_cfg_attr,
             &CFG_TEMPLATE,
         ) else {
@@ -436,7 +446,7 @@ impl<'a> StripUnconfigured<'a> {
             return EvalConfigResult::True;
         };
 
-        eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features)
+        eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors)
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f99060e9a21..79ec79a2fdf 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -13,7 +13,7 @@ use rustc_ast::{
     MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
 };
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::EvalConfigResult;
+use rustc_attr_parsing::{EvalConfigResult, ShouldEmit};
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_errors::PResult;
 use rustc_feature::Features;
@@ -2171,7 +2171,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         attr: ast::Attribute,
         pos: usize,
     ) -> EvalConfigResult {
-        let res = self.cfg().cfg_true(&attr, node.node_id());
+        let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints);
         if res.as_bool() {
             // A trace attribute left in AST in place of the original `cfg` attribute.
             // It can later be used by lints or other diagnostics.
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 69d86329e7a..1a1cfc9fa6f 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -509,27 +509,50 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi
 
 lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
 
-lint_mismatched_lifetime_syntaxes =
-    lifetime flowing from input to output with different syntax can be confusing
-    .label_mismatched_lifetime_syntaxes_inputs =
-        {$n_inputs ->
-            [one] this lifetime flows
-            *[other] these lifetimes flow
-        } to the output
-    .label_mismatched_lifetime_syntaxes_outputs =
-        the {$n_outputs ->
-            [one] lifetime gets
-            *[other] lifetimes get
-        } resolved as `{$lifetime_name}`
+lint_mismatched_lifetime_syntaxes_eliding_while_named =
+    eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_help =
+    the same lifetime is referred to in inconsistent ways, making the signature confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named =
+    hiding or eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_elided =
+    hiding a lifetime that's elided elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_named =
+    hiding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_input_elided =
+    the lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_input_hidden =
+    the lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_input_named =
+    the lifetime is named here
+
+lint_mismatched_lifetime_syntaxes_output_elided =
+    the same lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_output_hidden =
+    the same lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_output_named =
+    the same lifetime is named here
 
 lint_mismatched_lifetime_syntaxes_suggestion_explicit =
-    one option is to consistently use `{$lifetime_name}`
+    consistently use `{$lifetime_name}`
 
 lint_mismatched_lifetime_syntaxes_suggestion_implicit =
-    one option is to consistently remove the lifetime
+    remove the lifetime name from references
 
 lint_mismatched_lifetime_syntaxes_suggestion_mixed =
-    one option is to remove the lifetime for references and use the anonymous lifetime for paths
+    remove the lifetime name from references and use `'_` for type paths
+
+lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths =
+    use `'_` for type paths
 
 lint_missing_unsafe_on_extern = extern blocks should be unsafe
     .suggestion = needs `unsafe` before the extern keyword
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 419124d5144..f06757b3c23 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,7 +55,7 @@ mod invalid_from_utf8;
 mod late;
 mod let_underscore;
 mod levels;
-mod lifetime_syntax;
+pub mod lifetime_syntax;
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 5465968e984..2a5a34cdc6e 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
     }
 }
 
-fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
-    // Categorize lifetimes into source/syntax buckets.
-    let mut n_hidden = 0;
-    let mut n_elided = 0;
-    let mut n_named = 0;
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum LifetimeSyntaxCategory {
+    Hidden,
+    Elided,
+    Named,
+}
 
-    for info in input_info.iter().chain(output_info) {
+impl LifetimeSyntaxCategory {
+    fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> {
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
-
         match syntax_source {
-            // Ignore any other kind of lifetime.
-            (_, Other) => continue,
-
             // E.g. `&T`.
-            (Implicit, Reference | OutlivesBound | PreciseCapturing) |
+            (Implicit, Reference) |
             // E.g. `&'_ T`.
-            (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitAnonymous, Reference) |
             // E.g. `ContainsLifetime<'_>`.
-            (ExplicitAnonymous, Path { .. }) => n_elided += 1,
+            (ExplicitAnonymous, Path { .. }) |
+            // E.g. `+ '_`, `+ use<'_>`.
+            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Elided)
+            }
 
             // E.g. `ContainsLifetime`.
-            (Implicit, Path { .. }) => n_hidden += 1,
+            (Implicit, Path { .. }) => {
+                Some(Self::Hidden)
+            }
 
             // E.g. `&'a T`.
-            (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitBound, Reference) |
             // E.g. `ContainsLifetime<'a>`.
-            (ExplicitBound, Path { .. }) => n_named += 1,
-        };
+            (ExplicitBound, Path { .. }) |
+            // E.g. `+ 'a`, `+ use<'a>`.
+            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Named)
+            }
+
+            (Implicit, OutlivesBound | PreciseCapturing) |
+            (_, Other) => {
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug, Default)]
+pub struct LifetimeSyntaxCategories<T> {
+    pub hidden: T,
+    pub elided: T,
+    pub named: T,
+}
+
+impl<T> LifetimeSyntaxCategories<T> {
+    fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T {
+        use LifetimeSyntaxCategory::*;
+
+        match category {
+            Elided => &mut self.elided,
+            Hidden => &mut self.hidden,
+            Named => &mut self.named,
+        }
+    }
+}
+
+impl<T> LifetimeSyntaxCategories<Vec<T>> {
+    pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
+        LifetimeSyntaxCategories {
+            hidden: self.hidden.len(),
+            elided: self.elided.len(),
+            named: self.named.len(),
+        }
+    }
+
+    pub fn flatten(&self) -> impl Iterator<Item = &T> {
+        let Self { hidden, elided, named } = self;
+        [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten()
+    }
+}
+
+impl std::ops::Add for LifetimeSyntaxCategories<usize> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Self {
+            hidden: self.hidden + rhs.hidden,
+            elided: self.elided + rhs.elided,
+            named: self.named + rhs.named,
+        }
+    }
+}
+
+fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
+    let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default();
+
+    for info in input_info.iter().chain(output_info) {
+        if let Some(category) = info.lifetime_syntax_category() {
+            *syntax_counts.select(category) += 1;
+        }
     }
 
-    let syntax_counts = (n_hidden, n_elided, n_named);
     tracing::debug!(?syntax_counts);
 
-    matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _))
+    matches!(
+        syntax_counts,
+        LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ }
+    )
 }
 
 fn emit_mismatch_diagnostic<'tcx>(
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
+        let syntax_source = info.syntax_source();
 
         if let (_, Other) = syntax_source {
             // Ignore any other kind of lifetime.
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
             // E.g. `&'_ T`.
             (ExplicitAnonymous, Reference) => {
                 suggest_change_to_implicit.push(info);
-                suggest_change_to_mixed_implicit.push(info);
                 suggest_change_to_explicit_bound.push(info);
             }
 
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
         }
     }
 
+    let categorize = |infos: &[Info<'_>]| {
+        let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
+        for info in infos {
+            if let Some(category) = info.lifetime_syntax_category() {
+                categories.select(category).push(info.reporting_span());
+            }
+        }
+        categories
+    };
+
+    let inputs = categorize(input_info);
+    let outputs = categorize(output_info);
+
     let make_implicit_suggestions =
         |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
 
-    let inputs = input_info.iter().map(|info| info.reporting_span()).collect();
-    let outputs = output_info.iter().map(|info| info.reporting_span()).collect();
-
     let explicit_bound_suggestion = bound_lifetime.map(|info| {
         build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
     });
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
         ?explicit_anonymous_suggestion,
     );
 
-    let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned();
-
     // We can produce a number of suggestions which may overwhelm
     // the user. Instead, we order the suggestions based on Rust
     // idioms. The "best" choice is shown to the user and the
@@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>(
 
     cx.emit_span_lint(
         MISMATCHED_LIFETIME_SYNTAXES,
-        Vec::clone(&inputs),
-        lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions },
+        inputs.flatten().copied().collect::<Vec<_>>(),
+        lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions },
     );
 }
 
@@ -422,12 +501,12 @@ fn build_mismatch_suggestion(
     lifetime_name: &str,
     infos: &[&Info<'_>],
 ) -> lints::MismatchedLifetimeSyntaxesSuggestion {
-    let lifetime_name_sugg = lifetime_name.to_owned();
+    let lifetime_name = lifetime_name.to_owned();
 
     let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
 
     lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
-        lifetime_name_sugg,
+        lifetime_name,
         suggestions,
         tool_only: false,
     }
@@ -441,6 +520,14 @@ struct Info<'tcx> {
 }
 
 impl<'tcx> Info<'tcx> {
+    fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) {
+        (self.lifetime.syntax, self.lifetime.source)
+    }
+
+    fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> {
+        LifetimeSyntaxCategory::new(self.syntax_source())
+    }
+
     fn lifetime_name(&self) -> &str {
         self.lifetime.ident.as_str()
     }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index b1afbf298e3..fd8d0f832aa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -21,6 +21,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
 
 use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
 use crate::errors::{OverruledAttributeSub, RequestedLevel};
+use crate::lifetime_syntax::LifetimeSyntaxCategories;
 use crate::{LateContext, fluent_generated as fluent};
 
 // array_into_iter.rs
@@ -3216,30 +3217,59 @@ pub(crate) struct ReservedMultihash {
 
 #[derive(Debug)]
 pub(crate) struct MismatchedLifetimeSyntaxes {
-    pub lifetime_name: String,
-    pub inputs: Vec<Span>,
-    pub outputs: Vec<Span>,
+    pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
+    pub outputs: LifetimeSyntaxCategories<Vec<Span>>,
 
     pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
 }
 
 impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
     fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
-        diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes);
+        let counts = self.inputs.len() + self.outputs.len();
+        let message = match counts {
+            LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => {
+                panic!("No lifetime mismatch detected")
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named
+            }
 
-        diag.arg("lifetime_name", self.lifetime_name);
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named
+            }
+        };
+        diag.primary_message(message);
 
-        diag.arg("n_inputs", self.inputs.len());
-        for input in self.inputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs);
-            diag.span_label(input, a);
+        for s in self.inputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden);
+        }
+        for s in self.inputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided);
+        }
+        for s in self.inputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named);
         }
 
-        diag.arg("n_outputs", self.outputs.len());
-        for output in self.outputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs);
-            diag.span_label(output, a);
+        for s in self.outputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden);
+        }
+        for s in self.outputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided);
         }
+        for s in self.outputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named);
+        }
+
+        diag.help(fluent::lint_mismatched_lifetime_syntaxes_help);
 
         let mut suggestions = self.suggestions.into_iter();
         if let Some(s) = suggestions.next() {
@@ -3267,7 +3297,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
     },
 
     Explicit {
-        lifetime_name_sugg: String,
+        lifetime_name: String,
         suggestions: Vec<(Span, String)>,
         tool_only: bool,
     },
@@ -3307,6 +3337,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
             }
 
             Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
+                let message = if implicit_suggestions.is_empty() {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
+                } else {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed
+                };
+
                 let implicit_suggestions =
                     implicit_suggestions.into_iter().map(|s| (s, String::new()));
 
@@ -3314,19 +3350,19 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
                     implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
 
                 diag.multipart_suggestion_with_style(
-                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
+                    message,
                     suggestions,
                     Applicability::MaybeIncorrect,
                     style(tool_only),
                 );
             }
 
-            Explicit { lifetime_name_sugg, suggestions, tool_only } => {
-                diag.arg("lifetime_name_sugg", lifetime_name_sugg);
+            Explicit { lifetime_name, suggestions, tool_only } => {
+                diag.arg("lifetime_name", lifetime_name);
                 let msg = diag.eagerly_translate(
                     fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
                 );
-                diag.remove_arg("lifetime_name_sugg");
+                diag.remove_arg("lifetime_name");
                 diag.multipart_suggestion_with_style(
                     msg,
                     suggestions,
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index c4a0ae2ce9d..a92012f8329 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index 0666ae29409..d178fcda1fb 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_lexer = { path = "../rustc_lexer" }
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml
index 748fa944e28..762acf9a1eb 100644
--- a/compiler/rustc_proc_macro/Cargo.toml
+++ b/compiler/rustc_proc_macro/Cargo.toml
@@ -15,7 +15,7 @@ test = false
 doctest = false
 
 [dependencies]
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 
 [features]
 rustc-dep-of-std = []
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 5a1be618cee..e56aabfd414 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -85,7 +85,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
     /// but they cannot use def-site hygiene, so the assumption holds
     /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
-    pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> {
+    pub(crate) fn get_nearest_non_block_module(&self, mut def_id: DefId) -> Module<'ra> {
         loop {
             match self.get_module(def_id) {
                 Some(module) => return module,
@@ -94,44 +94,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> {
+    pub(crate) fn expect_module(&self, def_id: DefId) -> Module<'ra> {
         self.get_module(def_id).expect("argument `DefId` is not a module")
     }
 
     /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum,
     /// or trait), then this function returns that module's resolver representation, otherwise it
     /// returns `None`.
-    pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'ra>> {
-        if let module @ Some(..) = self.module_map.get(&def_id) {
-            return module.copied();
-        }
+    pub(crate) fn get_module(&self, def_id: DefId) -> Option<Module<'ra>> {
+        match def_id.as_local() {
+            Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(),
+            None => {
+                if let module @ Some(..) = self.extern_module_map.borrow().get(&def_id) {
+                    return module.copied();
+                }
 
-        if !def_id.is_local() {
-            // Query `def_kind` is not used because query system overhead is too expensive here.
-            let def_kind = self.cstore().def_kind_untracked(def_id);
-            if def_kind.is_module_like() {
-                let parent = self
-                    .tcx
-                    .opt_parent(def_id)
-                    .map(|parent_id| self.get_nearest_non_block_module(parent_id));
-                // Query `expn_that_defined` is not used because
-                // hashing spans in its result is expensive.
-                let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
-                return Some(self.new_module(
-                    parent,
-                    ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
-                    expn_id,
-                    self.def_span(def_id),
-                    // FIXME: Account for `#[no_implicit_prelude]` attributes.
-                    parent.is_some_and(|module| module.no_implicit_prelude),
-                ));
+                // Query `def_kind` is not used because query system overhead is too expensive here.
+                let def_kind = self.cstore().def_kind_untracked(def_id);
+                if def_kind.is_module_like() {
+                    let parent = self
+                        .tcx
+                        .opt_parent(def_id)
+                        .map(|parent_id| self.get_nearest_non_block_module(parent_id));
+                    // Query `expn_that_defined` is not used because
+                    // hashing spans in its result is expensive.
+                    let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
+                    return Some(self.new_extern_module(
+                        parent,
+                        ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
+                        expn_id,
+                        self.def_span(def_id),
+                        // FIXME: Account for `#[no_implicit_prelude]` attributes.
+                        parent.is_some_and(|module| module.no_implicit_prelude),
+                    ));
+                }
+
+                None
             }
         }
-
-        None
     }
 
-    pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> {
+    pub(crate) fn expn_def_scope(&self, expn_id: ExpnId) -> Module<'ra> {
         match expn_id.expn_data().macro_def_id {
             Some(def_id) => self.macro_def_scope(def_id),
             None => expn_id
@@ -141,7 +144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> {
+    pub(crate) fn macro_def_scope(&self, def_id: DefId) -> Module<'ra> {
         if let Some(id) = def_id.as_local() {
             self.local_macro_def_scopes[&id]
         } else {
@@ -403,7 +406,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         self.r.field_visibility_spans.insert(def_id, field_vis);
     }
 
-    fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
+    fn block_needs_anonymous_module(&self, block: &Block) -> bool {
         // If any statements are items, we need to create an anonymous module
         block
             .stmts
@@ -758,7 +761,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
                     self.r.mods_with_parse_errors.insert(def_id);
                 }
-                self.parent_scope.module = self.r.new_module(
+                self.parent_scope.module = self.r.new_local_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
@@ -790,7 +793,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => {
                 self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
 
-                self.parent_scope.module = self.r.new_module(
+                self.parent_scope.module = self.r.new_local_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
@@ -986,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let parent = self.parent_scope.module;
         let expansion = self.parent_scope.expansion;
         if self.block_needs_anonymous_module(block) {
-            let module = self.r.new_module(
+            let module = self.r.new_local_module(
                 Some(parent),
                 ModuleKind::Block,
                 expansion.to_expn_id(),
@@ -1118,7 +1121,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
     }
 
     /// Returns `true` if this attribute list contains `macro_use`.
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+    fn contains_macro_use(&self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
             if attr.has_name(sym::macro_escape) {
                 let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 781e2ce9704..7d51fef28d3 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -2,7 +2,7 @@ use std::mem;
 
 use rustc_ast::visit::FnKind;
 use rustc_ast::*;
-use rustc_attr_parsing::{AttributeParser, Early, OmitDoc};
+use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit};
 use rustc_expand::expand::AstFragment;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
@@ -132,7 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
                     Vec::new(),
-                    Early { emit_errors: false },
+                    Early { emit_errors: ShouldEmit::Nothing },
                 );
                 let attrs = parser.parse_attribute_list(
                     &i.attrs,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 5a162b5d2b9..f6f45adabe9 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2149,7 +2149,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     pub(crate) fn find_similarly_named_module_or_crate(
-        &mut self,
+        &self,
         ident: Symbol,
         current_module: Module<'ra>,
     ) -> Option<Symbol> {
@@ -2158,7 +2158,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             .keys()
             .map(|ident| ident.name)
             .chain(
-                self.module_map
+                self.local_module_map
+                    .iter()
+                    .filter(|(_, module)| {
+                        current_module.is_ancestor_of(**module) && current_module != **module
+                    })
+                    .flat_map(|(_, module)| module.kind.name()),
+            )
+            .chain(
+                self.extern_module_map
+                    .borrow()
                     .iter()
                     .filter(|(_, module)| {
                         current_module.is_ancestor_of(**module) && current_module != **module
@@ -2434,7 +2443,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     fn undeclared_module_suggest_declare(
-        &mut self,
+        &self,
         ident: Ident,
         path: std::path::PathBuf,
     ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
@@ -2449,7 +2458,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         ))
     }
 
-    fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
+    fn undeclared_module_exists(&self, ident: Ident) -> Option<std::path::PathBuf> {
         let map = self.tcx.sess.source_map();
 
         let src = map.span_to_filename(ident.span).into_local_path()?;
@@ -2808,24 +2817,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     return cached;
                 }
                 visited.insert(parent_module, false);
-                let res = r.module_map.get(&parent_module).is_some_and(|m| {
-                    for importer in m.glob_importers.borrow().iter() {
-                        if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
+                let m = r.expect_module(parent_module);
+                let mut res = false;
+                for importer in m.glob_importers.borrow().iter() {
+                    if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() {
+                        if next_parent_module == module
+                            || comes_from_same_module_for_glob(
+                                r,
+                                next_parent_module,
+                                module,
+                                visited,
+                            )
                         {
-                            if next_parent_module == module
-                                || comes_from_same_module_for_glob(
-                                    r,
-                                    next_parent_module,
-                                    module,
-                                    visited,
-                                )
-                            {
-                                return true;
-                            }
+                            res = true;
+                            break;
                         }
                     }
-                    false
-                });
+                }
                 visited.insert(parent_module, res);
                 res
             }
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 5de80de3f8d..34d1e9552fd 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -38,11 +38,11 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
 }
 
 impl Resolver<'_, '_> {
-    fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
+    fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId {
         self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
     }
 
-    fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility {
+    fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility {
         let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
         Visibility::Restricted(
             import
@@ -52,7 +52,7 @@ impl Resolver<'_, '_> {
         )
     }
 
-    fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility {
+    fn private_vis_def(&self, def_id: LocalDefId) -> Visibility {
         // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
         let normal_mod_id = self.nearest_normal_mod(def_id);
         if normal_mod_id == def_id {
@@ -113,8 +113,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
     /// Update effective visibilities of bindings in the given module,
     /// including their whole reexport chains.
     fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
-        assert!(self.r.module_map.contains_key(&module_id.to_def_id()));
-        let module = self.r.get_module(module_id.to_def_id()).unwrap();
+        let module = self.r.expect_module(module_id.to_def_id());
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 84d66c15f00..34941398a2b 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -219,7 +219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     fn hygienic_lexical_parent(
-        &mut self,
+        &self,
         module: Module<'ra>,
         ctxt: &mut SyntaxContext,
         derive_fallback_lint_id: Option<NodeId>,
@@ -841,7 +841,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
-                        return Ok(self.module_self_bindings[&module]);
+                        return Ok(module.self_binding.unwrap());
                     } else if ident.name == kw::Super || ident.name == kw::SelfLower {
                         // FIXME: Implement these with renaming requirements so that e.g.
                         // `use super;` doesn't work, but `use super as name;` does.
@@ -885,7 +885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             );
         }
 
-        let check_usable = |this: &mut Self, binding: NameBinding<'ra>| {
+        let check_usable = |this: &Self, binding: NameBinding<'ra>| {
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
         };
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index c3e39d2071b..0a4c25b0eb0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -456,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         f: F,
     ) -> T
     where
-        F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
+        F: FnOnce(&Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3ef98100d09..753b9365cd8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2491,7 +2491,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
-    fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
+    fn resolve_label(&self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
         let mut suggestion = None;
 
         for i in (0..self.label_ribs.len()).rev() {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index a4601cb44eb..ee462d90764 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -926,7 +926,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     continue;
                 };
                 if let Res::Def(DefKind::Mod, module) = res.expect_full_res()
-                    && let Some(module) = self.r.get_module(module)
+                    && let module = self.r.expect_module(module)
                     && let item = path[idx + 1].ident
                     && let Some(did) = find_doc_alias_name(self.r, module, item.name)
                 {
@@ -939,7 +939,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_trait_and_bounds(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         res: Option<Res>,
@@ -1140,7 +1140,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     /// Emit special messages for unresolved `Self` and `self`.
     fn suggest_self_ty(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         path: &[Segment],
@@ -1256,7 +1256,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn detect_missing_binding_available_from_pattern(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
@@ -1302,11 +1302,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         }
     }
 
-    fn suggest_at_operator_in_slice_pat_with_range(
-        &mut self,
-        err: &mut Diag<'_>,
-        path: &[Segment],
-    ) {
+    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {
         let Some(pat) = self.diag_metadata.current_pat else { return };
         let (bound, side, range) = match &pat.kind {
             ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),
@@ -1367,7 +1363,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn explain_functions_in_pattern(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         res: Option<Res>,
         source: PathSource<'_, '_, '_>,
@@ -1379,7 +1375,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_changing_type_to_const_param(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         res: Option<Res>,
         source: PathSource<'_, '_, '_>,
@@ -1429,7 +1425,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_pattern_match_with_let(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         span: Span,
@@ -1485,7 +1481,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
-    fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool {
+    fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {
         // Detect that we are actually in a `where` predicate.
         let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
             kind:
@@ -1633,7 +1629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         let ns = source.namespace();
         let is_expected = &|res| source.is_expected(res);
 
-        let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
+        let path_sep = |this: &Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
             const MESSAGE: &str = "use the path separator to refer to an item";
 
             let (lhs_span, rhs_span) = match &expr.kind {
@@ -2531,16 +2527,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     // FIXME: this is not totally accurate, but mostly works
                     suggestion.candidate != following_seg.ident.name
                 }
-                Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
-                    || false,
-                    |module| {
-                        self.r
-                            .resolutions(module)
-                            .borrow()
-                            .iter()
-                            .any(|(key, _)| key.ident.name == following_seg.ident.name)
-                    },
-                ),
+                Res::Def(DefKind::Mod, def_id) => {
+                    let module = self.r.expect_module(def_id);
+                    self.r
+                        .resolutions(module)
+                        .borrow()
+                        .iter()
+                        .any(|(key, _)| key.ident.name == following_seg.ident.name)
+                }
                 _ => true,
             });
         }
@@ -2589,7 +2583,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     // try to give a suggestion for this pattern: `name = blah`, which is common in other languages
     // suggest `let name = blah` to introduce a new binding
-    fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool {
+    fn let_binding_suggestion(&self, err: &mut Diag<'_>, ident_span: Span) -> bool {
         if ident_span.from_expansion() {
             return false;
         }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f904f326296..dae30b77ec1 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -585,6 +585,10 @@ struct ModuleData<'ra> {
     span: Span,
 
     expansion: ExpnId,
+
+    /// Binding for implicitly declared names that come with a module,
+    /// like `self` (not yet used), or `crate`/`$crate` (for root modules).
+    self_binding: Option<NameBinding<'ra>>,
 }
 
 /// All modules are unique and allocated on a same arena,
@@ -613,6 +617,7 @@ impl<'ra> ModuleData<'ra> {
         expansion: ExpnId,
         span: Span,
         no_implicit_prelude: bool,
+        self_binding: Option<NameBinding<'ra>>,
     ) -> Self {
         let is_foreign = match kind {
             ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
@@ -630,6 +635,7 @@ impl<'ra> ModuleData<'ra> {
             traits: RefCell::new(None),
             span,
             expansion,
+            self_binding,
         }
     }
 }
@@ -1075,7 +1081,10 @@ pub struct Resolver<'ra, 'tcx> {
     /// some AST passes can generate identifiers that only resolve to local or
     /// lang items.
     empty_module: Module<'ra>,
-    module_map: FxIndexMap<DefId, Module<'ra>>,
+    /// Eagerly populated map of all local non-block modules.
+    local_module_map: FxIndexMap<LocalDefId, Module<'ra>>,
+    /// Lazily populated cache of modules loaded from external crates.
+    extern_module_map: RefCell<FxIndexMap<DefId, Module<'ra>>>,
     binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>,
 
     underscore_disambiguator: u32,
@@ -1101,17 +1110,14 @@ pub struct Resolver<'ra, 'tcx> {
     builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>,
     builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'ra>>,
     registered_tool_bindings: FxHashMap<Ident, NameBinding<'ra>>,
-    /// Binding for implicitly declared names that come with a module,
-    /// like `self` (not yet used), or `crate`/`$crate` (for root modules).
-    module_self_bindings: FxHashMap<Module<'ra>, NameBinding<'ra>>,
-
     used_extern_options: FxHashSet<Symbol>,
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>,
     registered_tools: &'tcx RegisteredTools,
     macro_use_prelude: FxIndexMap<Symbol, NameBinding<'ra>>,
+    /// Eagerly populated map of all local macro definitions.
     local_macro_map: FxHashMap<LocalDefId, &'ra MacroData>,
-    /// Lazily populated cache of macros loaded from external crates.
+    /// Lazily populated cache of macro definitions loaded from external crates.
     extern_macro_map: RefCell<FxHashMap<DefId, &'ra MacroData>>,
     dummy_ext_bang: Arc<SyntaxExtension>,
     dummy_ext_derive: Arc<SyntaxExtension>,
@@ -1263,26 +1269,25 @@ impl<'ra> ResolverArenas<'ra> {
         expn_id: ExpnId,
         span: Span,
         no_implicit_prelude: bool,
-        module_map: &mut FxIndexMap<DefId, Module<'ra>>,
-        module_self_bindings: &mut FxHashMap<Module<'ra>, NameBinding<'ra>>,
     ) -> Module<'ra> {
+        let (def_id, self_binding) = match kind {
+            ModuleKind::Def(def_kind, def_id, _) => (
+                Some(def_id),
+                Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)),
+            ),
+            ModuleKind::Block => (None, None),
+        };
         let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
             parent,
             kind,
             expn_id,
             span,
             no_implicit_prelude,
+            self_binding,
         ))));
-        let def_id = module.opt_def_id();
         if def_id.is_none_or(|def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
-        if let Some(def_id) = def_id {
-            module_map.insert(def_id, module);
-            let res = module.res().unwrap();
-            let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT);
-            module_self_bindings.insert(module, binding);
-        }
         module
     }
     fn local_modules(&'ra self) -> std::cell::Ref<'ra, Vec<Module<'ra>>> {
@@ -1423,25 +1428,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         arenas: &'ra ResolverArenas<'ra>,
     ) -> Resolver<'ra, 'tcx> {
         let root_def_id = CRATE_DEF_ID.to_def_id();
-        let mut module_map = FxIndexMap::default();
-        let mut module_self_bindings = FxHashMap::default();
+        let mut local_module_map = FxIndexMap::default();
         let graph_root = arenas.new_module(
             None,
             ModuleKind::Def(DefKind::Mod, root_def_id, None),
             ExpnId::root(),
             crate_span,
             attr::contains_name(attrs, sym::no_implicit_prelude),
-            &mut module_map,
-            &mut module_self_bindings,
         );
+        local_module_map.insert(CRATE_DEF_ID, graph_root);
         let empty_module = arenas.new_module(
             None,
             ModuleKind::Def(DefKind::Mod, root_def_id, None),
             ExpnId::root(),
             DUMMY_SP,
             true,
-            &mut Default::default(),
-            &mut Default::default(),
         );
 
         let mut node_id_to_def_id = NodeMap::default();
@@ -1502,7 +1503,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
             empty_module,
-            module_map,
+            local_module_map,
+            extern_module_map: Default::default(),
             block_map: Default::default(),
             binding_parent_modules: FxHashMap::default(),
             ast_transform_scopes: FxHashMap::default(),
@@ -1544,8 +1546,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     (*ident, binding)
                 })
                 .collect(),
-            module_self_bindings,
-
             used_extern_options: Default::default(),
             macro_names: FxHashSet::default(),
             builtin_macros: Default::default(),
@@ -1608,7 +1608,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         resolver
     }
 
-    fn new_module(
+    fn new_local_module(
         &mut self,
         parent: Option<Module<'ra>>,
         kind: ModuleKind,
@@ -1616,17 +1616,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         span: Span,
         no_implicit_prelude: bool,
     ) -> Module<'ra> {
-        let module_map = &mut self.module_map;
-        let module_self_bindings = &mut self.module_self_bindings;
-        self.arenas.new_module(
-            parent,
-            kind,
-            expn_id,
-            span,
-            no_implicit_prelude,
-            module_map,
-            module_self_bindings,
-        )
+        let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
+        if let Some(def_id) = module.opt_def_id() {
+            self.local_module_map.insert(def_id.expect_local(), module);
+        }
+        module
+    }
+
+    fn new_extern_module(
+        &self,
+        parent: Option<Module<'ra>>,
+        kind: ModuleKind,
+        expn_id: ExpnId,
+        span: Span,
+        no_implicit_prelude: bool,
+    ) -> Module<'ra> {
+        let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
+        self.extern_module_map.borrow_mut().insert(module.def_id(), module);
+        module
     }
 
     fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData {
@@ -2012,7 +2019,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> {
+    fn resolve_crate_root(&self, ident: Ident) -> Module<'ra> {
         debug!("resolve_crate_root({:?})", ident);
         let mut ctxt = ident.span.ctxt();
         let mark = if ident.name == kw::DollarCrate {
@@ -2085,7 +2092,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         module
     }
 
-    fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> {
+    fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> {
         let mut module = self.expect_module(module.nearest_parent_mod());
         while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
             let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark()));
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index c17d74659db..77ef7f56c09 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -170,7 +170,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
         self.invocation_parents[&id].parent_def
     }
 
-    fn resolve_dollar_crates(&mut self) {
+    fn resolve_dollar_crates(&self) {
         hygiene::update_dollar_crate_names(|ctxt| {
             let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
             match self.resolve_crate_root(ident).kind {
@@ -835,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
-        let check_consistency = |this: &mut Self,
+        let check_consistency = |this: &Self,
                                  path: &[Segment],
                                  span,
                                  kind: MacroKind,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index bd1d29826e6..8c138c7e931 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -22,6 +22,7 @@ use rustc_hir::{
     expr_needs_parens, is_range_literal,
 };
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
+use rustc_middle::middle::privacy::Level;
 use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::{
@@ -2870,11 +2871,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         ty::ClauseKind::Trait(trait_pred) => {
                             let def_id = trait_pred.def_id();
                             let visible_item = if let Some(local) = def_id.as_local() {
-                                // Check for local traits being reachable.
-                                let vis = &tcx.resolutions(()).effective_visibilities;
-                                // Account for non-`pub` traits in the root of the local crate.
-                                let is_locally_reachable = tcx.parent(def_id).is_crate_root();
-                                vis.is_reachable(local) || is_locally_reachable
+                                let ty = trait_pred.self_ty();
+                                // when `TraitA: TraitB` and `S` only impl TraitA,
+                                // we check if `TraitB` can be reachable from `S`
+                                // to determine whether to note `TraitA` is sealed trait.
+                                if let ty::Adt(adt, _) = ty.kind() {
+                                    let visibilities = tcx.effective_visibilities(());
+                                    visibilities.effective_vis(local).is_none_or(|v| {
+                                        v.at_level(Level::Reexported)
+                                            .is_accessible_from(adt.did(), tcx)
+                                    })
+                                } else {
+                                    // FIXME(xizheyin): if the type is not ADT, we should not suggest it
+                                    true
+                                }
                             } else {
                                 // Check for foreign traits being reachable.
                                 tcx.visible_parent_map(()).get(&def_id).is_some()
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 3b313edea6f..4a7263d0ccd 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -223,7 +223,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
             }
             // Skips type aliases, as they are meant to be transparent.
             // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly?
-            ty::Alias(ty::Free, alias_ty) if alias_ty.def_id.is_local() => {
+            ty::Alias(ty::Free, alias_ty) if let Some(def_id) = alias_ty.def_id.as_local() => {
+                if !self.seen.insert(def_id) {
+                    return;
+                }
                 self.tcx
                     .type_of(alias_ty.def_id)
                     .instantiate(self.tcx, alias_ty.args)
@@ -256,16 +259,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                                 return;
                             }
 
-                            let impl_args = alias_ty.args.rebase_onto(
+                            let alias_args = alias_ty.args.rebase_onto(
                                 self.tcx,
                                 impl_trait_ref.def_id,
                                 ty::GenericArgs::identity_for_item(self.tcx, parent),
                             );
 
-                            if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
+                            if self.tcx.check_args_compatible(assoc.def_id, alias_args) {
                                 self.tcx
                                     .type_of(assoc.def_id)
-                                    .instantiate(self.tcx, impl_args)
+                                    .instantiate(self.tcx, alias_args)
                                     .visit_with(self);
                                 return;
                             } else {
diff --git a/library/Cargo.lock b/library/Cargo.lock
index c681c5935df..8b5275e5065 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -271,9 +271,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.4"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
+checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
 dependencies = [
  "rustc-std-workspace-core",
  "rustc-std-workspace-std",
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 881a7a24083..c43f3834630 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -135,16 +135,20 @@ pub enum FromBytesWithNulError {
 }
 
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl Error for FromBytesWithNulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
+impl fmt::Display for FromBytesWithNulError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::InteriorNul { .. } => "data provided contains an interior nul byte",
-            Self::NotNulTerminated => "data provided is not nul terminated",
+            Self::InteriorNul { position } => {
+                write!(f, "data provided contains an interior nul byte at byte position {position}")
+            }
+            Self::NotNulTerminated => write!(f, "data provided is not nul terminated"),
         }
     }
 }
 
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for FromBytesWithNulError {}
+
 /// An error indicating that no nul byte was present.
 ///
 /// A slice used to create a [`CStr`] must contain a nul byte somewhere
@@ -181,18 +185,6 @@ impl Default for &CStr {
     }
 }
 
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl fmt::Display for FromBytesWithNulError {
-    #[allow(deprecated, deprecated_in_future)]
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(self.description())?;
-        if let Self::InteriorNul { position } = self {
-            write!(f, " at byte pos {position}")?;
-        }
-        Ok(())
-    }
-}
-
 impl CStr {
     /// Wraps a raw C string with a safe C string wrapper.
     ///
diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml
index 8ea92088a84..0042a6e8ece 100644
--- a/library/proc_macro/Cargo.toml
+++ b/library/proc_macro/Cargo.toml
@@ -9,7 +9,7 @@ std = { path = "../std" }
 # `core` when resolving doc links. Without this line a different `core` will be
 # loaded from sysroot causing duplicate lang items and other similar errors.
 core = { path = "../core" }
-rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] }
+rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] }
 
 [features]
 default = ["rustc-dep-of-std"]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index ff326342989..162b4fdcc8a 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1471,11 +1471,11 @@ impl Literal {
                 let mut error = None;
                 let mut buf = Vec::with_capacity(symbol.len());
 
-                unescape_c_str(symbol, |_span, c| match c {
+                unescape_c_str(symbol, |_span, res| match res {
                     Ok(MixedUnit::Char(c)) => {
-                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                        buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
                     }
-                    Ok(MixedUnit::HighByte(b)) => buf.push(b),
+                    Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
                     Err(err) => {
                         if err.is_fatal() {
                             error = Some(ConversionErrorKind::FailedToUnescape(err));
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 28958b60fc3..22a75183404 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -697,7 +697,7 @@ impl Config {
         config.change_id = toml.change_id.inner;
 
         let Build {
-            mut description,
+            description,
             build,
             host,
             target,
@@ -749,7 +749,7 @@ impl Config {
             compiletest_diff_tool,
             compiletest_use_stage0_libtest,
             tidy_extra_checks,
-            mut ccache,
+            ccache,
             exclude,
         } = toml.build.unwrap_or_default();
 
@@ -942,7 +942,7 @@ impl Config {
         config.rust_profile_use = flags_rust_profile_use;
         config.rust_profile_generate = flags_rust_profile_generate;
 
-        config.apply_rust_config(toml.rust, flags_warnings, &mut description);
+        config.apply_rust_config(toml.rust, flags_warnings);
 
         config.reproducible_artifacts = flags_reproducible_artifact;
         config.description = description;
@@ -963,7 +963,7 @@ impl Config {
             config.channel = channel;
         }
 
-        config.apply_llvm_config(toml.llvm, &mut ccache);
+        config.apply_llvm_config(toml.llvm);
 
         config.apply_gcc_config(toml.gcc);
 
diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs
index 4774e202bd8..1f0cecd145c 100644
--- a/src/bootstrap/src/core/config/toml/llvm.rs
+++ b/src/bootstrap/src/core/config/toml/llvm.rs
@@ -17,8 +17,6 @@ define_config! {
         tests: Option<bool> = "tests",
         enzyme: Option<bool> = "enzyme",
         plugins: Option<bool> = "plugins",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache
-        ccache: Option<StringOrBool> = "ccache",
         static_libstdcpp: Option<bool> = "static-libstdcpp",
         libzstd: Option<bool> = "libzstd",
         ninja: Option<bool> = "ninja",
@@ -97,7 +95,6 @@ pub fn check_incompatible_options_for_ci_llvm(
         assertions: _,
         tests: _,
         plugins,
-        ccache: _,
         static_libstdcpp: _,
         libzstd,
         ninja: _,
@@ -149,11 +146,7 @@ pub fn check_incompatible_options_for_ci_llvm(
 }
 
 impl Config {
-    pub fn apply_llvm_config(
-        &mut self,
-        toml_llvm: Option<Llvm>,
-        ccache: &mut Option<StringOrBool>,
-    ) {
+    pub fn apply_llvm_config(&mut self, toml_llvm: Option<Llvm>) {
         let mut llvm_tests = None;
         let mut llvm_enzyme = None;
         let mut llvm_offload = None;
@@ -168,7 +161,6 @@ impl Config {
                 tests,
                 enzyme,
                 plugins,
-                ccache: llvm_ccache,
                 static_libstdcpp,
                 libzstd,
                 ninja,
@@ -191,13 +183,7 @@ impl Config {
                 download_ci_llvm,
                 build_config,
             } = llvm;
-            if llvm_ccache.is_some() {
-                eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead.");
-            }
 
-            if ccache.is_none() {
-                *ccache = llvm_ccache;
-            }
             set(&mut self.ninja_in_file, ninja);
             llvm_tests = tests;
             llvm_enzyme = enzyme;
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index 0fae235bb93..307aa52294b 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -36,8 +36,6 @@ define_config! {
         incremental: Option<bool> = "incremental",
         default_linker: Option<String> = "default-linker",
         channel: Option<String> = "channel",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.description
-        description: Option<String> = "description",
         musl_root: Option<String> = "musl-root",
         rpath: Option<bool> = "rpath",
         strip: Option<bool> = "strip",
@@ -320,7 +318,6 @@ pub fn check_incompatible_options_for_ci_rustc(
         jemalloc,
         rpath,
         channel,
-        description,
         default_linker,
         std_features,
 
@@ -388,7 +385,6 @@ pub fn check_incompatible_options_for_ci_rustc(
     err!(current_rust_config.std_features, std_features, "rust");
 
     warn!(current_rust_config.channel, channel, "rust");
-    warn!(current_rust_config.description, description, "rust");
 
     Ok(())
 }
@@ -415,12 +411,7 @@ pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) ->
 }
 
 impl Config {
-    pub fn apply_rust_config(
-        &mut self,
-        toml_rust: Option<Rust>,
-        warnings: Warnings,
-        description: &mut Option<String>,
-    ) {
+    pub fn apply_rust_config(&mut self, toml_rust: Option<Rust>, warnings: Warnings) {
         let mut debug = None;
         let mut rustc_debug_assertions = None;
         let mut std_debug_assertions = None;
@@ -459,7 +450,6 @@ impl Config {
                 randomize_layout,
                 default_linker,
                 channel: _, // already handled above
-                description: rust_description,
                 musl_root,
                 rpath,
                 verbose_tests,
@@ -552,14 +542,6 @@ impl Config {
             set(&mut self.jemalloc, jemalloc);
             set(&mut self.test_compare_mode, test_compare_mode);
             set(&mut self.backtrace, backtrace);
-            if rust_description.is_some() {
-                eprintln!(
-                    "Warning: rust.description is deprecated. Use build.description instead."
-                );
-            }
-            if description.is_none() {
-                *description = rust_description;
-            }
             set(&mut self.rust_dist_src, dist_src);
             set(&mut self.verbose_tests, verbose_tests);
             // in the case "false" is set explicitly, do not overwrite the command line args
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index d888a7863bc..f802640a42d 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -481,4 +481,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.",
     },
+    ChangeInfo {
+        change_id: 143926,
+        severity: ChangeSeverity::Warning,
+        summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.",
+    },
 ];
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 65f3f05d6cb..578641e910d 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -312,7 +312,7 @@ mod issue_9218 {
 
     // Inferred to be `&'a str`, afaik.
     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-        //~^ ERROR: lifetime flowing from input to output with different syntax
+        //~^ ERROR: eliding a lifetime that's named elsewhere is confusing
         todo!()
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 600343754e1..fd9ceddfe11 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -231,18 +231,19 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
 LL |     fn good(v1: &String, v2: &String) {
    |                              ^^^^^^^ help: change this to: `&str`
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> tests/ui/ptr_arg.rs:314:36
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-   |                                    ^^     ^^           ---- the lifetime gets resolved as `'a`
+   |                                    ^^     ^^           ---- the same lifetime is elided here
    |                                    |      |
-   |                                    |      these lifetimes flow to the output
-   |                                    these lifetimes flow to the output
+   |                                    |      the lifetime is named here
+   |                                    the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
    |                                                         ++
diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
index e914a2df2ba..6e1ab84ed18 100644
--- a/src/tools/lint-docs/Cargo.toml
+++ b/src/tools/lint-docs/Cargo.toml
@@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book."
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 serde_json = "1.0.57"
 tempfile = "3.1.0"
 walkdir = "2.3.1"
diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs
index 459acea6f0b..5a96633c99e 100644
--- a/src/tools/miri/src/bin/log/tracing_chrome.rs
+++ b/src/tools/miri/src/bin/log/tracing_chrome.rs
@@ -1,8 +1,18 @@
 // SPDX-License-Identifier: MIT
 // SPDX-FileCopyrightText: Copyright (c) 2020 Thoren Paulson
-//! This file is taken unmodified from the following link, except for file attributes and
-//! `extern crate` at the top.
-//! https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs
+//! This file was initially taken from the following link:
+//! <https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs>
+//!
+//! The precise changes that were made to the original file can be found in git history
+//! (`git log -- path/to/tracing_chrome.rs`), but in summary:
+//! - the file attributes were changed and `extern crate` was added at the top
+//! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate
+//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing
+//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
+//!   ```rust
+//!   tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
+//!   ```
+//!
 //! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it
 //! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would
 //! not be possible to use the [ChromeLayer] in a context that expects a [Layer] from
@@ -79,14 +89,26 @@ where
 }
 
 /// Decides how traces will be recorded.
+/// Also see <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1>
 #[derive(Default)]
 pub enum TraceStyle {
-    /// Traces will be recorded as a group of threads.
+    /// Traces will be recorded as a group of threads, and all spans on the same thread will appear
+    /// on a single trace line in <https://ui.perfetto.dev>.
     /// In this style, spans should be entered and exited on the same thread.
+    ///
+    /// If a tracing span has a field called "tracing_separate_thread", it will be given a separate
+    /// span ID even in this mode, to make it appear on a separate line when viewing the trace in
+    /// <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
+    /// ```rust
+    /// tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
+    /// ```
+    /// [tracing::field::Empty] is used so that other tracing layers (e.g. the logger) will ignore
+    /// the "tracing_separate_thread" argument and not print out anything for it.
     #[default]
     Threaded,
 
-    /// Traces will recorded as a group of asynchronous operations.
+    /// Traces will recorded as a group of asynchronous operations. All spans will be given separate
+    /// span IDs and will appear on separate trace lines in <https://ui.perfetto.dev>.
     Async,
 }
 
@@ -497,31 +519,39 @@ where
         }
     }
 
-    fn get_root_id(span: SpanRef<S>) -> u64 {
-        span.scope()
-            .from_root()
-            .take(1)
-            .next()
-            .unwrap_or(span)
-            .id()
-            .into_u64()
+    fn get_root_id(&self, span: SpanRef<S>) -> Option<u64> {
+        match self.trace_style {
+            TraceStyle::Threaded => {
+                if span.fields().field("tracing_separate_thread").is_some() {
+                    // assign an independent "id" to spans with argument "tracing_separate_thread",
+                    // so they appear a separate trace line in trace visualization tools, see
+                    // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1
+                    Some(span.id().into_u64())
+                } else {
+                    None
+                }
+            },
+            TraceStyle::Async => Some(
+                span.scope()
+                    .from_root()
+                    .take(1)
+                    .next()
+                    .unwrap_or(span)
+                    .id()
+                    .into_u64()
+            ),
+        }
     }
 
     fn enter_span(&self, span: SpanRef<S>, ts: f64) {
         let callsite = self.get_callsite(EventOrSpan::Span(&span));
-        let root_id = match self.trace_style {
-            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
-            _ => None,
-        };
+        let root_id = self.get_root_id(span);
         self.send_message(Message::Enter(ts, callsite, root_id));
     }
 
     fn exit_span(&self, span: SpanRef<S>, ts: f64) {
         let callsite = self.get_callsite(EventOrSpan::Span(&span));
-        let root_id = match self.trace_style {
-            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
-            _ => None,
-        };
+        let root_id = self.get_root_id(span);
         self.send_message(Message::Exit(ts, callsite, root_id));
     }
 
diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs
new file mode 100644
index 00000000000..2097567f322
--- /dev/null
+++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs
@@ -0,0 +1,22 @@
+//! Make sure that line debuginfo of function parameters are correct even if
+//! they are not on the same line. Regression test for
+// <https://github.com/rust-lang/rust/issues/45010>.
+
+//@ compile-flags: -g -Copt-level=0
+
+#[rustfmt::skip] // Having parameters on different lines is crucial for this test.
+pub fn foo(
+    x_parameter_not_in_std: i32,
+    y_parameter_not_in_std: i32,
+) -> i32 {
+    x_parameter_not_in_std + y_parameter_not_in_std
+}
+
+fn main() {
+    foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`)
+}
+
+// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1,
+// CHECK-SAME: line: 9
+// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2,
+// CHECK-SAME: line: 10
diff --git a/tests/ui/check-cfg/cfg-crate-features.rs b/tests/ui/check-cfg/cfg-crate-features.rs
new file mode 100644
index 00000000000..16be8aaeeaa
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-crate-features.rs
@@ -0,0 +1,13 @@
+// https://github.com/rust-lang/rust/issues/143977
+// Check that features are available when an attribute is applied to a crate
+
+#![cfg(version("1.0"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+
+// Using invalid value `does_not_exist`,
+// so we don't accidentally configure out the crate for any certain OS
+#![cfg(not(target(os = "does_not_exist")))]
+//~^ ERROR compact `cfg(target(..))` is experimental and subject to change
+//~| WARN unexpected `cfg` condition value: `does_not_exist`
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr
new file mode 100644
index 00000000000..60a5404c073
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-crate-features.stderr
@@ -0,0 +1,33 @@
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/cfg-crate-features.rs:4:8
+   |
+LL | #![cfg(version("1.0"))]
+   |        ^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: compact `cfg(target(..))` is experimental and subject to change
+  --> $DIR/cfg-crate-features.rs:9:12
+   |
+LL | #![cfg(not(target(os = "does_not_exist")))]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
+   = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+warning: unexpected `cfg` condition value: `does_not_exist`
+  --> $DIR/cfg-crate-features.rs:9:19
+   |
+LL | #![cfg(not(target(os = "does_not_exist")))]
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, and `uefi` and 9 more
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
index f68fdb3b651..32fa46b92b3 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
@@ -1,14 +1,15 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/issue-71348.rs:18:40
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
-   |                                        ^^           -- ------------------------ the lifetimes get resolved as `'a`
+   |                                        ^^           -- ------------------------ the same lifetime is hidden here
    |                                        |            |
-   |                                        |            the lifetimes get resolved as `'a`
-   |                                        this lifetime flows to the output
+   |                                        |            the same lifetime is named here
+   |                                        the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<'a, N>>::Target
    |                                                                     +++
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs
index c6563c80305..9053f362ce4 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.rs
+++ b/tests/ui/const-generics/type-dependent/issue-71348.rs
@@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> {
 impl Foo {
     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
     //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
-    //[full]~^^ WARNING lifetime flowing from input to output with different syntax
+    //[full]~^^ WARNING hiding a lifetime that's named elsewhere is confusing
     where
         Self: Get<'a, N>,
     {
diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs
index 22a607e9e0e..0ea75f2a2f4 100644
--- a/tests/ui/consts/const_transmute_type_id4.rs
+++ b/tests/ui/consts/const_transmute_type_id4.rs
@@ -10,7 +10,7 @@ const _: () = {
         std::ptr::write(ptr.offset(0), main as fn() as *const ());
     }
     assert!(a == b);
-    //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id
+    //~^ ERROR: invalid `TypeId` value
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr
index b418a79d7f0..b224227cf35 100644
--- a/tests/ui/consts/const_transmute_type_id4.stderr
+++ b/tests/ui/consts/const_transmute_type_id4.stderr
@@ -1,4 +1,4 @@
-error[E0080]: type_id_eq: `TypeId` provenance is not a type id
+error[E0080]: invalid `TypeId` value: not all bytes carry type id metadata
   --> $DIR/const_transmute_type_id4.rs:12:13
    |
 LL |     assert!(a == b);
diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs
index 0a9ba01e0dd..ae0429f8dbb 100644
--- a/tests/ui/consts/const_transmute_type_id5.rs
+++ b/tests/ui/consts/const_transmute_type_id5.rs
@@ -1,12 +1,11 @@
-//! Test that we require an equal TypeId to have the same integer
-//! part, even if the provenance matches.
+//! Test that we require an equal TypeId to have an integer part that properly
+//! reflects the type id hash.
 
 #![feature(const_type_id, const_trait_impl, const_cmp)]
 
 use std::any::TypeId;
 
 const _: () = {
-    let a = TypeId::of::<()>();
     let mut b = TypeId::of::<()>();
     unsafe {
         let ptr = &mut b as *mut TypeId as *mut *const ();
@@ -14,8 +13,8 @@ const _: () = {
         let val = std::ptr::read(ptr);
         std::ptr::write(ptr.offset(1), val);
     }
-    assert!(a == b);
-    //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+    assert!(b == b);
+    //~^ ERROR: invalid `TypeId` value
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr
index 59823fcc1c9..6205679ebb6 100644
--- a/tests/ui/consts/const_transmute_type_id5.stderr
+++ b/tests/ui/consts/const_transmute_type_id5.stderr
@@ -1,7 +1,7 @@
-error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
-  --> $DIR/const_transmute_type_id5.rs:17:13
+error[E0080]: invalid `TypeId` value: the hash does not match the type id metadata
+  --> $DIR/const_transmute_type_id5.rs:16:13
    |
-LL |     assert!(a == b);
+LL |     assert!(b == b);
    |             ^^^^^^ evaluation of `_` failed inside this call
    |
 note: inside `<TypeId as PartialEq>::eq`
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
index 1ac3c593dbe..1b8a5d4ca99 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
     v.into_iter()
 }
 
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
index b9d8674992c..3651226e0c3 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
@@ -1,11 +1,12 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-   |                               ^^ this lifetime flows to the output               ---- the lifetime gets resolved as `'a`
+   |                               ^^ the lifetime is named here                      ---- the same lifetime is elided here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &'a u32)> {
    |                                                                                   ++
diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs
new file mode 100644
index 00000000000..34803c8c103
--- /dev/null
+++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs
@@ -0,0 +1,18 @@
+// The opaque type collector used to expand free alias types (in situ) without guarding against
+// endlessly recursing aliases which lead to the compiler overflowing its stack in certain
+// situations.
+//
+// In most situations we wouldn't even reach the collector when there's an overflow because we
+// would've already bailed out early during the item's wfcheck due to the normalization failure.
+//
+// In the case below however, while collecting the opaque types defined by the AnonConst, we
+// descend into its nested items (here: type alias `Recur`) to acquire their opaque types --
+// meaning we get there before we wfcheck `Recur`.
+//
+// issue: <https://github.com/rust-lang/rust/issues/131994>
+#![feature(lazy_type_alias)]
+#![expect(incomplete_features)]
+
+struct Hold([(); { type Recur = Recur; 0 }]); //~ ERROR overflow normalizing the type alias `Recur`
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr
new file mode 100644
index 00000000000..e93fcd03a96
--- /dev/null
+++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr
@@ -0,0 +1,11 @@
+error[E0275]: overflow normalizing the type alias `Recur`
+  --> $DIR/opaq-ty-collection-infinite-recur.rs:16:20
+   |
+LL | struct Hold([(); { type Recur = Recur; 0 }]);
+   |                    ^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
index 1804003d367..9162a38f510 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
@@ -4,7 +4,7 @@ struct Foo;
 
 impl Foo {
     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         unsafe { &mut *(x as *mut _) }
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
index 7c7411651d0..5a7a5a6ebf9 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
@@ -1,17 +1,18 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/example-from-issue48686.rs:6:21
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-   |                     ^^^^^^^                      ------- the lifetime gets resolved as `'static`
+   |                     ^^^^^^^                      ------- the same lifetime is elided here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/example-from-issue48686.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
    |                                                   +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
index 3d5aab5c829..ecc790be5a0 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
@@ -1,26 +1,26 @@
 #![deny(mismatched_lifetime_syntaxes)]
 
 fn ampersand<'a>(x: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets<'a>(x: &'a u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma<'a>(x: &'a u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
index 681b3c97052..af56a0a0ea5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:3:22
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
-   |                      ^^        --- the lifetime gets resolved as `'a`
+   |                      ^^        --- the same lifetime is elided here
    |                      |
-   |                      this lifetime flows to the output
+   |                      the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/missing-lifetime-kind.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 {
    |                                 ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:10:21
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets {
-   |                     ^^        -------- the lifetime gets resolved as `'a`
+   |                     ^^        -------- the same lifetime is hidden here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> {
    |                                       ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:17:18
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
-   |                  ^^        --------- the lifetime gets resolved as `'a`
+   |                  ^^        --------- the same lifetime is hidden here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> {
    |                                  +++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:22:23
    |
 LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-   |                       ^^         -- the lifetime gets resolved as `'a`
+   |                       ^^         -- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 {
 LL + fn underscore<'a>(x: &'a u8) -> &'a u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
index cc398ab7888..449b2a3c0a8 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
@@ -6,13 +6,13 @@
 #[warn(mismatched_lifetime_syntaxes)]
 mod foo {
     fn bar(x: &'static u8) -> &u8 {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         x
     }
 
     #[deny(mismatched_lifetime_syntaxes)]
     fn baz(x: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         x
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
index da691225c17..cf0a29678fa 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
@@ -1,35 +1,37 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:8:16
    |
 LL |     fn bar(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:6:8
    |
 LL | #[warn(mismatched_lifetime_syntaxes)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn bar(x: &'static u8) -> &'static u8 {
    |                                +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:14:16
    |
 LL |     fn baz(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:13:12
    |
 LL |     #[deny(mismatched_lifetime_syntaxes)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn baz(x: &'static u8) -> &'static u8 {
    |                                +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
index 47ae258f138..c41cf44e1c5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
@@ -14,26 +14,26 @@ impl Trait for () {
 }
 
 fn ampersand(x: &'static u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets(x: &'static u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma(x: &'static u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore(x: &'static u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
index 5b9a986bcbe..d60bec6f7e4 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:16:18
    |
 LL | fn ampersand(x: &'static u8) -> &u8 {
-   |                  ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                  ^^^^^^^        --- the same lifetime is elided here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/static.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL | fn ampersand(x: &'static u8) -> &'static u8 {
    |                                  +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:23:17
    |
 LL | fn brackets(x: &'static u8) -> Brackets {
-   |                 ^^^^^^^        -------- the lifetime gets resolved as `'static`
+   |                 ^^^^^^^        -------- the same lifetime is hidden here
    |                 |
-   |                 this lifetime flows to the output
+   |                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn brackets(x: &'static u8) -> Brackets<'static> {
    |                                        +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:30:14
    |
 LL | fn comma(x: &'static u8) -> Comma<u8> {
-   |              ^^^^^^^        --------- the lifetime gets resolved as `'static`
+   |              ^^^^^^^        --------- the same lifetime is hidden here
    |              |
-   |              this lifetime flows to the output
+   |              the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn comma(x: &'static u8) -> Comma<'static, u8> {
    |                                   ++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:35:19
    |
 LL | fn underscore(x: &'static u8) -> &'_ u8 {
-   |                   ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                   ^^^^^^^         -- the same lifetime is elided here
    |                   |
-   |                   this lifetime flows to the output
+   |                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL - fn underscore(x: &'static u8) -> &'_ u8 {
 LL + fn underscore(x: &'static u8) -> &'static u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
index b98423afb17..f6260c47202 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
@@ -5,109 +5,111 @@ struct ContainsLifetime<'a>(&'a u8);
 
 struct S(u8);
 
+// ref to ref
+
 fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
-// ---
+// path to path
 
 fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_explicit_anonymous_path<'a>(
     v: ContainsLifetime<'a>,
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
 ) -> ContainsLifetime<'_> {
     v
 }
 
-// ---
+// ref to path
 
 fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
-// ---
+// path to ref
 
 fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 impl S {
     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     // ---
 
     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 }
@@ -122,43 +124,43 @@ mod static_suggestions {
     struct S(u8);
 
     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     impl S {
         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
 
         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
     }
@@ -170,23 +172,23 @@ mod impl_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_precise_capture<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ) -> impl FnOnce() + use<'_> {
         move || _ = v
     }
@@ -200,13 +202,13 @@ mod dyn_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         Box::new(iter::once(v))
     }
 
     fn explicit_bound_path_to_dyn_trait_bound<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
         Box::new(iter::once(v))
     }
@@ -214,10 +216,28 @@ mod dyn_trait {
 
 /// These tests serve to exercise edge cases of the lint formatting
 mod diagnostic_output {
+    #[derive(Copy, Clone)]
+    struct ContainsLifetime<'a>(&'a u8);
+
+    fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        v.0
+    }
+
     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         (v, v)
     }
+
+    fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+        //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing
+        (v.0, v)
+    }
+
+    fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        (v, v, ContainsLifetime(v))
+    }
 }
 
 /// Trait functions are represented differently in the HIR. Make sure
@@ -228,20 +248,20 @@ mod trait_functions {
 
     trait TheTrait {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 
     impl TheTrait for &u8 {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(v)
         }
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(self)
         }
     }
@@ -255,7 +275,7 @@ mod foreign_functions {
 
     extern "Rust" {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
index 108b3f14169..20b7561c594 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
@@ -1,538 +1,613 @@
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:8:47
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:10:47
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-   |                                               ^^        --- the lifetime gets resolved as `'a`
+   |                                               ^^        --- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
+   |                                               the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/mismatched-lifetime-syntaxes.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 {
    |                                                          ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:13:57
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:15:57
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-   |                                                         ^^         -- the lifetime gets resolved as `'a`
+   |                                                         ^^         -- the same lifetime is elided here
    |                                                         |
-   |                                                         this lifetime flows to the output
+   |                                                         the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
 LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:20:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:22:48
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-   |                                                ^^^^^^^^^^^^^^^^                      -- the lifetime gets resolved as `'_`
+   |                                                ^^^^^^^^^^^^^^^^                      -- the same lifetime is elided here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is hidden here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:25:65
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:27:65
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'_`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is elided here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:30:65
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:32:65
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'a`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:36:25
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:38:25
    |
 LL |     v: ContainsLifetime<'a>,
-   |                         ^^ this lifetime flows to the output
+   |                         ^^ the lifetime is named here
 LL |
 LL | ) -> ContainsLifetime<'_> {
-   |                       -- the lifetime gets resolved as `'a`
+   |                       -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - ) -> ContainsLifetime<'_> {
 LL + ) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:44:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:46:37
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                     ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                     ^^^     ---------------- the same lifetime is hidden here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                             ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:49:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:51:48
    |
 LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'_`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<'_> {
+   |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:54:48
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:56:48
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'a`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:59:58
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:61:58
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-   |                                                          ^^                         -- the lifetime gets resolved as `'a`
+   |                                                          ^^                         -- the same lifetime is elided here
    |                                                          |
-   |                                                          this lifetime flows to the output
+   |                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
 LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:66:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:68:37
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-   |                                     ^^^^^^^^^^^^^^^^     --- the lifetime gets resolved as `'_`
+   |                                     ^^^^^^^^^^^^^^^^     --- the same lifetime is elided here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is hidden here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 {
    |                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:71:47
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:73:47
    |
 LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-   |                                               ^^^^^^^^^^^^^^^^      -- the lifetime gets resolved as `'_`
+   |                                               ^^^^^^^^^^^^^^^^      -- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
-   |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   |                                               the lifetime is hidden here
    |
-LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 {
+   |                                                               ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:76:64
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:78:64
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-   |                                                                ^^      --- the lifetime gets resolved as `'a`
+   |                                                                ^^      --- the same lifetime is elided here
    |                                                                |
-   |                                                                this lifetime flows to the output
+   |                                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:81:74
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:83:74
    |
 LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-   |                                                                          ^^       -- the lifetime gets resolved as `'a`
+   |                                                                          ^^       -- the same lifetime is elided here
    |                                                                          |
-   |                                                                          this lifetime flows to the output
+   |                                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
 LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:87:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:89:55
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-   |                                                       ^^          --- the lifetime gets resolved as `'a`
+   |                                                       ^^          --- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 {
    |                                                                    ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:92:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:94:65
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-   |                                                                 ^^           -- the lifetime gets resolved as `'a`
+   |                                                                 ^^           -- the same lifetime is elided here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:99:56
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:101:56
    |
 LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'_`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL -     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-LL +     fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime<'_> {
+   |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:104:56
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:106:56
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'a`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:109:66
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:111:66
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-   |                                                                  ^^                           -- the lifetime gets resolved as `'a`
+   |                                                                  ^^                           -- the same lifetime is elided here
    |                                                                  |
-   |                                                                  this lifetime flows to the output
+   |                                                                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:124:39
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:126:39
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-   |                                       ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                                       ^^^^^^^        --- the same lifetime is elided here
    |                                       |
-   |                                       this lifetime flows to the output
+   |                                       the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 {
    |                                                       +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:129:49
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:131:49
    |
 LL |     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-   |                                                 ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                                                 ^^^^^^^         -- the same lifetime is elided here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
 LL +     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:134:40
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:136:40
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-   |                                        ^^^^^^^        ---------------- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^        ---------------- the same lifetime is hidden here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> {
    |                                                                       +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:139:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:141:50
    |
 LL |     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-   |                                                  ^^^^^^^                         -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^                         -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
 LL +     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:145:40
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:147:40
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-   |                                        ^^^^^^^          --- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^          --- the same lifetime is elided here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &'static u8 {
    |                                                          +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:150:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:152:50
    |
 LL |         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-   |                                                  ^^^^^^^           -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^           -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
 LL +         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:155:41
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:157:41
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-   |                                         ^^^^^^^          ---------------- the lifetime gets resolved as `'static`
+   |                                         ^^^^^^^          ---------------- the same lifetime is hidden here
    |                                         |
-   |                                         this lifetime flows to the output
+   |                                         the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> {
    |                                                                          +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:160:51
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:162:51
    |
 LL |         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-   |                                                   ^^^^^^^                           -- the lifetime gets resolved as `'static`
+   |                                                   ^^^^^^^                           -- the same lifetime is elided here
    |                                                   |
-   |                                                   this lifetime flows to the output
+   |                                                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
 LL +         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:172:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:174:55
    |
 LL |     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-   |                                                       ^^                        -- the lifetime gets resolved as `'a`
+   |                                                       ^^                        -- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:177:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:179:65
    |
 LL |     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-   |                                                                 ^^                            -- the lifetime gets resolved as `'a`
-   |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 ^^ the lifetime is named here -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
 LL +     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:182:72
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:184:72
    |
 LL |     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-   |                                                                        ^^                      -- the lifetime gets resolved as `'a`
+   |                                                                        ^^                      -- the same lifetime is elided here
    |                                                                        |
-   |                                                                        this lifetime flows to the output
+   |                                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:188:29
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:190:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> impl FnOnce() + use<'_> {
-   |                              -- the lifetime gets resolved as `'a`
+   |                              -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     ) -> impl FnOnce() + use<'_> {
 LL +     ) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:202:54
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:204:54
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-   |                                                      ^^                                ---    -- the lifetimes get resolved as `'a`
-   |                                                      |                                 |
-   |                                                      |                                 the lifetimes get resolved as `'a`
-   |                                                      this lifetime flows to the output
+   |                                                      ^^ the lifetime is named here     --- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &'a u8> + '_> {
    |                                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:208:29
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:210:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
-   |                                  ----------------    -- the lifetimes get resolved as `'a`
-   |                                  |
-   |                                  the lifetimes get resolved as `'a`
+   |                                  ---------------- the same lifetime is hidden here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime<'a>> + '_> {
    |                                                  ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:217:33
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:222:33
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+   |                                 ^^      ^^         --- the same lifetime is elided here
+   |                                 |       |
+   |                                 |       the lifetime is named here
+   |                                 the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 {
+   |                                                     ++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:227:33
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-   |                                 ^^         ---  --- the lifetimes get resolved as `'a`
+   |                                 ^^         ---  --- the same lifetime is elided here
    |                                 |          |
-   |                                 |          the lifetimes get resolved as `'a`
-   |                                 this lifetime flows to the output
+   |                                 |          the same lifetime is elided here
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) {
    |                                             ++      ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:230:45
+error: hiding or eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:232:53
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+   |                                                     ^^       ---  ---------------- the same lifetime is hidden here
+   |                                                     |        |
+   |                                                     |        the same lifetime is elided here
+   |                                                     the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, ContainsLifetime<'a>) {
+   |                                                               ++                     ++++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:237:38
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+   |                                      ^^         ---   --                      -- the same lifetime is named here
+   |                                      |          |     |
+   |                                      |          |     the same lifetime is named here
+   |                                      |          the same lifetime is elided here
+   |                                      the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&'a u8, &'a u8, ContainsLifetime<'a>) {
+   |                                                  ++
+
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:250:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:233:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:253:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>;
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:238:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:258:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:243:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:263:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:257:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:277:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: aborting due to 39 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
new file mode 100644
index 00000000000..13f3065e442
--- /dev/null
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
@@ -0,0 +1,13 @@
+// We should not emit sealed traits note, see issue #143392
+
+mod inner {
+    pub trait TraitA {}
+
+    pub trait TraitB: TraitA {}
+}
+
+struct Struct;
+
+impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277]
+
+fn main(){}
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
new file mode 100644
index 00000000000..f80d985ad6e
--- /dev/null
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `Struct: TraitA` is not satisfied
+  --> $DIR/false-sealed-traits-note.rs:11:24
+   |
+LL | impl inner::TraitB for Struct {}
+   |                        ^^^^^^ the trait `TraitA` is not implemented for `Struct`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/false-sealed-traits-note.rs:4:5
+   |
+LL |     pub trait TraitA {}
+   |     ^^^^^^^^^^^^^^^^
+note: required by a bound in `TraitB`
+  --> $DIR/false-sealed-traits-note.rs:6:23
+   |
+LL |     pub trait TraitB: TraitA {}
+   |                       ^^^^^^ required by this bound in `TraitB`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
index ecd669059ed..ce2fb8235cc 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
@@ -4,11 +4,11 @@ struct Foo<'a>(&'a str);
 
 impl<'b> Foo<'b> {
     fn a<'a>(self: Self, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
 }
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
index 5351bf3c94c..7108fa1a290 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:6:30
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &str {
-   |                              ^^         ---- the lifetime gets resolved as `'a`
+   |                              ^^         ---- the same lifetime is elided here
    |                              |
-   |                              this lifetime flows to the output
+   |                              the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &'a str {
    |                                          ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:10:33
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-   |                                 ^^         ---- the lifetime gets resolved as `'a`
+   |                                 ^^         ---- the same lifetime is elided here
    |                                 |
-   |                                 this lifetime flows to the output
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str {
    |                                             ++
diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs
index f839ab03a60..0093971fee4 100644
--- a/tests/ui/self/self_lifetime-async.rs
+++ b/tests/ui/self/self_lifetime-async.rs
@@ -4,13 +4,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr
index a9c1be2e808..43dc96abdc2 100644
--- a/tests/ui/self/self_lifetime-async.stderr
+++ b/tests/ui/self/self_lifetime-async.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:6:29
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                             ^^             --- the lifetime gets resolved as `'b`
+   |                             ^^             --- the same lifetime is elided here
    |                             |
-   |                             this lifetime flows to the output
+   |                             the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                             ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:12:42
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                          ^^        --- the lifetime gets resolved as `'a`
+   |                                          ^^        --- the same lifetime is elided here
    |                                          |
-   |                                          this lifetime flows to the output
+   |                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                                     ++
diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs
index aaa31f85ad5..190809af22f 100644
--- a/tests/ui/self/self_lifetime.rs
+++ b/tests/ui/self/self_lifetime.rs
@@ -5,13 +5,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr
index ec676e69cf6..4f9b2fcd2ad 100644
--- a/tests/ui/self/self_lifetime.stderr
+++ b/tests/ui/self/self_lifetime.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:7:23
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                       ^^             --- the lifetime gets resolved as `'b`
+   |                       ^^             --- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                       ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:13:36
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                    ^^        --- the lifetime gets resolved as `'a`
+   |                                    ^^        --- the same lifetime is elided here
    |                                    |
-   |                                    this lifetime flows to the output
+   |                                    the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                               ++