diff --git a/Cargo.lock b/Cargo.lock
index 68ea8b51c555c..90bcc2e4be42a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3958,6 +3958,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "thin-vec",
  "tracing",
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index 60086cd6e477f..2899b8304bc14 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -104,9 +104,67 @@ infer_relate_object_bound = ...so that it can be closed over into an object
 infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
 infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
 infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
-[true] ...
-*[false] {""}
+    [true] ...
+    *[false] {""}
 }
 infer_relate_param_bound_2 = ...that is required by this bound
 infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
 infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+
+infer_nothing = {""}
+
+infer_lifetime_mismatch = lifetime mismatch
+
+infer_declared_different = this parameter and the return type are declared with different lifetimes...
+infer_data_returned = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} is returned here
+
+infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
+infer_declared_multiple = this type is declared with multiple lifetimes...
+infer_types_declared_different = these two types are declared with different lifetimes...
+infer_data_flows = ...but data{$label_var1_exists ->
+    [true] -> {" "}from `{$label_var1}`
+    *[false] -> {""}
+} flows{$label_var2_exists ->
+    [true] -> {" "}into `{$label_var2}`
+    *[false] -> {""}
+} here
+
+infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+    [true] {" "}and update trait if needed
+    *[false] {""}
+}
+infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_region_explanation = {$pref_kind ->
+    *[should_not_happen] [{$pref_kind}]
+    [empty] {""}
+}{$pref_kind ->
+    [empty] {""}
+    *[other] {" "}
+}{$desc_kind ->
+    *[should_not_happen] [{$desc_kind}]
+    [restatic] the static lifetime
+    [reempty] the empty lifetime
+    [reemptyuni] the empty lifetime in universe {$desc_arg}
+    [revar] lifetime {$desc_arg}
+
+    [as_defined] the lifetime `{$desc_arg}` as defined here
+    [as_defined_anon] the anonymous lifetime as defined here
+    [defined_here] the anonymous lifetime defined here
+    [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
+    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+    *[should_not_happen] [{$suff_kind}]
+    [empty]{""}
+    [continues] ...
+}
+
+infer_mismatched_static_lifetime = incompatible lifetime on type
+infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs
deleted file mode 100644
index 938f8aa77a5b4..0000000000000
--- a/compiler/rustc_infer/src/errors.rs
+++ /dev/null
@@ -1,254 +0,0 @@
-use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
-use rustc_hir::FnRetTy;
-use rustc_macros::SessionDiagnostic;
-use rustc_span::{BytePos, Span};
-
-use crate::infer::error_reporting::{
-    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
-    ObligationCauseAsDiagArg,
-};
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::opaque_hidden_type)]
-pub struct OpaqueHiddenTypeDiag {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[note(infer::opaque_type)]
-    pub opaque_type: Span,
-    #[note(infer::hidden_type)]
-    pub hidden_type: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
-pub struct AnnotationRequired<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0283
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
-pub struct AmbigousImpl<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0284
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
-pub struct AmbigousReturn<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
-pub struct NeedTypeInfoInGenerator<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub generator_kind: GeneratorKindAsDiagArg,
-    #[subdiagnostic]
-    pub bad_label: InferenceBadError<'a>,
-}
-
-// Used when a better one isn't available
-#[derive(SessionSubdiagnostic)]
-#[label(infer::label_bad)]
-pub struct InferenceBadError<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub bad_kind: &'static str,
-    pub prefix_kind: UnderspecifiedArgKind,
-    pub has_parent: bool,
-    pub prefix: &'a str,
-    pub parent_prefix: &'a str,
-    pub parent_name: String,
-    pub name: String,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum SourceKindSubdiag<'a> {
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_let,
-        code = ": {type_name}",
-        applicability = "has-placeholders"
-    )]
-    LetLike {
-        #[primary_span]
-        span: Span,
-        name: String,
-        type_name: String,
-        kind: &'static str,
-        x_kind: &'static str,
-        prefix_kind: UnderspecifiedArgKind,
-        prefix: &'a str,
-        arg_name: String,
-    },
-    #[label(infer::source_kind_subdiag_generic_label)]
-    GenericLabel {
-        #[primary_span]
-        span: Span,
-        is_type: bool,
-        param_name: String,
-        parent_exists: bool,
-        parent_prefix: String,
-        parent_name: String,
-    },
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_generic_suggestion,
-        code = "::<{args}>",
-        applicability = "has-placeholders"
-    )]
-    GenericSuggestion {
-        #[primary_span]
-        span: Span,
-        arg_count: usize,
-        args: String,
-    },
-}
-
-// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
-// Would be a part of `SourceKindSubdiag` otherwise.
-pub enum SourceKindMultiSuggestion<'a> {
-    FullyQualified {
-        span: Span,
-        def_path: String,
-        adjustment: &'a str,
-        successor: (&'a str, BytePos),
-    },
-    ClosureReturn {
-        ty_info: String,
-        data: &'a FnRetTy<'a>,
-        should_wrap_expr: Option<Span>,
-    },
-}
-
-impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        match self {
-            Self::FullyQualified { span, def_path, adjustment, successor } => {
-                let suggestion = vec![
-                    (span.shrink_to_lo(), format!("{def_path}({adjustment}")),
-                    (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
-                ];
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_fully_qualified,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-            Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
-                let (arrow, post) = match data {
-                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
-                    _ => ("", ""),
-                };
-                let suggestion = match should_wrap_expr {
-                    Some(end_span) => vec![
-                        (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
-                        (end_span, " }".to_string()),
-                    ],
-                    None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
-                };
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_closure_return,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-        }
-    }
-}
-
-pub enum RegionOriginNote<'a> {
-    Plain {
-        span: Span,
-        msg: DiagnosticMessage,
-    },
-    WithName {
-        span: Span,
-        msg: DiagnosticMessage,
-        name: &'a str,
-        continues: bool,
-    },
-    WithRequirement {
-        span: Span,
-        requirement: ObligationCauseAsDiagArg<'a>,
-        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
-    },
-}
-
-impl AddSubdiagnostic for RegionOriginNote<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        let mut label_or_note = |span, msg: DiagnosticMessage| {
-            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
-            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
-            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
-            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
-                diag.span_label(span, msg);
-            } else if span_is_primary && expanded_sub_count == 0 {
-                diag.note(msg);
-            } else {
-                diag.span_note(span, msg);
-            }
-        };
-        match self {
-            RegionOriginNote::Plain { span, msg } => {
-                label_or_note(span, msg);
-            }
-            RegionOriginNote::WithName { span, msg, name, continues } => {
-                label_or_note(span, msg);
-                diag.set_arg("name", name);
-                diag.set_arg("continues", continues);
-            }
-            RegionOriginNote::WithRequirement {
-                span,
-                requirement,
-                expected_found: Some((expected, found)),
-            } => {
-                label_or_note(span, fluent::infer::subtype);
-                diag.set_arg("requirement", requirement);
-
-                diag.note_expected_found(&"", expected, &"", found);
-            }
-            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
-                // FIXME: this really should be handled at some earlier stage. Our
-                // handling of region checking when type errors are present is
-                // *terrible*.
-                label_or_note(span, fluent::infer::subtype_2);
-                diag.set_arg("requirement", requirement);
-            }
-        };
-    }
-}
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
new file mode 100644
index 0000000000000..d232a18646244
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -0,0 +1,499 @@
+use hir::GenericParamKind;
+use rustc_errors::{
+    fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
+};
+use rustc_hir as hir;
+use rustc_hir::{FnRetTy, Ty};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{Region, TyCtxt};
+use rustc_span::symbol::kw;
+use rustc_span::{symbol::Ident, BytePos, Span};
+
+use crate::infer::error_reporting::{
+    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+    ObligationCauseAsDiagArg,
+};
+
+pub mod note_and_explain;
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::opaque_hidden_type)]
+pub struct OpaqueHiddenTypeDiag {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(infer::opaque_type)]
+    pub opaque_type: Span,
+    #[note(infer::hidden_type)]
+    pub hidden_type: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0282")]
+pub struct AnnotationRequired<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0283")]
+pub struct AmbigousImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0284")]
+pub struct AmbigousReturn<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::need_type_info_in_generator, code = "E0698")]
+pub struct NeedTypeInfoInGenerator<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub generator_kind: GeneratorKindAsDiagArg,
+    #[subdiagnostic]
+    pub bad_label: InferenceBadError<'a>,
+}
+
+// Used when a better one isn't available
+#[derive(SessionSubdiagnostic)]
+#[label(infer::label_bad)]
+pub struct InferenceBadError<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub bad_kind: &'static str,
+    pub prefix_kind: UnderspecifiedArgKind,
+    pub has_parent: bool,
+    pub prefix: &'a str,
+    pub parent_prefix: &'a str,
+    pub parent_name: String,
+    pub name: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_let,
+        code = ": {type_name}",
+        applicability = "has-placeholders"
+    )]
+    LetLike {
+        #[primary_span]
+        span: Span,
+        name: String,
+        type_name: String,
+        kind: &'static str,
+        x_kind: &'static str,
+        prefix_kind: UnderspecifiedArgKind,
+        prefix: &'a str,
+        arg_name: String,
+    },
+    #[label(infer::source_kind_subdiag_generic_label)]
+    GenericLabel {
+        #[primary_span]
+        span: Span,
+        is_type: bool,
+        param_name: String,
+        parent_exists: bool,
+        parent_prefix: String,
+        parent_name: String,
+    },
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_generic_suggestion,
+        code = "::<{args}>",
+        applicability = "has-placeholders"
+    )]
+    GenericSuggestion {
+        #[primary_span]
+        span: Span,
+        arg_count: usize,
+        args: String,
+    },
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindMultiSuggestion<'a> {
+    #[multipart_suggestion_verbose(
+        infer::source_kind_fully_qualified,
+        applicability = "has-placeholders"
+    )]
+    FullyQualified {
+        #[suggestion_part(code = "{def_path}({adjustment}")]
+        span_lo: Span,
+        #[suggestion_part(code = "{successor_pos}")]
+        span_hi: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor_pos: &'a str,
+    },
+    #[multipart_suggestion_verbose(
+        infer::source_kind_closure_return,
+        applicability = "has-placeholders"
+    )]
+    ClosureReturn {
+        #[suggestion_part(code = "{start_span_code}")]
+        start_span: Span,
+        start_span_code: String,
+        #[suggestion_part(code = " }}")]
+        end_span: Option<Span>,
+    },
+}
+
+impl<'a> SourceKindMultiSuggestion<'a> {
+    pub fn new_fully_qualified(
+        span: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor: (&'a str, BytePos),
+    ) -> Self {
+        Self::FullyQualified {
+            span_lo: span.shrink_to_lo(),
+            span_hi: span.shrink_to_hi().with_hi(successor.1),
+            def_path,
+            adjustment,
+            successor_pos: successor.0,
+        }
+    }
+
+    pub fn new_closure_return(
+        ty_info: String,
+        data: &'a FnRetTy<'a>,
+        should_wrap_expr: Option<Span>,
+    ) -> Self {
+        let (arrow, post) = match data {
+            FnRetTy::DefaultReturn(_) => ("-> ", " "),
+            _ => ("", ""),
+        };
+        let (start_span, start_span_code, end_span) = match should_wrap_expr {
+            Some(end_span) => {
+                (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
+            }
+            None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
+        };
+        Self::ClosureReturn { start_span, start_span_code, end_span }
+    }
+}
+
+pub enum RegionOriginNote<'a> {
+    Plain {
+        span: Span,
+        msg: DiagnosticMessage,
+    },
+    WithName {
+        span: Span,
+        msg: DiagnosticMessage,
+        name: &'a str,
+        continues: bool,
+    },
+    WithRequirement {
+        span: Span,
+        requirement: ObligationCauseAsDiagArg<'a>,
+        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
+    },
+}
+
+impl AddSubdiagnostic for RegionOriginNote<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut label_or_note = |span, msg: DiagnosticMessage| {
+            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+                diag.span_label(span, msg);
+            } else if span_is_primary && expanded_sub_count == 0 {
+                diag.note(msg);
+            } else {
+                diag.span_note(span, msg);
+            }
+        };
+        match self {
+            RegionOriginNote::Plain { span, msg } => {
+                label_or_note(span, msg);
+            }
+            RegionOriginNote::WithName { span, msg, name, continues } => {
+                label_or_note(span, msg);
+                diag.set_arg("name", name);
+                diag.set_arg("continues", continues);
+            }
+            RegionOriginNote::WithRequirement {
+                span,
+                requirement,
+                expected_found: Some((expected, found)),
+            } => {
+                label_or_note(span, fluent::infer::subtype);
+                diag.set_arg("requirement", requirement);
+
+                diag.note_expected_found(&"", expected, &"", found);
+            }
+            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+                // FIXME: this really should be handled at some earlier stage. Our
+                // handling of region checking when type errors are present is
+                // *terrible*.
+                label_or_note(span, fluent::infer::subtype_2);
+                diag.set_arg("requirement", requirement);
+            }
+        };
+    }
+}
+
+pub enum LifetimeMismatchLabels {
+    InRet {
+        param_span: Span,
+        ret_span: Span,
+        span: Span,
+        label_var1: Option<Ident>,
+    },
+    Normal {
+        hir_equal: bool,
+        ty_sup: Span,
+        ty_sub: Span,
+        span: Span,
+        sup: Option<Ident>,
+        sub: Option<Ident>,
+    },
+}
+
+impl AddSubdiagnostic for LifetimeMismatchLabels {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+                diag.span_label(param_span, fluent::infer::declared_different);
+                diag.span_label(ret_span, fluent::infer::nothing);
+                diag.span_label(span, fluent::infer::data_returned);
+                diag.set_arg("label_var1_exists", label_var1.is_some());
+                diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+            }
+            LifetimeMismatchLabels::Normal {
+                hir_equal,
+                ty_sup,
+                ty_sub,
+                span,
+                sup: label_var1,
+                sub: label_var2,
+            } => {
+                if hir_equal {
+                    diag.span_label(ty_sup, fluent::infer::declared_multiple);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_lifetime_flow);
+                } else {
+                    diag.span_label(ty_sup, fluent::infer::types_declared_different);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_flows);
+                    diag.set_arg("label_var1_exists", label_var1.is_some());
+                    diag.set_arg(
+                        "label_var1",
+                        label_var1.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                    diag.set_arg("label_var2_exists", label_var2.is_some());
+                    diag.set_arg(
+                        "label_var2",
+                        label_var2.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                }
+            }
+        }
+    }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub sub: Region<'a>,
+    pub ty_sup: &'a Ty<'a>,
+    pub ty_sub: &'a Ty<'a>,
+    pub add_note: bool,
+}
+
+impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut mk_suggestion = || {
+            let (
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+            ) = (self.ty_sub, self.ty_sup) else {
+                return false;
+            };
+
+            if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
+                return false;
+            };
+
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+                return false;
+            };
+
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+            let node = self.tcx.hir().get(hir_id);
+            let is_impl = matches!(&node, hir::Node::ImplItem(_));
+            let generics = match node {
+                hir::Node::Item(&hir::Item {
+                    kind: hir::ItemKind::Fn(_, ref generics, ..),
+                    ..
+                })
+                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                _ => return false,
+            };
+
+            let suggestion_param_name = generics
+                .params
+                .iter()
+                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                .map(|p| p.name.ident().name)
+                .find(|i| *i != kw::UnderscoreLifetime);
+            let introduce_new = suggestion_param_name.is_none();
+            let suggestion_param_name =
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+            debug!(?lifetime_sup.span);
+            debug!(?lifetime_sub.span);
+            let make_suggestion = |span: rustc_span::Span| {
+                if span.is_empty() {
+                    (span, format!("{}, ", suggestion_param_name))
+                } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
+                {
+                    (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
+                } else {
+                    (span, suggestion_param_name.clone())
+                }
+            };
+            let mut suggestions =
+                vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
+
+            if introduce_new {
+                let new_param_suggestion = if let Some(first) =
+                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+                {
+                    (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+                } else {
+                    (generics.span, format!("<{}>", suggestion_param_name))
+                };
+
+                suggestions.push(new_param_suggestion);
+            }
+
+            diag.multipart_suggestion(
+                fluent::infer::lifetime_param_suggestion,
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+            diag.set_arg("is_impl", is_impl);
+            true
+        };
+        if mk_suggestion() && self.add_note {
+            diag.note(fluent::infer::lifetime_param_suggestion_elided);
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::lifetime_mismatch, code = "E0623")]
+pub struct LifetimeMismatch<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub labels: LifetimeMismatchLabels,
+    #[subdiagnostic]
+    pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub struct IntroducesStaticBecauseUnmetLifetimeReq {
+    pub unmet_requirements: MultiSpan,
+    pub binding_span: Span,
+}
+
+impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+    fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+        self.unmet_requirements
+            .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+    }
+}
+
+pub struct ImplNote {
+    pub impl_span: Option<Span>,
+}
+
+impl AddSubdiagnostic for ImplNote {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self.impl_span {
+            Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
+            None => diag.note(fluent::infer::msl_impl_note),
+        };
+    }
+}
+
+pub enum TraitSubdiag {
+    Note { span: Span },
+    Sugg { span: Span },
+}
+
+// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
+impl AddSubdiagnostic for TraitSubdiag {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            TraitSubdiag::Note { span } => {
+                diag.span_note(span, "this has an implicit `'static` lifetime requirement");
+            }
+            TraitSubdiag::Sugg { span } => {
+                diag.span_suggestion_verbose(
+                    span,
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_".to_owned(),
+                    rustc_errors::Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::mismatched_static_lifetime)]
+pub struct MismatchedStaticLifetime<'a> {
+    #[primary_span]
+    pub cause_span: Span,
+    #[subdiagnostic]
+    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
+    #[subdiagnostic]
+    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+    #[subdiagnostic]
+    pub impl_note: ImplNote,
+    #[subdiagnostic]
+    pub trait_subdiags: Vec<TraitSubdiag>,
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
new file mode 100644
index 0000000000000..6f1f9522c869d
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -0,0 +1,179 @@
+use crate::infer::error_reporting::nice_region_error::find_anon_type;
+use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::{symbol::kw, Span};
+
+#[derive(Default)]
+struct DescriptionCtx<'a> {
+    span: Option<Span>,
+    kind: &'a str,
+    arg: String,
+    num_arg: u32,
+}
+
+impl<'a> DescriptionCtx<'a> {
+    fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        me.span = alt_span;
+        match *region {
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {
+                return Self::from_early_bound_and_free_regions(tcx, region);
+            }
+            ty::ReStatic => {
+                me.kind = "restatic";
+            }
+
+            ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
+
+            ty::ReEmpty(ui) => {
+                me.kind = "reemptyuni";
+                me.arg = format!("{:?}", ui);
+            }
+
+            ty::RePlaceholder(_) => return None,
+
+            // FIXME(#13998) RePlaceholder should probably print like
+            // ReFree rather than dumping Debug output on the user.
+            //
+            // We shouldn't really be having unification failures with ReVar
+            // and ReLateBound though.
+            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+                me.kind = "revar";
+                me.arg = format!("{:?}", region);
+            }
+        };
+        Some(me)
+    }
+
+    fn from_early_bound_and_free_regions<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        let scope = region.free_region_binding_scope(tcx).expect_local();
+        match *region {
+            ty::ReEarlyBound(ref br) => {
+                let mut sp = tcx.def_span(scope);
+                if let Some(param) =
+                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+                {
+                    sp = param.span;
+                }
+                if br.has_name() {
+                    me.kind = "as_defined";
+                    me.arg = br.name.to_string();
+                } else {
+                    me.kind = "as_defined_anon";
+                };
+                me.span = Some(sp)
+            }
+            ty::ReFree(ref fr) => {
+                if !fr.bound_region.is_named()
+                    && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                {
+                    me.kind = "defined_here";
+                    me.span = Some(ty.span);
+                } else {
+                    match fr.bound_region {
+                        ty::BoundRegionKind::BrNamed(_, name) => {
+                            let mut sp = tcx.def_span(scope);
+                            if let Some(param) =
+                                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                            {
+                                sp = param.span;
+                            }
+                            if name == kw::UnderscoreLifetime {
+                                me.kind = "as_defined_anon";
+                            } else {
+                                me.kind = "as_defined";
+                                me.arg = name.to_string();
+                            };
+                            me.span = Some(sp);
+                        }
+                        ty::BrAnon(idx) => {
+                            me.kind = "anon_num_here";
+                            me.num_arg = idx+1;
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                        _ => {
+                            me.kind = "defined_here_reg";
+                            me.arg = region.to_string();
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                    }
+                }
+            }
+            _ => bug!(),
+        }
+        Some(me)
+    }
+
+    fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+        diag.set_arg("desc_kind", self.kind);
+        diag.set_arg("desc_arg", self.arg);
+        diag.set_arg("desc_num_arg", self.num_arg);
+    }
+}
+
+pub enum PrefixKind {
+    Empty,
+}
+
+pub enum SuffixKind {
+    Continues,
+}
+
+impl IntoDiagnosticArg for PrefixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Empty => "empty",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+impl IntoDiagnosticArg for SuffixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Continues => "continues",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+pub struct RegionExplanation<'a> {
+    desc: DescriptionCtx<'a>,
+    prefix: PrefixKind,
+    suffix: SuffixKind,
+}
+
+impl RegionExplanation<'_> {
+    pub fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+        prefix: PrefixKind,
+        suffix: SuffixKind,
+    ) -> Option<Self> {
+        Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+    }
+}
+
+impl AddSubdiagnostic for RegionExplanation<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        if let Some(span) = self.desc.span {
+            diag.span_note(span, fluent::infer::region_explanation);
+        } else {
+            diag.note(fluent::infer::region_explanation);
+        }
+        self.desc.add_to(diag);
+        diag.set_arg("pref_kind", self.prefix);
+        diag.set_arg("suff_kind", self.suffix);
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 20ce28fe8d03d..cb2be93589d05 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -511,20 +511,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     _ => "",
                 };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified {
-                    span: receiver.span,
+                multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+                    receiver.span,
                     def_path,
                     adjustment,
                     successor,
-                });
+                ));
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
                 let ty_info = ty_to_string(self, ty);
-                multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn {
+                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
                     ty_info,
                     data,
                     should_wrap_expr,
-                });
+                ));
             }
         }
         match error_code {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 9a2ab3e32248b..3a4320a9a8f1d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -1,6 +1,9 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where both the regions are anonymous.
 
+use crate::errors::AddLifetimeParamsSuggestion;
+use crate::errors::LifetimeMismatch;
+use crate::errors::LifetimeMismatchLabels;
 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::SubregionOrigin;
 use crate::infer::TyCtxt;
 
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::{GenericParamKind, Ty};
+use rustc_errors::AddSubdiagnostic;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir::Ty;
 use rustc_middle::ty::Region;
-use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let sub_is_ret_type =
             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
 
-        let span_label_var1 = match anon_param_sup.pat.simple_ident() {
-            Some(simple_ident) => format!(" from `{}`", simple_ident),
-            None => String::new(),
-        };
-
-        let span_label_var2 = match anon_param_sub.pat.simple_ident() {
-            Some(simple_ident) => format!(" into `{}`", simple_ident),
-            None => String::new(),
-        };
-
         debug!(
             "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
             sub_is_ret_type, sup_is_ret_type
         );
 
-        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
-        match (sup_is_ret_type, sub_is_ret_type) {
+        let labels = match (sup_is_ret_type, sub_is_ret_type) {
             (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
                 let param_span =
                     if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
-
-                err.span_label(
+                LifetimeMismatchLabels::InRet {
                     param_span,
-                    "this parameter and the return type are declared with different lifetimes...",
-                );
-                err.span_label(ret_span, "");
-                err.span_label(span, format!("...but data{} is returned here", span_label_var1));
-            }
-
-            (None, None) => {
-                if ty_sup.hir_id == ty_sub.hir_id {
-                    err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(span, "...but data with one lifetime flows into the other here");
-                } else {
-                    err.span_label(
-                        ty_sup.span,
-                        "these two types are declared with different lifetimes...",
-                    );
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(
-                        span,
-                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
-                    );
+                    ret_span,
+                    span,
+                    label_var1: anon_param_sup.pat.simple_ident(),
                 }
             }
-        }
 
-        if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
-            err.note("each elided lifetime in input position becomes a distinct lifetime");
-        }
+            (None, None) => LifetimeMismatchLabels::Normal {
+                hir_equal: ty_sup.hir_id == ty_sub.hir_id,
+                ty_sup: ty_sup.span,
+                ty_sub: ty_sub.span,
+                span,
+                sup: anon_param_sup.pat.simple_ident(),
+                sub: anon_param_sub.pat.simple_ident(),
+            },
+        };
 
-        let reported = err.emit();
+        let suggestion =
+            AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+        let err = LifetimeMismatch { span, labels, suggestion };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
 
+/// Currently only used in rustc_borrowck, probably should be
+/// removed in favour of public_errors::AddLifetimeParamsSuggestion
 pub fn suggest_adding_lifetime_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     sub: Region<'tcx>,
-    ty_sup: &Ty<'_>,
-    ty_sub: &Ty<'_>,
+    ty_sup: &'tcx Ty<'_>,
+    ty_sub: &'tcx Ty<'_>,
     err: &mut Diagnostic,
-) -> bool {
-    let (
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
-    ) = (ty_sub, ty_sup) else {
-        return false;
-    };
-
-    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
-        return false;
-    };
-
-    let Some(anon_reg) = tcx.is_suitable_region(sub) else {
-        return false;
-    };
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
-    let node = tcx.hir().get(hir_id);
-    let is_impl = matches!(&node, hir::Node::ImplItem(_));
-    let generics = match node {
-        hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
-        | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-        | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
-        _ => return false,
-    };
-
-    let suggestion_param_name = generics
-        .params
-        .iter()
-        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .map(|p| p.name.ident().name)
-        .find(|i| *i != kw::UnderscoreLifetime);
-    let introduce_new = suggestion_param_name.is_none();
-    let suggestion_param_name =
-        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
-    debug!(?lifetime_sup.span);
-    debug!(?lifetime_sub.span);
-    let make_suggestion = |span: rustc_span::Span| {
-        if span.is_empty() {
-            (span, format!("{}, ", suggestion_param_name))
-        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
-            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
-        } else {
-            (span, suggestion_param_name.clone())
-        }
-    };
-    let mut suggestions =
-        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
-    if introduce_new {
-        let new_param_suggestion =
-            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
-                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
-            } else {
-                (generics.span, format!("<{}>", suggestion_param_name))
-            };
-
-        suggestions.push(new_param_suggestion);
-    }
-
-    let mut sugg = String::from("consider introducing a named lifetime parameter");
-    if is_impl {
-        sugg.push_str(" and update trait if needed");
-    }
-    err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect);
-
-    true
+) {
+    let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+    suggestion.add_to_diagnostic(err);
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index c20b96cae2e4f..1410e2b63b0b8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -1,13 +1,14 @@
 //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
 //! to hold.
 
+use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
+use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::ObligationCauseCode;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::ty::TypeVisitor;
@@ -39,12 +40,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             = *parent.code() else {
             return None;
         };
-        let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
         // FIXME: we should point at the lifetime
-        let mut multi_span: MultiSpan = vec![binding_span].into();
-        multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
-        err.span_note(multi_span, "because this has an unmet lifetime requirement");
-        note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+        let multi_span: MultiSpan = vec![binding_span].into();
+        let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
+            unmet_requirements: multi_span,
+            binding_span,
+        };
+
+        let expl = note_and_explain::RegionExplanation::new(
+            self.tcx(),
+            sup,
+            Some(binding_span),
+            note_and_explain::PrefixKind::Empty,
+            note_and_explain::SuffixKind::Continues,
+        );
+        let mut impl_span = None;
+        let mut trait_subdiags = Vec::new();
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
@@ -73,31 +85,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // there aren't trait objects or because none are implicit, then just
                 // write a single note on the impl itself.
 
-                let impl_span = self.tcx().def_span(*impl_def_id);
-                err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+                impl_span = Some(self.tcx().def_span(*impl_def_id));
             } else {
                 // Otherwise, point at all implicit static lifetimes
 
-                err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
                 for span in &traits {
-                    err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
                     // It would be nice to put this immediately under the above note, but they get
                     // pushed to the end.
-                    err.span_suggestion_verbose(
-                        span.shrink_to_hi(),
-                        "consider relaxing the implicit `'static` requirement",
-                        " + '_",
-                        Applicability::MaybeIncorrect,
-                    );
+                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
                 }
             }
         } else {
             // Otherwise just point out the impl.
 
-            let impl_span = self.tcx().def_span(*impl_def_id);
-            err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+            impl_span = Some(self.tcx().def_span(*impl_def_id));
         }
-        let reported = err.emit();
+        let err = MismatchedStaticLifetime {
+            cause_span: cause.span,
+            unmet_lifetime_reqs: multispan_subdiag,
+            expl,
+            impl_note: ImplNote { impl_span },
+            trait_subdiags,
+        };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 6f026678170b7..562246f4e8a1b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -911,8 +911,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
     }
 
-    fn get_visibility(self, id: DefIndex) -> ty::Visibility {
-        self.root.tables.visibility.get(self, id).unwrap().decode(self)
+    fn get_visibility(self, id: DefIndex) -> ty::Visibility<DefId> {
+        self.root
+            .tables
+            .visibility
+            .get(self, id)
+            .unwrap()
+            .decode(self)
+            .map_id(|index| self.local_def_id(index))
     }
 
     fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
@@ -1182,7 +1188,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
 
-    fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator<Item = Visibility> + 'a {
+    fn get_struct_field_visibilities(
+        self,
+        id: DefIndex,
+    ) -> impl Iterator<Item = Visibility<DefId>> + 'a {
         self.root
             .tables
             .children
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 6b447ebd99910..dede1b2122a3c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -210,7 +210,6 @@ provide! { tcx, def_id, other, cdata,
     lookup_const_stability => { table }
     lookup_default_body_stability => { table }
     lookup_deprecation_entry => { table }
-    visibility => { table }
     unused_generic_params => { table }
     opt_def_kind => { table_direct }
     impl_parent => { table }
@@ -225,6 +224,7 @@ provide! { tcx, def_id, other, cdata,
     generator_kind => { table }
     trait_def => { table }
 
+    visibility => { cdata.get_visibility(def_id.index) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
         let _ = cdata;
@@ -485,7 +485,7 @@ impl CStore {
     pub fn struct_field_visibilities_untracked(
         &self,
         def: DefId,
-    ) -> impl Iterator<Item = Visibility> + '_ {
+    ) -> impl Iterator<Item = Visibility<DefId>> + '_ {
         self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
     }
 
@@ -493,7 +493,7 @@ impl CStore {
         self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index)
     }
 
-    pub fn visibility_untracked(&self, def: DefId) -> Visibility {
+    pub fn visibility_untracked(&self, def: DefId) -> Visibility<DefId> {
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 039486ba02c37..b807663b10fd0 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1138,7 +1138,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
             }
             if should_encode_visibility(def_kind) {
-                record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+                let vis =
+                    self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index);
+                record!(self.tables.visibility[def_id] <- vis);
             }
             if should_encode_stability(def_kind) {
                 self.encode_stability(def_id);
@@ -1727,7 +1729,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
-            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
+            let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
+            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- vis);
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 6f849a58580e6..748b3afec37c7 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -338,7 +338,7 @@ define_tables! {
     children: Table<DefIndex, LazyArray<DefIndex>>,
 
     opt_def_kind: Table<DefIndex, DefKind>,
-    visibility: Table<DefIndex, LazyValue<ty::Visibility>>,
+    visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
     def_span: Table<DefIndex, LazyValue<Span>>,
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
     lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
index c8e78747d8e7b..5ff014c7815a9 100644
--- a/compiler/rustc_middle/src/metadata.rs
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -2,6 +2,7 @@ use crate::ty;
 
 use rustc_hir::def::Res;
 use rustc_macros::HashStable;
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -18,7 +19,7 @@ pub struct ModChild {
     /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
     pub res: Res<!>,
     /// Visibility of the item.
-    pub vis: ty::Visibility,
+    pub vis: ty::Visibility<DefId>,
     /// Span of the item.
     pub span: Span,
     /// A proper `macro_rules` item (not a reexport).
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 8e7bacca262e1..4478b45cf1437 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1607,7 +1607,7 @@ rustc_queries! {
         desc { "looking up late bound vars" }
     }
 
-    query visibility(def_id: DefId) -> ty::Visibility {
+    query visibility(def_id: DefId) -> ty::Visibility<DefId> {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index c97156ac17ff6..55ee5bd2f810d 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -42,7 +42,7 @@ impl AssocItem {
     }
 
     #[inline]
-    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
         tcx.visibility(self.def_id)
     }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 262d59f8ff8a7..c2e5decfc786e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -22,6 +22,7 @@ use crate::ty::{
     FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
     ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
     RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+    Visibility,
 };
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -1728,6 +1729,11 @@ impl<'tcx> TyCtxt<'tcx> {
             .chain(self.crates(()).iter().copied())
             .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
     }
+
+    #[inline]
+    pub fn local_visibility(self, def_id: LocalDefId) -> Visibility {
+        self.visibility(def_id.to_def_id()).expect_local()
+    }
 }
 
 /// A trait implemented for all `X<'a>` types that can be safely and
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ee4e8ff50f824..37136ff2ef5d3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -263,11 +263,11 @@ impl fmt::Display for ImplPolarity {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
-pub enum Visibility {
+pub enum Visibility<Id = LocalDefId> {
     /// Visible everywhere (including in other crates).
     Public,
     /// Visible only in the given crate-local module.
-    Restricted(DefId),
+    Restricted(Id),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
@@ -358,28 +358,45 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> {
     }
 }
 
-impl Visibility {
-    /// Returns `true` if an item with this visibility is accessible from the given block.
-    pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
-        let restriction = match self {
-            // Public items are visible everywhere.
-            Visibility::Public => return true,
-            // Restricted items are visible in an arbitrary local module.
-            Visibility::Restricted(other) if other.krate != module.krate => return false,
-            Visibility::Restricted(module) => module,
-        };
+impl<Id> Visibility<Id> {
+    pub fn is_public(self) -> bool {
+        matches!(self, Visibility::Public)
+    }
+
+    pub fn map_id<OutId>(self, f: impl FnOnce(Id) -> OutId) -> Visibility<OutId> {
+        match self {
+            Visibility::Public => Visibility::Public,
+            Visibility::Restricted(id) => Visibility::Restricted(f(id)),
+        }
+    }
+}
+
+impl<Id: Into<DefId>> Visibility<Id> {
+    pub fn to_def_id(self) -> Visibility<DefId> {
+        self.map_id(Into::into)
+    }
 
-        tree.is_descendant_of(module, restriction)
+    /// Returns `true` if an item with this visibility is accessible from the given module.
+    pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool {
+        match self {
+            // Public items are visible everywhere.
+            Visibility::Public => true,
+            Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()),
+        }
     }
 
     /// Returns `true` if this visibility is at least as accessible as the given visibility
-    pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
-        let vis_restriction = match vis {
-            Visibility::Public => return self == Visibility::Public,
-            Visibility::Restricted(module) => module,
-        };
+    pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool {
+        match vis {
+            Visibility::Public => self.is_public(),
+            Visibility::Restricted(id) => self.is_accessible_from(id, tree),
+        }
+    }
+}
 
-        self.is_accessible_from(vis_restriction, tree)
+impl Visibility<DefId> {
+    pub fn expect_local(self) -> Visibility {
+        self.map_id(|id| id.expect_local())
     }
 
     // Returns `true` if this item is visible anywhere in the local crate.
@@ -389,10 +406,6 @@ impl Visibility {
             Visibility::Restricted(def_id) => def_id.is_local(),
         }
     }
-
-    pub fn is_public(self) -> bool {
-        matches!(self, Visibility::Public)
-    }
 }
 
 /// The crate variances map is computed during typeck and contains the
@@ -1861,7 +1874,7 @@ pub enum VariantDiscr {
 pub struct FieldDef {
     pub did: DefId,
     pub name: Symbol,
-    pub vis: Visibility,
+    pub vis: Visibility<DefId>,
 }
 
 impl PartialEq for FieldDef {
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index ca24c0d1ce386..9c8dc30e2db3f 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,4 +1,4 @@
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIndex};
 use rustc_index::vec::{Idx, IndexVec};
 
 use crate::middle::exported_symbols::ExportedSymbol;
@@ -60,7 +60,7 @@ trivially_parameterized_over_tcx! {
     ty::ImplPolarity,
     ty::ReprOptions,
     ty::TraitDef,
-    ty::Visibility,
+    ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
     ty::fast_reject::SimplifiedTypeGen<DefId>,
     rustc_ast::Attribute,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 763038c52d7fa..7f992c18a18e4 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1036,7 +1036,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             VarBindingForm {
                                 binding_mode,
                                 opt_ty_info,
-                                opt_match_place: Some((Some(place), span)),
+                                opt_match_place: Some((None, span)),
                                 pat_span: span,
                             },
                         )))))
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index d2f93b679acc5..7e09efe5972a3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -202,6 +202,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
         let mut ty = self.typeck_results.node_type(pat.hir_id);
+        let mut span = pat.span;
 
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
@@ -262,6 +263,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             hir::PatKind::Binding(_, id, ident, ref sub) => {
+                if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
+                    span = span.with_hi(ident_span.hi());
+                }
+
                 let bm = *self
                     .typeck_results
                     .pat_binding_modes()
@@ -326,7 +331,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
         };
 
-        Box::new(Pat { span: pat.span, ty, kind })
+        Box::new(Pat { span, ty, kind })
     }
 
     fn lower_tuple_subpats(
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ba69bc23118b2..b2966f0d21801 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,6 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(associated_type_defaults)]
 #![feature(control_flow_enum)]
+#![feature(let_else)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
@@ -334,7 +335,9 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
         _kind: &str,
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
-        self.min = VL::new_min(self, def_id);
+        if let Some(def_id) = def_id.as_local() {
+            self.min = VL::new_min(self, def_id);
+        }
         ControlFlow::CONTINUE
     }
 }
@@ -342,7 +345,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
 trait VisibilityLike: Sized {
     const MAX: Self;
     const SHALLOW: bool = false;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self;
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self;
 
     // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
@@ -357,8 +360,8 @@ trait VisibilityLike: Sized {
 }
 impl VisibilityLike for ty::Visibility {
     const MAX: Self = ty::Visibility::Public;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        min(find.tcx.visibility(def_id), find.min, find.tcx)
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
 impl VisibilityLike for Option<AccessLevel> {
@@ -373,15 +376,8 @@ impl VisibilityLike for Option<AccessLevel> {
     // both "shallow" version of its self type and "shallow" version of its trait if it exists
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        cmp::min(
-            if let Some(def_id) = def_id.as_local() {
-                find.access_levels.map.get(&def_id).copied()
-            } else {
-                Self::MAX
-            },
-            find.min,
-        )
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        cmp::min(find.access_levels.map.get(&def_id).copied(), find.min)
     }
 }
 
@@ -511,15 +507,15 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.def_id);
-            let vis = self.tcx.visibility(item_id.def_id);
+            let vis = self.tcx.local_visibility(item_id.def_id);
             self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
-                if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
+                if export.vis.is_accessible_from(defining_mod, self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
                         if let Some(def_id) = def_id.as_local() {
-                            let vis = self.tcx.visibility(def_id.to_def_id());
+                            let vis = self.tcx.local_visibility(def_id);
                             self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
                         }
                     }
@@ -542,7 +538,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
             DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update(def_id, level);
                 }
             }
@@ -554,7 +550,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             DefKind::Macro(_) => {
                 let item = self.tcx.hir().expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
-                    if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                    if vis.is_accessible_from(module, self.tcx) {
                         self.update(def_id, level);
                     }
                 }
@@ -565,7 +561,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             // hygiene these don't need to be marked reachable. The contents of
             // the module, however may be reachable.
             DefKind::Mod => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update_macro_reachable(def_id, module);
                 }
             }
@@ -579,8 +575,8 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                     {
                         for field in struct_def.fields() {
                             let def_id = self.tcx.hir().local_def_id(field.hir_id);
-                            let field_vis = self.tcx.visibility(def_id);
-                            if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                            let field_vis = self.tcx.local_visibility(def_id);
+                            if field_vis.is_accessible_from(module, self.tcx) {
                                 self.reach(def_id, level).ty();
                             }
                         }
@@ -654,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+                        || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                     {
                         self.update(impl_item_ref.id.def_id, item_level);
                     }
@@ -682,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
+                    if self.tcx.visibility(foreign_item.id.def_id).is_public() {
                         self.update(foreign_item.id.def_id, item_level);
                     }
                 }
@@ -1117,7 +1113,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
     }
 
     fn item_is_accessible(&self, did: DefId) -> bool {
-        self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx)
+        self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx)
     }
 
     // Take node-id of an expression or pattern and check its type for privacy.
@@ -1609,8 +1605,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
                         if self.access_levels.is_reachable(impl_item_ref.id.def_id)
-                            || self.tcx.visibility(impl_item_ref.id.def_id)
-                                == ty::Visibility::Public
+                            || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                         {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
@@ -1780,17 +1775,17 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
             );
         }
 
-        let hir_id = match def_id.as_local() {
-            Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id),
-            None => return false,
+        let Some(local_def_id) = def_id.as_local() else {
+            return false;
         };
 
-        let vis = self.tcx.visibility(def_id);
+        let vis = self.tcx.local_visibility(local_def_id);
         if !vis.is_at_least(self.required_visibility, self.tcx) {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
             let vis_descr = match vis {
                 ty::Visibility::Public => "public",
                 ty::Visibility::Restricted(vis_def_id) => {
-                    if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
+                    if vis_def_id == self.tcx.parent_module(hir_id) {
                         "private"
                     } else if vis_def_id.is_top_level_module() {
                         "crate-private"
@@ -1906,7 +1901,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
     pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(id.def_id);
+        let item_visibility = tcx.local_visibility(id.def_id);
         let def_kind = tcx.def_kind(id.def_id);
 
         match def_kind {
@@ -1957,7 +1952,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
                     for foreign_item in items {
-                        let vis = tcx.visibility(foreign_item.id.def_id);
+                        let vis = tcx.local_visibility(foreign_item.id.def_id);
                         self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
                     }
                 }
@@ -1972,7 +1967,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
                     for field in struct_def.fields() {
                         let def_id = tcx.hir().local_def_id(field.hir_id);
-                        let field_visibility = tcx.visibility(def_id);
+                        let field_visibility = tcx.local_visibility(def_id);
                         self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
                     }
                 }
@@ -1992,7 +1987,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                     }
                     for impl_item_ref in impl_.items {
                         let impl_item_vis = if impl_.of_trait.is_none() {
-                            min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+                            min(tcx.local_visibility(impl_item_ref.id.def_id), impl_vis, tcx)
                         } else {
                             impl_vis
                         };
@@ -2019,8 +2014,11 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
-    let def_id = def_id.expect_local();
+fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> {
+    local_visibility(tcx, def_id.expect_local()).to_def_id()
+}
+
+fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
     match tcx.resolutions(()).visibilities.get(&def_id) {
         Some(vis) => *vis,
         None => {
@@ -2037,7 +2035,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                 | Node::Item(hir::Item {
                     kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
                     ..
-                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()),
+                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
@@ -2050,7 +2048,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                                 tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id");
                                 ty::Visibility::Public
                             },
-                            |def_id| tcx.visibility(def_id),
+                            |def_id| tcx.visibility(def_id).expect_local(),
                         ),
                         _ => span_bug!(impl_item.span, "the parent is not a trait impl"),
                     }
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index bafc6b0a08233..d7599a56c0b66 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -21,6 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.8"
 tracing = "0.1"
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index d7732cb1825b1..0bc811eb04412 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -148,3 +148,5 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
         });
     }
 }
+
+impl<'ctx> rustc_type_ir::HashStableContext for StableHashingContext<'ctx> {}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 51e8c24b9c25a..9cb735b36856c 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -39,24 +39,26 @@ use std::ptr;
 
 type Res = def::Res<NodeId>;
 
-impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a>
+    for (Module<'a>, ty::Visibility<Id>, Span, LocalExpnId)
+{
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Module(self.0),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
     }
 }
 
-impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, false),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -70,7 +72,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroE
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, true),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -260,7 +262,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         self.r.visibilities[&def_id.expect_local()]
                     }
                     // Otherwise, the visibility is restricted to the nearest parent `mod` item.
-                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                    _ => ty::Visibility::Restricted(
+                        self.parent_scope.module.nearest_parent_mod().expect_local(),
+                    ),
                 })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
@@ -311,7 +315,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                             } else {
                                 let vis = ty::Visibility::Restricted(res.def_id());
                                 if self.r.is_accessible_from(vis, parent_scope.module) {
-                                    Ok(vis)
+                                    Ok(vis.expect_local())
                                 } else {
                                     Err(VisResolutionError::AncestorOnly(path.span))
                                 }
@@ -649,7 +653,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         true,
                         // The whole `use` item
                         item,
-                        ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                        ty::Visibility::Restricted(
+                            self.parent_scope.module.nearest_parent_mod().expect_local(),
+                        ),
                         root_span,
                     );
                 }
@@ -765,10 +771,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 if let Some(ctor_node_id) = vdata.ctor_id() {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
-                    let mut ctor_vis = if vis == ty::Visibility::Public
+                    let mut ctor_vis = if vis.is_public()
                         && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                        ty::Visibility::Restricted(CRATE_DEF_ID)
                     } else {
                         vis
                     };
@@ -785,7 +791,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         if ctor_vis.is_at_least(field_vis, &*self.r) {
                             ctor_vis = field_vis;
                         }
-                        ret_fields.push(field_vis);
+                        ret_fields.push(field_vis.to_def_id());
                     }
                     let ctor_def_id = self.r.local_def_id(ctor_node_id);
                     let ctor_res = Res::Def(
@@ -795,7 +801,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.visibilities.insert(ctor_def_id, ctor_vis);
 
-                    self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields));
+                    self.r
+                        .struct_constructors
+                        .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields));
                 }
             }
 
@@ -867,8 +875,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         }
         .map(|module| {
             let used = self.process_macro_use_imports(item, module);
-            let binding =
-                (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+            let vis = ty::Visibility::<LocalDefId>::Public;
+            let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas);
             (used, Some(ModuleOrUniformRoot::Module(module)), binding)
         })
         .unwrap_or((true, None, self.r.dummy_binding));
@@ -1117,7 +1125,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))),
+                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
                 used: Cell::new(false),
             })
         };
@@ -1263,7 +1271,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
-                ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                ty::Visibility::Restricted(CRATE_DEF_ID)
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
@@ -1294,7 +1302,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 }
                 _ => self.resolve_visibility(&item.vis),
             };
-            if vis != ty::Visibility::Public {
+            if !vis.is_public() {
                 self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
@@ -1507,10 +1515,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         self.r.visibilities.insert(def_id, vis);
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
-        let ctor_vis = if vis == ty::Visibility::Public
+        let ctor_vis = if vis.is_public()
             && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
         {
-            ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+            ty::Visibility::Restricted(CRATE_DEF_ID)
         } else {
             vis
         };
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b84a610833ddf..2287aa1eb2567 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -6,6 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::ty;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
 use rustc_span::symbol::{kw, Ident};
@@ -26,6 +27,8 @@ use Determinacy::*;
 use Namespace::*;
 use RibKind::*;
 
+type Visibility = ty::Visibility<LocalDefId>;
+
 impl<'a> Resolver<'a> {
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
@@ -424,8 +427,7 @@ impl<'a> Resolver<'a> {
                 let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
                 let ok = |res, span, arenas| {
                     Ok((
-                        (res, ty::Visibility::Public, span, LocalExpnId::ROOT)
-                            .to_name_binding(arenas),
+                        (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas),
                         Flags::empty(),
                     ))
                 };
@@ -438,7 +440,7 @@ impl<'a> Resolver<'a> {
                         {
                             let binding = (
                                 Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                ty::Visibility::Public,
+                                Visibility::Public,
                                 attr.span,
                                 expn_id,
                             )
@@ -841,9 +843,8 @@ impl<'a> Resolver<'a> {
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
-                        let binding =
-                            (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT)
-                                .to_name_binding(self.arenas);
+                        let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT)
+                            .to_name_binding(self.arenas);
                         return Ok(binding);
                     } else if ident.name == kw::Super || ident.name == kw::SelfLower {
                         // FIXME: Implement these with renaming requirements so that e.g.
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 27745cee52df7..c133c272bac27 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -214,7 +214,7 @@ impl<'a> Resolver<'a> {
         binding: &'a NameBinding<'a>,
         import: &'a Import<'a>,
     ) -> &'a NameBinding<'a> {
-        let import_vis = import.expect_vis();
+        let import_vis = import.expect_vis().to_def_id();
         let vis = if binding.vis.is_at_least(import_vis, self)
             || pub_use_of_private_extern_crate_hack(import, binding)
         {
@@ -227,7 +227,7 @@ impl<'a> Resolver<'a> {
             if vis == import_vis
                 || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
             {
-                max_vis.set(Some(vis))
+                max_vis.set(Some(vis.expect_local()))
             }
         }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index aaa9ae6f32513..f7b7313d1049d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -648,7 +648,7 @@ pub struct NameBinding<'a> {
     ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>,
     expansion: LocalExpnId,
     span: Span,
-    vis: ty::Visibility,
+    vis: ty::Visibility<DefId>,
 }
 
 pub trait ToNameBinding<'a> {
@@ -1012,7 +1012,7 @@ pub struct Resolver<'a> {
     /// Table for mapping struct IDs into struct constructor IDs,
     /// it's not used during normal resolution, only for better error reporting.
     /// Also includes of list of each fields visibility
-    struct_constructors: DefIdMap<(Res, ty::Visibility, Vec<ty::Visibility>)>,
+    struct_constructors: DefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
     /// Features enabled for this crate.
     active_features: FxHashSet<Symbol>,
@@ -1808,7 +1808,11 @@ impl<'a> Resolver<'a> {
         self.pat_span_map.insert(node, span);
     }
 
-    fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
+    fn is_accessible_from(
+        &self,
+        vis: ty::Visibility<impl Into<DefId>>,
+        module: Module<'a>,
+    ) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod(), self)
     }
 
@@ -1862,10 +1866,8 @@ impl<'a> Resolver<'a> {
                     self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.expect_module(crate_id.as_def_id());
-                Some(
-                    (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
-                        .to_name_binding(self.arenas),
-                )
+                let vis = ty::Visibility::<LocalDefId>::Public;
+                Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas))
             }
         })
     }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index a1533fe46b3ef..ceb6b6c68b055 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -305,6 +305,12 @@ impl DefId {
     }
 }
 
+impl From<LocalDefId> for DefId {
+    fn from(local: LocalDefId) -> DefId {
+        local.to_def_id()
+    }
+}
+
 impl<E: Encoder> Encodable<E> for DefId {
     default fn encode(&self, s: &mut E) {
         self.krate.encode(s);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 9b8bb9e36201c..efdb1ace13992 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1895,9 +1895,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         // FIXME(compiler-errors): This could be generalized, both to
                         // be more granular, and probably look past other `#[fundamental]`
                         // types, too.
-                        self.tcx
-                            .visibility(def.did())
-                            .is_accessible_from(body_id.owner.to_def_id(), self.tcx)
+                        self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx)
                     } else {
                         true
                     }
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 5488bca8f471d..da30344ef7ec0 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -23,6 +23,9 @@ pub mod sty;
 pub use codec::*;
 pub use sty::*;
 
+/// Needed so we can use #[derive(HashStable_Generic)]
+pub trait HashStableContext {}
+
 pub trait Interner {
     type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
@@ -295,6 +298,7 @@ rustc_index::newtype_index! {
     /// is the outer fn.
     ///
     /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
+    #[derive(HashStable_Generic)]
     pub struct DebruijnIndex {
         DEBUG_FORMAT = "DebruijnIndex({})",
         const INNERMOST = 0,
@@ -366,7 +370,7 @@ impl DebruijnIndex {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum IntTy {
     Isize,
     I8,
@@ -413,7 +417,7 @@ impl IntTy {
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum UintTy {
     Usize,
     U8,
@@ -460,7 +464,7 @@ impl UintTy {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum FloatTy {
     F32,
     F64,
@@ -597,7 +601,7 @@ impl UnifyKey for FloatVid {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -666,30 +670,6 @@ impl Variance {
     }
 }
 
-impl<CTX> HashStable<CTX> for DebruijnIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.as_u32().hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for IntTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for UintTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for FloatTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl<CTX> HashStable<CTX> for InferTy {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         use InferTy::*;
@@ -703,12 +683,6 @@ impl<CTX> HashStable<CTX> for InferTy {
     }
 }
 
-impl<CTX> HashStable<CTX> for Variance {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl fmt::Debug for IntVarValue {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -811,6 +785,7 @@ rustc_index::newtype_index! {
     /// declared, but a type name in a non-zero universe is a placeholder
     /// type -- an idealized representative of "types in general" that we
     /// use for checking generic functions.
+    #[derive(HashStable_Generic)]
     pub struct UniverseIndex {
         DEBUG_FORMAT = "U{}",
     }
@@ -850,9 +825,3 @@ impl UniverseIndex {
         self.private < other.private
     }
 }
-
-impl<CTX> HashStable<CTX> for UniverseIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.private.hash_stable(ctx, hasher);
-    }
-}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 74737e30bb4d3..26e48d2d2147e 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -3,7 +3,6 @@
 use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
 use std::{fmt, hash};
 
-use crate::DebruijnIndex;
 use crate::FloatTy;
 use crate::IntTy;
 use crate::Interner;
@@ -11,6 +10,7 @@ use crate::TyDecoder;
 use crate::TyEncoder;
 use crate::UintTy;
 use crate::UniverseIndex;
+use crate::{DebruijnIndex, HashStableContext};
 
 use self::RegionKind::*;
 use self::TyKind::*;
@@ -774,7 +774,7 @@ where
 
 // This is not a derived impl because a derive would require `I: HashStable`
 #[allow(rustc::usage_of_ty_tykind)]
-impl<CTX, I: Interner> HashStable<CTX> for TyKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for TyKind<I>
 where
     I::AdtDef: HashStable<CTX>,
     I::DefId: HashStable<CTX>,
@@ -1286,7 +1286,7 @@ where
 }
 
 // This is not a derived impl because a derive would require `I: HashStable`
-impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I>
 where
     I::EarlyBoundRegion: HashStable<CTX>,
     I::BoundRegion: HashStable<CTX>,
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index d078252ebd4e2..e1d55ff82cbad 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
-                        sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                         // Skip suggestions for unstable public fields (for example `Pin::pointer`)
                         && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
 
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index e4141647d7d2d..0e6a8ef8265b2 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1729,9 +1729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let private_fields: Vec<&ty::FieldDef> = variant
                 .fields
                 .iter()
-                .filter(|field| {
-                    !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
-                })
+                .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx))
                 .collect();
 
             if !private_fields.is_empty() {
@@ -2343,7 +2341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
                 def.non_enum_variant().fields.iter().any(|field| {
                     field.ident(self.tcx) == ident
-                        && field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                 })
             } else if let ty::Tuple(tys) = output_ty.kind()
                 && let Ok(idx) = ident.as_str().parse::<usize>()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 124ac5c24fa5c..8065b848ad6f8 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1161,7 +1161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => None,
         });
         if let Some((field, field_ty)) = field_receiver {
-            let scope = tcx.parent_module(self.body_id).to_def_id();
+            let scope = tcx.parent_module(self.body_id);
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 9096fc442d493..9fb915a056ab6 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1397,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .iter()
                 .copied()
                 .filter(|(field, _)| {
-                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx)
                         && !matches!(
                             tcx.eval_stability(field.did, None, DUMMY_SP, None),
                             EvalResult::Deny { .. }
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 1c5efa94bd36a..f921839cf529f 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -41,6 +41,9 @@ pub struct OpenOptions {
     mode: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 pub struct FilePermissions(!);
 
 pub struct FileType(!);
@@ -110,6 +113,11 @@ impl fmt::Debug for FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.0
@@ -344,6 +352,10 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
 }
 
 impl DirBuilder {
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 2dad41bb18fce..95e711737738a 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -67,6 +67,7 @@ features = [
     "psapi",
     "impl-default",
     "timezoneapi",
+    "winbase",
 ]
 
 [dev-dependencies]
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 3a00e258e00e5..0ebabbd5ca5c0 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -197,9 +197,11 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
                 ptr::null_mut(),
             );
 
-            let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize];
-            let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
-            let buf = &mut (*db).ReparseTarget as *mut u16;
+            #[repr(C, align(8))]
+            struct Align8<T>(T);
+            let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
+            let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
+            let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16;
             let mut i = 0;
             // FIXME: this conversion is very hacky
             let v = br"\??\";
@@ -219,7 +221,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
             let res = DeviceIoControl(
                 h as *mut _,
                 FSCTL_SET_REPARSE_POINT,
-                data.as_ptr() as *mut _,
+                db.cast(),
                 (*db).ReparseDataLength + 8,
                 ptr::null_mut(),
                 0,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 980a1485b59b7..c2baea839f638 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1777,7 +1777,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
+pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
     match vis {
         ty::Visibility::Public => Visibility::Public,
         ty::Visibility::Restricted(module) => Visibility::Restricted(module),
@@ -2111,8 +2111,8 @@ fn clean_use_statement<'tcx>(
     // `pub(super)` or higher. If the current module is the top level
     // module, there isn't really a parent module, which makes the results
     // meaningless. In this case, we make sure the answer is `false`.
-    let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
-        && !current_mod.is_top_level_module();
+    let is_visible_from_parent_mod =
+        visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
 
     if pub_underscore {
         if let Some(ref inline) = inline_attr {
diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
index d39145973624f..96716a39a2bfd 100644
--- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
@@ -8,13 +8,13 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     let mut _4: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
     let mut _5: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
     let mut _6: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
-    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
     let mut _9: u32;                     // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84
     let mut _10: u32;                    // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
     scope 1 {
-        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:21
-        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:78
+        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:11
+        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:58
     }
 
     bb0: {
@@ -61,10 +61,10 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     }
 
     bb9: {
-        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
-        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
+        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
         StorageLive(_9);                 // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         _9 = _7;                         // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         StorageLive(_10);                // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
index 6e9a8b4d975fa..6a5021139cf61 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
@@ -15,9 +15,9 @@ fn move_out_by_subslice() -> () {
     let mut _11: std::boxed::Box<i32>;   // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
     scope 1 {
         debug a => _1;                   // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         scope 4 {
-            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         }
     }
     scope 2 {
@@ -77,8 +77,8 @@ fn move_out_by_subslice() -> () {
     bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
         FakeRead(ForLet(None), _1);      // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
-        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
         drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
     }
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index d4f81930843bf..1fd1eb128511b 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -23,7 +23,7 @@ LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
    |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., _] => (),
-   |         ----------- value moved here
+   |         - value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
@@ -32,7 +32,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
    |
 LL |         ref mut foo @ [.., _] => Some(foo),
-   |         --------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -44,7 +44,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5
    |
 LL |         [ref foo @ .., ref bar] => Some(foo),
-   |          ------------ immutable borrow occurs here
+   |          ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -56,7 +56,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5
    |
 LL |         ref foo @ [.., ref bar] => Some(foo),
-   |         ----------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -71,7 +71,7 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         foo @ Some(Test::Foo | Test::Bar) => (),
-   |         ---------------------------------
+   |         ---
    |         |
    |         value moved here
    |         value moved here
@@ -83,7 +83,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
    |
 LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ------------------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -95,7 +95,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5
    |
 LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ----------------------------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -107,7 +107,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5
    |
 LL |         ref foo @ Some(box ref s) => Some(foo),
-   |         ------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -122,7 +122,7 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4])
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
-   |         -------------------------------------
+   |         -
    |         |
    |         value moved here
    |         value moved here
@@ -134,7 +134,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
-   |         ------------------------------------------------- immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -146,7 +146,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
-   |                  ---------- immutable borrow occurs here
+   |                  ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -158,7 +158,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5
    |
 LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
-   |             ----------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -170,7 +170,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5
    |
 LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ------------------------------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -182,7 +182,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5
    |
 LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ----------------------------------------------- mutable borrow occurs here
+   |             --------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -194,7 +194,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5
    |
 LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |         ------------------------------------------------------------ immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
index cfcc62de4383b..2c1b9c10d4660 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
@@ -200,7 +200,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 LL |         match v {
 LL |             &[x @ ..] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -212,7 +212,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ ..] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -224,7 +224,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[x @ .., _] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -236,7 +236,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ .., _] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
index 3249aae8f44a3..346b82a266644 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
@@ -79,7 +79,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(_x, _), _, _] => {}
    |           ^^ value used here after move
@@ -90,7 +90,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (_x, _)] => {}
    |               ^^ value used here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
index c198002265b73..6c6a25c251e70 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
index 8f2da9d203b0d..77702e145df81 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
@@ -79,7 +79,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(ref _x, _), _, _] => {}
    |           ^^^^^^ value borrowed here after move
@@ -90,7 +90,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (ref _x, _)] => {}
    |               ^^^^^^ value borrowed here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -134,7 +134,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
@@ -145,7 +145,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
index 4b27f03dc4589..6cc2c2f7a984c 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
index b0bad6e997887..9add7553afa70 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -34,7 +34,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(ref _x, _), _, _] = a;
    |           ^^^^^^ value borrowed here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (ref _x, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, ref _y @ ..] = a;
-   |             ^^^^^^^^^^^ value borrowed here after partial move
+   |             ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -122,7 +122,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:88:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
@@ -132,7 +132,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:94:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index 1fc2b292b84c7..363effcfe5322 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -34,7 +34,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(_x, _), _, _] = a;
    |           ^^ value used here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (_x, _)] = a;
    |               ^^ value used here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, _y @ ..] = a;
-   |             ^^^^^^^ value used here after partial move
+   |             ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
index b8ac7a3a4469d..f4324110ccb8e 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
@@ -57,7 +57,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [ref first, ref second, ..] = *s;
    |                     ---------- immutable borrow occurs here
 LL |     let [_, ref mut tail @ ..] = *s;
-   |             ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |             ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -67,7 +67,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [.., ref second, ref first] = *s;
    |              ---------- immutable borrow occurs here
 LL |     let [ref mut tail @ .., _] = *s;
-   |          ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -75,9 +75,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10
    |
 LL |     let [_,  ref s1 @ ..] = *s;
-   |              ----------- immutable borrow occurs here
+   |              ------ immutable borrow occurs here
 LL |     let [ref mut s2 @ .., _, _] = *s;
-   |          ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^ mutable borrow occurs here
 LL |     nop_subslice(s1);
    |                  -- immutable borrow later used here
 
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
index d3388e071aa53..f9a63bd49dd57 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
@@ -88,7 +88,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [ref first, ref second, ..] = *s {
    |                        ---------- immutable borrow occurs here
 LL |         if let [_, ref mut tail @ ..] = *s {
-   |                    ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                    ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -98,7 +98,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [.., ref second, ref first] = *s {
    |                 ---------- immutable borrow occurs here
 LL |         if let [ref mut tail @ .., _] = *s {
-   |                 ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -106,9 +106,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17
    |
 LL |     if let [_, _, _, ref s1 @ ..] = *s {
-   |                      ----------- immutable borrow occurs here
+   |                      ------ immutable borrow occurs here
 LL |         if let [ref mut s2 @ .., _, _, _] = *s {
-   |                 ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^ mutable borrow occurs here
 LL |             nop_subslice(s1);
    |                          -- immutable borrow later used here
 
diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
index ff70ba9fcca8b..0ac7df944d781 100644
--- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
+++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
@@ -2,7 +2,7 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5
    |
 LL |         [1, 2, ref tail @ ..] => tail,
-   |                ------------- borrow of `a[_]` occurs here
+   |                -------- borrow of `a[_]` occurs here
 ...
 LL |     a[2] = 0;
    |     ^^^^^^^^ assignment to borrowed `a[_]` occurs here
diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
index ddd89afe5bf91..c3bcb7de65daa 100644
--- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
+++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -14,7 +14,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
    |
 LL |         &mut [ref _b @ ..] => {
-   |               ----------- borrow of `vec[_]` occurs here
+   |               ------ borrow of `vec[_]` occurs here
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
diff --git a/src/test/ui/moves/move-out-of-array-ref.stderr b/src/test/ui/moves/move-out-of-array-ref.stderr
index fd682e56ae1de..0caa0b83a4c7c 100644
--- a/src/test/ui/moves/move-out-of-array-ref.stderr
+++ b/src/test/ui/moves/move-out-of-array-ref.stderr
@@ -13,7 +13,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:13:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
@@ -35,7 +35,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:23:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr
index 9a863bf31a7fb..93b0dcfc2d18a 100644
--- a/src/test/ui/moves/move-out-of-slice-2.stderr
+++ b/src/test/ui/moves/move-out-of-slice-2.stderr
@@ -14,7 +14,7 @@ LL |     match *a {
    |           ^^ cannot move out of here
 LL |
 LL |         [a @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `a` has type `[A]`, which does not implement the `Copy` trait
@@ -26,7 +26,7 @@ LL |     match *b {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, b @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `b` has type `[A]`, which does not implement the `Copy` trait
@@ -38,7 +38,7 @@ LL |     match *c {
    |           ^^ cannot move out of here
 LL |
 LL |         [c @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `c` has type `[C]`, which does not implement the `Copy` trait
@@ -50,7 +50,7 @@ LL |     match *d {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, d @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `d` has type `[C]`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr
index 19f0223a357a5..dcb6f9fec18b6 100644
--- a/src/test/ui/nll/issue-51244.stderr
+++ b/src/test/ui/nll/issue-51244.stderr
@@ -2,7 +2,7 @@ error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
   --> $DIR/issue-51244.rs:3:5
    |
 LL |     let ref my_ref @ _ = 0;
-   |         -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _`
+   |         ---------- help: consider changing this to be a mutable reference: `ref mut my_ref`
 LL |     *my_ref = 0;
    |     ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
 
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 4249a74b3ed62..fad84dda0e192 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -40,9 +40,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
    |
 LL |         Some(ref _y @ _z) => {}
-   |              ^^^^^^^^^--
-   |              |        |
-   |              |        value moved here
+   |              ^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
@@ -55,9 +54,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
    |
 LL |         Some(ref mut _y @ _z) => {}
-   |              ^^^^^^^^^^^^^--
-   |              |            |
-   |              |            value moved here
+   |              ^^^^^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
index ee0885a014aa4..a481ca4683382 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
    |
 LL | fn f(a @ A(u): A) -> Box<u8> {
-   |      ^^^^^^-^
-   |      |     |
-   |      |     value partially moved here
+   |      ^     - value partially moved here
+   |      |
    |      value used here after partial move
    |
    = note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index 8e00bf5c328be..83751843b1b81 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:11:9
    |
 LL |     let a @ b = U;
-   |         ^^^^-   - move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^   -   - move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |   |
    |         |   value moved here
    |         value used here after move
@@ -11,9 +11,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:13:9
    |
 LL |     let a @ (b, c) = (U, U);
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -22,9 +21,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:15:9
    |
 LL |     let a @ (b, c) = (u(), u());
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -35,9 +33,8 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |         -------^-
-   |         |      |
-   |         |      value used here after move
+   |         -      ^ value used here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -46,18 +43,16 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |                     --------^-
-   |                     |       |
-   |                     |       value used here after move
+   |                     -       ^ value used here after move
+   |                     |
    |                     value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:25:9
    |
 LL |         xs @ [a, .., b] => {}
-   |         ^^^^^^^^^^^^^-^
-   |         |            |
-   |         |            value partially moved here
+   |         ^^           - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -66,9 +61,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:29:9
    |
 LL |         xs @ [_, ys @ .., _] => {}
-   |         ^^^^^^^^^-------^^^^
-   |         |        |
-   |         |        value partially moved here
+   |         ^^       -- value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -77,7 +71,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:22:12
    |
 LL |     fn fun(a @ b: U) {}
-   |            ^^^^-
+   |            ^----
    |            |   |
    |            |   value moved here
    |            value used here after move
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 4b2048855ebb4..002c7609f6109 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -74,9 +74,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
    |
 LL |     let ref a @ box b = Box::new(NC);
-   |         ^^^^^^^^^^^^-
-   |         |           |
-   |         |           value moved here
+   |         ^^^^^       - value moved here
+   |         |
    |         value borrowed here after move
    |
    = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
@@ -85,9 +84,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -97,9 +95,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -109,9 +106,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -121,9 +117,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
    |
 LL |         ref mut a @ box ref b => {
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             drop(b);
@@ -133,9 +128,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
-   |           ^^^^^^^^^^^^^^^^-----
-   |           |               |
-   |           |               immutable borrow occurs here
+   |           ^^^^^^^^^       ----- immutable borrow occurs here
+   |           |
    |           mutable borrow occurs here
 ...
 LL |         drop(b);
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index bc2c1625fd0ef..a9e66de084242 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -262,9 +262,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -273,9 +272,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -286,10 +284,7 @@ error[E0382]: use of moved value
 LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
@@ -297,9 +292,8 @@ error[E0382]: borrow of moved value
 LL |     match Some([U, U]) {
    |           ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: borrow of moved value
@@ -308,9 +302,8 @@ error[E0382]: borrow of moved value
 LL |     match Some(u()) {
    |           --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
 LL |         a @ Some(ref b) => {}
-   |         ---------^^^^^-
-   |         |        |
-   |         |        value borrowed here after move
+   |         -        ^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -319,10 +312,7 @@ error[E0382]: use of moved value
 LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
@@ -330,18 +320,16 @@ error[E0382]: borrow of moved value
 LL |     match Some([u(), u()]) {
    |           ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |           ^^^^^^^^^^^^^^^^^^^^-------------^
-   |           |                   |
-   |           |                   value partially moved here
+   |           ^^^^^               ----- value partially moved here
+   |           |
    |           value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index c019aae3dfc9c..e03a9298214e4 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -237,9 +237,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -248,7 +247,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
    |
 LL |     let ref a @ b = u();
-   |         ^^^^^^^^-   --- move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^^^^^   -   --- move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |       |
    |         |       value moved here
    |         value borrowed here after move
@@ -257,9 +256,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                  ^^^^^^^^-----
-   |                  |       |
-   |                  |       value moved here
+   |                  ^^^^^   ----- value moved here
+   |                  |
    |                  value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -268,9 +266,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                                 ^^^^^^^^-
-   |                                 |       |
-   |                                 |       value moved here
+   |                                 ^^^^^   - value moved here
+   |                                 |
    |                                 value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -279,9 +276,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -290,9 +286,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                       ^^^^^^^^-----
-   |                       |       |
-   |                       |       value moved here
+   |                       ^^^^^   ----- value moved here
+   |                       |
    |                       value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -305,9 +300,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                                      ^^^^^^^^-
-   |                                      |       |
-   |                                      |       value moved here
+   |                                      ^^^^^   - value moved here
+   |                                      |
    |                                      value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -320,7 +314,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
    |
 LL |     fn f1(ref a @ b: U) {}
-   |           ^^^^^^^^-
+   |           ^^^^^----
    |           |       |
    |           |       value moved here
    |           value borrowed here after move
@@ -330,9 +324,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                    ^^^^^^^^-----
-   |                    |       |
-   |                    |       value moved here
+   |                    ^^^^^   ----- value moved here
+   |                    |
    |                    value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -341,9 +334,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                                   ^^^^^^^^-
-   |                                   |       |
-   |                                   |       value moved here
+   |                                   ^^^^^   - value moved here
+   |                                   |
    |                                   value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -352,9 +344,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
-   |           ^^^^^^^^^^^^^^^^-----^
-   |           |               |
-   |           |               value partially moved here
+   |           ^^^^^^^^^       ----- value partially moved here
+   |           |
    |           value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 2ae78d1084e0e..9fd5e229afd0a 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -298,9 +298,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
    |
 LL |         ref mut z @ &mut Some(ref a) => {
-   |         ----------------------^^^^^-
-   |         |                     |
-   |         |                     immutable borrow occurs here
+   |         ---------             ^^^^^ immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             **z = None;
@@ -310,9 +309,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
    |
 LL |     let ref mut a @ ref b = u();
-   |         ^^^^^^^^^^^^-----
-   |         |           |
-   |         |           immutable borrow occurs here
+   |         ^^^^^^^^^   ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -322,9 +320,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
    |
 LL |     let ref a @ ref mut b = u();
-   |         ^^^^^^^^---------
-   |         |       |
-   |         |       mutable borrow occurs here
+   |         ^^^^^   --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = u();
@@ -334,9 +331,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |         -----------^^^^^^^^^-
-   |         |          |
-   |         |          mutable borrow occurs here
+   |         -----      ^^^^^^^^^ mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -346,9 +342,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |                                 ------------^^^^^^^^^-
-   |                                 |           |
-   |                                 |           mutable borrow occurs here
+   |                                 -----       ^^^^^^^^^ mutable borrow occurs here
+   |                                 |
    |                                 immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -406,9 +401,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -418,9 +412,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -430,9 +423,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 LL |
 LL |     *b = U;
@@ -442,7 +434,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
-   |                      --------^^^^^^^^^^^^-
+   |                      --------^^^^^^^^^----
    |                      |       |           |
    |                      |       |           value moved here
    |                      |       value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index aa02230419b5e..e47aea9c77e6c 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -262,9 +262,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -274,9 +273,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     *b = U;
@@ -286,9 +284,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -298,9 +295,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -310,9 +306,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -322,9 +317,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -334,7 +328,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
-   |                      ------------^^^^^^^^^^^^-
+   |                      ------------^^^^^^^^^----
    |                      |           |           |
    |                      |           |           value moved here
    |                      |           value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index d290144b6155a..cd3234952fa54 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/copy-and-move-mixed.rs:12:9
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
-   |         ^^^^^^^^^^------------^
-   |         |         |
-   |         |         value partially moved here
+   |         ^         - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index d78faa682b507..840a513d6c67d 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -48,7 +48,7 @@ error[E0382]: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
    |
 LL |     let ref mut a @ b = NotCopy;
-   |         ^^^^^^^^^^^^-   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+   |         ^^^^^^^^^   -   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
    |         |           |
    |         |           value moved here
    |         value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
index 3180bd0afc104..70beb5d423223 100644
--- a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
+++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
@@ -11,7 +11,7 @@ error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutab
   --> $DIR/nested-binding-modes-mut.rs:9:5
    |
 LL |     let not_mut @ mut is_mut = 42;
-   |         -------------------- help: consider changing this to be mutable: `mut not_mut`
+   |         ------- help: consider changing this to be mutable: `mut not_mut`
 LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index 5beca04d28590..bac2db6ce825c 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -35,7 +35,7 @@ error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as
   --> $DIR/borrowck-move-ref-pattern.rs:13:16
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- immutable borrow occurs here
+   |                             ----------- immutable borrow occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                ^^^^^^^^^^^ mutable borrow occurs here
@@ -47,7 +47,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:29
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                             ^^^ move out of `arr[..]` occurs here
@@ -59,7 +59,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:34
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                                  ^^^^^^^ move out of `arr[..]` occurs here
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 74f7df611778e..4e68d6810e29b 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 if adt.is_struct();
                 let variant = adt.non_enum_variant();
                 if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
-                let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
+                let module_did = cx.tcx.parent_module(stmt.hir_id);
                 if variant
                     .fields
                     .iter()
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 9ca443b7dff6c..23c86482b46cb 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
     self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
-    Ty, TyCtxt, Visibility,
+    Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -464,7 +464,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
         if let ty::Adt(adt, substs) = ty.kind();
-        if cx.tcx.visibility(adt.did()) == Visibility::Public;
+        if cx.tcx.visibility(adt.did()).is_public();
         if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);