From 0c6077984f944193c457fc41ee6777c6f359c4f4 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 12 Apr 2024 16:16:40 +0000
Subject: [PATCH 01/22] Avoid an intermediate Option and just create the
 resulting enum directly

---
 compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 64b816553dff9..7dcaa16b6ffa0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -301,18 +301,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 formal_input_ty,
                 coerced_ty,
             );
-            let subtyping_error = match supertype_error {
+
+            // If neither check failed, the types are compatible
+            match supertype_error {
                 Ok(InferOk { obligations, value: () }) => {
                     self.register_predicates(obligations);
-                    None
+                    Compatibility::Compatible
                 }
-                Err(err) => Some(err),
-            };
-
-            // If neither check failed, the types are compatible
-            match subtyping_error {
-                None => Compatibility::Compatible,
-                Some(_) => Compatibility::Incompatible(subtyping_error),
+                Err(err) => Compatibility::Incompatible(Some(err)),
             }
         };
 

From 24653a56640305a64d31da8f87c4575112ff7184 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 12 Apr 2024 16:17:31 +0000
Subject: [PATCH 02/22] Remove a HACK by instead inferring opaque types during
 expected/formal type checking

---
 .../rustc_hir_typeck/src/fn_ctxt/_impl.rs     | 26 -------------------
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    |  2 +-
 2 files changed, 1 insertion(+), 27 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index f1e82543a993a..681af1a14c2c7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -711,32 +711,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let formal_ret = self.resolve_vars_with_obligations(formal_ret);
         let ret_ty = expected_ret.only_has_type(self)?;
 
-        // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
-        // Without it, the inference
-        // variable will get instantiated with the opaque type. The inference variable often
-        // has various helpful obligations registered for it that help closures figure out their
-        // signature. If we infer the inference var to the opaque type, the closure won't be able
-        // to find those obligations anymore, and it can't necessarily find them from the opaque
-        // type itself. We could be more powerful with inference if we *combined* the obligations
-        // so that we got both the obligations from the opaque type and the ones from the inference
-        // variable. That will accept more code than we do right now, so we need to carefully consider
-        // the implications.
-        // Note: this check is pessimistic, as the inference type could be matched with something other
-        // than the opaque type, but then we need a new `TypeRelation` just for this specific case and
-        // can't re-use `sup` below.
-        // See tests/ui/impl-trait/hidden-type-is-opaque.rs and
-        // tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
-        if formal_ret.has_infer_types() {
-            for ty in ret_ty.walk() {
-                if let ty::GenericArgKind::Type(ty) = ty.unpack()
-                    && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
-                    && self.can_define_opaque_ty(def_id)
-                {
-                    return None;
-                }
-            }
-        }
-
         let expect_args = self
             .fudge_inference_if_ok(|| {
                 let ocx = ObligationCtxt::new(self);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 7dcaa16b6ffa0..13226d304c8f0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // 3. Check if the formal type is a supertype of the checked one
             //    and register any such obligations for future type checks
             let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
-                DefineOpaqueTypes::No,
+                DefineOpaqueTypes::Yes,
                 formal_input_ty,
                 coerced_ty,
             );

From e4f4e58dc3c20617f4a245a38237ed5fe0224911 Mon Sep 17 00:00:00 2001
From: JeanCASPAR <55629512+JeanCASPAR@users.noreply.github.com>
Date: Sun, 24 Mar 2024 12:43:53 +0000
Subject: [PATCH 03/22] Port build_reduce_graph

---
 compiler/rustc_resolve/messages.ftl           |  60 ++++++-
 .../rustc_resolve/src/build_reduced_graph.rs  |  63 ++-----
 compiler/rustc_resolve/src/diagnostics.rs     |   2 +-
 compiler/rustc_resolve/src/errors.rs          | 161 +++++++++++++++++-
 4 files changed, 235 insertions(+), 51 deletions(-)

diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index a03bb6acd41a7..b26cf9aa3363d 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -11,6 +11,8 @@ resolve_added_macro_use =
 resolve_ancestor_only =
     visibilities can only be restricted to ancestor modules
 
+resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here
+
 resolve_associated_const_with_similar_name_exists =
     there is an associated constant with a similar name
 
@@ -20,6 +22,10 @@ resolve_associated_fn_with_similar_name_exists =
 resolve_associated_type_with_similar_name_exists =
     there is an associated type with a similar name
 
+resolve_attempt_to_define_builtin_macro_twice =
+    attempted to define built-in macro more than once
+    .note = previously defined here
+
 resolve_attempt_to_use_non_constant_value_in_constant =
     attempt to use a non-constant value in a constant
 
@@ -32,6 +38,8 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
 resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
     this would need to be a `{$suggestion}`
 
+resolve_bad_macro_import = bad macro import
+
 resolve_binding_in_never_pattern =
     never patterns cannot contain variable bindings
     .suggestion = use a wildcard `_` instead
@@ -100,13 +108,31 @@ resolve_const_param_in_non_trivial_anon_const =
 resolve_const_param_in_ty_of_const_param =
     const parameters may not be used in the type of const parameters
 
-resolve_expected_found =
+resolve_elided_anonymous_lifetime_report_error =
+    `&` without an explicit lifetime name cannot be used here
+    .label = explicit lifetime name needed here
+
+resolve_elided_anonymous_lifetime_report_error_suggestion =
+    consider introducing a higher-ranked lifetime here
+
+resolve_expected_module_found =
     expected module, found {$res} `{$path_str}`
     .label = not a module
 
+resolve_explicit_anonymous_lifetime_report_error =
+    `'_` cannot be used here
+    .label = `'_` is a reserved lifetime name
+
 resolve_explicit_unsafe_traits =
     unsafe traits like `{$ident}` should be implemented explicitly
 
+resolve_extern_crate_loading_macro_not_at_crate_root =
+    an `extern crate` loading macros must be at the crate root
+
+resolve_extern_crate_self_requires_renaming =
+    `extern crate self;` requires renaming
+    .suggestion = rename the `self` crate to be able to import it
+
 resolve_forward_declared_generic_param =
     generic parameters with a default cannot use forward declared identifiers
     .label = defaulted generic parameters cannot be forward declared
@@ -135,17 +161,20 @@ resolve_generic_params_from_outer_item_static = a `static` is a separate item fr
 
 resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
 
-
 resolve_ident_bound_more_than_once_in_parameter_list =
     identifier `{$identifier}` is bound more than once in this parameter list
     .label = used as parameter more than once
 
+resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here
+
 resolve_ident_bound_more_than_once_in_same_pattern =
     identifier `{$identifier}` is bound more than once in the same pattern
     .label = used in a pattern more than once
 
 resolve_imported_crate = `$crate` may not be imported
 
+resolve_imported_macro_not_found = imported macro not found
+
 resolve_imports_cannot_refer_to =
     imports cannot refer to {$what}
 
@@ -183,11 +212,22 @@ resolve_lowercase_self =
 resolve_macro_defined_later =
     a macro with the same name exists, but it appears later at here
 
+resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments =
+    macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+
 resolve_macro_expected_found =
     expected {$expected}, found {$found} `{$macro_path}`
 
+resolve_macro_extern_deprecated =
+    `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
+    .help = try an outer attribute: `#[macro_use]`
+
 resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
 
+resolve_macro_use_name_already_in_use =
+    `{$name}` is already in scope
+    .note = macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
+
 resolve_method_not_member_of_trait =
     method `{$method}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
@@ -217,6 +257,8 @@ resolve_param_in_ty_of_const_param =
     the type of const parameters must not depend on other generic parameters
     .label = the type must not depend on the parameter `{$name}`
 
+resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}`
+
 resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
     .help = you can define integration tests in a directory named `tests`
 
@@ -254,6 +296,9 @@ resolve_self_in_generic_param_default =
     generic parameters cannot use `Self` in their defaults
     .label = `Self` in generic parameter default
 
+resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$ident}`
+    .label = 'static is a reserved lifetime name
+
 resolve_tool_module_imported =
     cannot use a tool module through an import
     .note = the tool module imported here
@@ -284,12 +329,18 @@ resolve_undeclared_label =
     use of undeclared label `{$name}`
     .label = undeclared label `{$name}`
 
+resolve_underscore_lifetime_is_reserved = `'_` cannot be used here
+    .label = `'_` is a reserved lifetime name
+
 resolve_unexpected_res_change_ty_to_const_param_sugg =
     you might have meant to write a const parameter here
 
 resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg =
     if you meant to collect the rest of the slice in `{$ident}`, use the at operator
 
+resolve_unnamed_crate_root_import =
+    crate root imports need to be explicitly named: `use crate as name;`
+
 resolve_unreachable_label =
     use of unreachable label `{$name}`
     .label = unreachable label `{$name}`
@@ -312,3 +363,8 @@ resolve_variable_bound_with_different_mode =
     variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
     .label = bound in different ways
     .first_binding_span = first binding
+
+resolve_variable_is_not_bound_in_all_patterns =
+    variable `{$name}` is not bound in all patterns
+
+resolve_variable_not_in_all_patterns = variable not in all patterns
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 375f20dd809f2..1b6387acf71e2 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -19,7 +19,6 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability};
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@@ -529,11 +528,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 }
 
                 if ident.name == kw::Crate {
-                    self.r.dcx().span_err(
-                        ident.span,
-                        "crate root imports need to be explicitly named: \
-                         `use crate as name;`",
-                    );
+                    self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span });
                 }
 
                 let kind = ImportKind::Single {
@@ -848,16 +843,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         let expansion = parent_scope.expansion;
 
         let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
-            self.r
-                .dcx()
-                .struct_span_err(item.span, "`extern crate self;` requires renaming")
-                .with_span_suggestion(
-                    item.span,
-                    "rename the `self` crate to be able to import it",
-                    "extern crate self as name;",
-                    Applicability::HasPlaceholders,
-                )
-                .emit();
+            self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp });
             return;
         } else if orig_name == Some(kw::SelfLower) {
             Some(self.r.graph_root)
@@ -897,9 +883,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         if parent == self.r.graph_root {
             if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
                 if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
-                    let msg = "macro-expanded `extern crate` items cannot \
-                                       shadow names passed with `--extern`";
-                    self.r.dcx().span_err(item.span, msg);
+                    self.r.dcx().emit_err(
+                        errors::MacroExpandedExternCrateCannotShadowExternArguments {
+                            span: item.span,
+                        },
+                    );
                     // `return` is intended to discard this binding because it's an
                     // unregistered ambiguity error which would result in a panic
                     // caused by inconsistency `path_res`
@@ -1030,10 +1018,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         allow_shadowing: bool,
     ) {
         if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
-            let msg = format!("`{name}` is already in scope");
-            let note =
-                "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
-            self.r.dcx().struct_span_err(span, msg).with_note(note).emit();
+            self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name });
         }
     }
 
@@ -1044,13 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         for attr in &item.attrs {
             if attr.has_name(sym::macro_use) {
                 if self.parent_scope.module.parent.is_some() {
-                    struct_span_code_err!(
-                        self.r.dcx(),
-                        item.span,
-                        E0468,
-                        "an `extern crate` loading macros must be at the crate root"
-                    )
-                    .emit();
+                    self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot {
+                        span: item.span,
+                    });
                 }
                 if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
                     if orig_name == kw::SelfLower {
@@ -1058,7 +1039,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     }
                 }
                 let ill_formed = |span| {
-                    struct_span_code_err!(self.r.dcx(), span, E0466, "bad macro import").emit();
+                    self.r.dcx().emit_err(errors::BadMacroImport { span });
                 };
                 match attr.meta() {
                     Some(meta) => match meta.kind {
@@ -1143,13 +1124,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                         allow_shadowing,
                     );
                 } else {
-                    struct_span_code_err!(
-                        self.r.dcx(),
-                        ident.span,
-                        E0469,
-                        "imported macro not found"
-                    )
-                    .emit();
+                    self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span });
                 }
             }
         }
@@ -1160,18 +1135,16 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
     fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
             if attr.has_name(sym::macro_escape) {
-                let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
-                let mut err = self.r.dcx().struct_span_warn(attr.span, msg);
-                if let ast::AttrStyle::Inner = attr.style {
-                    err.help("try an outer attribute: `#[macro_use]`");
-                }
-                err.emit();
+                let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner).then_some(());
+                self.r
+                    .dcx()
+                    .emit_warn(errors::MacroExternDeprecated { span: attr.span, inner_attribute });
             } else if !attr.has_name(sym::macro_use) {
                 continue;
             }
 
             if !attr.is_word() {
-                self.r.dcx().span_err(attr.span, "arguments to `macro_use` are not allowed here");
+                self.r.dcx().emit_err(errors::ArgumentsMacroUseNotAllowed { span: attr.span });
             }
             return true;
         }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4057bc9ffbd07..1a14558468dd2 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1005,7 +1005,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
             ),
             VisResolutionError::ExpectedFound(span, path_str, res) => {
-                self.dcx().create_err(errs::ExpectedFound { span, res, path_str })
+                self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
             }
             VisResolutionError::Indeterminate(span) => {
                 self.dcx().create_err(errs::Indeterminate(span))
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 5eee6a51fd2da..665abc2b06729 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,4 +1,5 @@
-use rustc_errors::{codes::*, Applicability};
+#![allow(dead_code)] // TODO : non
+use rustc_errors::{codes::*, Applicability, MultiSpan};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{
     symbol::{Ident, Symbol},
@@ -495,8 +496,8 @@ pub(crate) struct Relative2018 {
 pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span);
 
 #[derive(Diagnostic)]
-#[diag(resolve_expected_found, code = E0577)]
-pub(crate) struct ExpectedFound {
+#[diag(resolve_expected_module_found, code = E0577)]
+pub(crate) struct ExpectedModuleFound {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
@@ -801,3 +802,157 @@ pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg {
     pub ident: Ident,
     pub snippet: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(resolve_extern_crate_loading_macro_not_at_crate_root, code = E0468)]
+pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_bad_macro_import, code = E0466)]
+pub(crate) struct BadMacroImport {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_extern_crate_self_requires_renaming)]
+pub(crate) struct ExternCrateSelfRequiresRenaming {
+    #[primary_span]
+    #[suggestion(code = "extern crate self as name;", applicability = "has-placeholders")]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_macro_use_name_already_in_use)]
+#[note]
+pub(crate) struct MacroUseNameAlreadyInUse {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_imported_macro_not_found, code = E0469)]
+pub(crate) struct ImportedMacroNotFound {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_macro_extern_deprecated)]
+pub(crate) struct MacroExternDeprecated {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[help]
+    pub inner_attribute: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_arguments_macro_use_not_allowed)]
+pub(crate) struct ArgumentsMacroUseNotAllowed {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_unnamed_crate_root_import)]
+pub(crate) struct UnnamedCrateRootImport {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)]
+pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)]
+pub(crate) struct ElidedAnonymousLivetimeReportError {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    resolve_elided_anonymous_lifetime_report_error_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion {
+    #[suggestion_part(code = "for<'a> ")]
+    pub(crate) lo: Span,
+    #[suggestion_part(code = "'a ")]
+    pub(crate) hi: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)]
+pub(crate) struct ExplicitAnonymousLivetimeReportError {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_implicit_elided_lifetimes_not_allowed_here, code = E0726)]
+pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_underscore_lifetime_is_reserved, code = E0637)]
+pub(crate) struct UnderscoreLifetimeIsReserved {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_static_lifetime_is_reserved, code = E0262)]
+pub(crate) struct StaticLifetimeIsReserved {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) lifetime: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_attempt_to_define_builtin_macro_twice, code = E0773)]
+pub(crate) struct AttemptToDefineBuiltinMacroTwice {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[note]
+    pub(crate) note_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_variable_is_not_bound_in_all_patterns, code = E0408)]
+pub(crate) struct VariableIsNotBoundInAllPatterns {
+    #[primary_span]
+    pub(crate) multispan: MultiSpan,
+    pub(crate) name: Symbol,
+}
+
+#[derive(Subdiagnostic, Debug, Clone)]
+#[label(resolve_pattern_doesnt_bind_name)]
+pub(crate) struct PatternDoesntBindName {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) name: Symbol,
+}
+
+#[derive(Subdiagnostic, Debug, Clone)]
+#[label(resolve_variable_not_in_all_patterns)]
+pub(crate) struct VariableNotInAllPatterns {
+    #[primary_span]
+    pub(crate) span: Span,
+}
\ No newline at end of file

From 4226dc2045717ba8570e56c446557ce808b10916 Mon Sep 17 00:00:00 2001
From: Jean CASPAR <jean.caspar67610@gmail.com>
Date: Sun, 24 Mar 2024 15:11:27 +0000
Subject: [PATCH 04/22] Migrate some diagnostics

---
 compiler/rustc_resolve/messages.ftl       |  2 +-
 compiler/rustc_resolve/src/diagnostics.rs | 22 ++++---
 compiler/rustc_resolve/src/errors.rs      |  3 +-
 compiler/rustc_resolve/src/late.rs        | 77 +++++++++--------------
 compiler/rustc_resolve/src/macros.rs      | 14 ++---
 5 files changed, 48 insertions(+), 70 deletions(-)

diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index b26cf9aa3363d..c737ad86e466b 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -296,7 +296,7 @@ resolve_self_in_generic_param_default =
     generic parameters cannot use `Self` in their defaults
     .label = `Self` in generic parameter default
 
-resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$ident}`
+resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}`
     .label = 'static is a reserved lifetime name
 
 resolve_tool_module_imported =
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 1a14558468dd2..a367a5f21db2d 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -29,8 +29,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
 
-use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
-use crate::errors::{
+use crate::errors::{self,
+    AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion,
     ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition,
     MaybeMissingMacroRulesName,
 };
@@ -677,18 +677,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let origin_sp = origin.iter().copied().collect::<Vec<_>>();
 
                 let msp = MultiSpan::from_spans(target_sp.clone());
-                let mut err = struct_span_code_err!(
-                    self.dcx(),
-                    msp,
-                    E0408,
-                    "variable `{}` is not bound in all patterns",
+                let mut err = self.dcx().create_err(errors::VariableIsNotBoundInAllPatterns {
+                    multispan: msp,
                     name,
-                );
+                });
                 for sp in target_sp {
-                    err.span_label(sp, format!("pattern doesn't bind `{name}`"));
+                    err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName {
+                        span: sp,
+                        name,
+                    });
                 }
                 for sp in origin_sp {
-                    err.span_label(sp, "variable not in all patterns");
+                    err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns {
+                        span: sp,
+                    });
                 }
                 if could_be_path {
                     let import_suggestions = self.lookup_import_candidates(
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 665abc2b06729..9a140f98c7fb8 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,4 +1,3 @@
-#![allow(dead_code)] // TODO : non
 use rustc_errors::{codes::*, Applicability, MultiSpan};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{
@@ -955,4 +954,4 @@ pub(crate) struct PatternDoesntBindName {
 pub(crate) struct VariableNotInAllPatterns {
     #[primary_span]
     pub(crate) span: Span,
-}
\ No newline at end of file
+}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 49b4a6efd3c3e..ec11bfd96daa7 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -6,8 +6,7 @@
 //! If you wonder why there's no `early.rs`, that's because it's split into three files -
 //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
 
-use crate::errors::ImportsCannotReferTo;
-use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
+use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
 use crate::{BindingKey, Used};
 use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
 use crate::{ResolutionError, Resolver, Segment, UseError};
@@ -17,7 +16,7 @@ use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, DiagArgValue, IntoDiagArg, StashKey,
+    codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey,
 };
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
@@ -1666,18 +1665,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     );
                 }
                 LifetimeRibKind::AnonymousReportError => {
-                    let (msg, note) = if elided {
-                        (
-                            "`&` without an explicit lifetime name cannot be used here",
-                            "explicit lifetime name needed here",
-                        )
-                    } else {
-                        ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
-                    };
-                    let mut diag =
-                        struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,);
-                    diag.span_label(lifetime.ident.span, note);
                     if elided {
+                        let mut suggestion = None;
                         for rib in self.lifetime_ribs[i..].iter().rev() {
                             if let LifetimeRibKind::Generics {
                                 span,
@@ -1685,19 +1674,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                                 ..
                             } = &rib.kind
                             {
-                                diag.multipart_suggestion(
-                                    "consider introducing a higher-ranked lifetime here",
-                                    vec![
-                                        (span.shrink_to_lo(), "for<'a> ".into()),
-                                        (lifetime.ident.span.shrink_to_hi(), "'a ".into()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                );
+                                suggestion =
+                                    Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
+                                        lo: span.shrink_to_lo(),
+                                        hi: lifetime.ident.span.shrink_to_hi(),
+                                    });
                                 break;
                             }
                         }
-                    }
-                    diag.emit();
+                        self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
+                            span: lifetime.ident.span,
+                            suggestion,
+                        });
+                    } else {
+                        self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError {
+                            span: lifetime.ident.span,
+                        });
+                    };
                     self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
                     return;
                 }
@@ -1863,13 +1856,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     //     async fn foo(_: std::cell::Ref<u32>) { ... }
                     LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
                     | LifetimeRibKind::AnonymousWarn(_) => {
+                        let mut err =
+                            self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere {
+                                span: path_span,
+                            });
                         let sess = self.r.tcx.sess;
-                        let mut err = struct_span_code_err!(
-                            sess.dcx(),
-                            path_span,
-                            E0726,
-                            "implicit elided lifetime not allowed here"
-                        );
                         rustc_errors::add_elided_lifetime_in_path_suggestion(
                             sess.source_map(),
                             &mut err,
@@ -2313,7 +2304,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let report_error = |this: &Self, ns| {
                 if this.should_report_errs() {
                     let what = if ns == TypeNS { "type parameters" } else { "local variables" };
-                    this.r.dcx().emit_err(ImportsCannotReferTo { span: ident.span, what });
+                    this.r.dcx().emit_err(errors::ImportsCannotReferTo { span: ident.span, what });
                 }
             };
 
@@ -2633,29 +2624,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             }
 
             if param.ident.name == kw::UnderscoreLifetime {
-                struct_span_code_err!(
-                    self.r.dcx(),
-                    param.ident.span,
-                    E0637,
-                    "`'_` cannot be used here"
-                )
-                .with_span_label(param.ident.span, "`'_` is a reserved lifetime name")
-                .emit();
+                self.r
+                    .dcx()
+                    .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
                 // Record lifetime res, so lowering knows there is something fishy.
                 self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
             if param.ident.name == kw::StaticLifetime {
-                struct_span_code_err!(
-                    self.r.dcx(),
-                    param.ident.span,
-                    E0262,
-                    "invalid lifetime parameter name: `{}`",
-                    param.ident,
-                )
-                .with_span_label(param.ident.span, "'static is a reserved lifetime name")
-                .emit();
+                self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
+                    span: param.ident.span,
+                    lifetime: param.ident,
+                });
                 // Record lifetime res, so lowering knows there is something fishy.
                 self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index dbca2f9895d20..bedf79400e36b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -14,7 +14,7 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{codes::*, struct_span_code_err, Applicability, StashKey};
+use rustc_errors::{Applicability, StashKey};
 use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
@@ -916,14 +916,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         rule_spans = Vec::new();
                     }
                     BuiltinMacroState::AlreadySeen(span) => {
-                        struct_span_code_err!(
-                            self.dcx(),
-                            item.span,
-                            E0773,
-                            "attempted to define built-in macro more than once"
-                        )
-                        .with_span_note(span, "previously defined here")
-                        .emit();
+                        self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice {
+                            span: item.span,
+                            note_span: span,
+                        });
                     }
                 }
             } else {

From cec9f7f71659360e66933d4fb782d37938d00f09 Mon Sep 17 00:00:00 2001
From: Jean CASPAR <jean.caspar67610@gmail.com>
Date: Sun, 24 Mar 2024 21:53:18 +0000
Subject: [PATCH 05/22] Migrate more diagnostics

---
 compiler/rustc_resolve/messages.ftl       | 106 +++++++++
 compiler/rustc_resolve/src/diagnostics.rs | 273 +++++++++++-----------
 compiler/rustc_resolve/src/errors.rs      | 267 +++++++++++++++++++++
 compiler/rustc_resolve/src/late.rs        |   4 +-
 compiler/rustc_resolve/src/macros.rs      |  61 +++--
 5 files changed, 537 insertions(+), 174 deletions(-)

diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index c737ad86e466b..95592b1c1dd6f 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -38,6 +38,9 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
 resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
     this would need to be a `{$suggestion}`
 
+resolve_attributes_starting_with_rustc_are_reserved =
+    attributes starting with `rustc` are reserved for use by the `rustc` compiler
+
 resolve_bad_macro_import = bad macro import
 
 resolve_binding_in_never_pattern =
@@ -70,12 +73,19 @@ resolve_cannot_determine_macro_resolution =
     cannot determine resolution for the {$kind} `{$path}`
     .note = import resolution is stuck, try simplifying macro imports
 
+resolve_cannot_find_builtin_macro_with_name =
+    cannot find a built-in macro with name `{$ident}`
+
 resolve_cannot_find_ident_in_this_scope =
     cannot find {$expected} `{$ident}` in this scope
 
 resolve_cannot_glob_import_possible_crates =
     cannot glob-import all possible crates
 
+resolve_cannot_use_through_an_import =
+    cannot use {$article} {$descr} through an import
+    .note = the {$descr} imported here
+
 resolve_change_import_binding =
     you can use `as` to change the binding name of the import
 
@@ -88,6 +98,12 @@ resolve_consider_adding_macro_export =
 resolve_consider_declaring_with_pub =
     consider declaring type or module `{$ident}` with `pub`
 
+resolve_consider_making_the_field_public =
+    { $number_of_fields ->
+        [one] consider making the field publicly accessible
+        *[other] consider making the fields publicly accessible
+    }
+
 resolve_consider_marking_as_pub =
     consider marking `{$ident}` as `pub` in the imported module
 
@@ -108,6 +124,9 @@ resolve_const_param_in_non_trivial_anon_const =
 resolve_const_param_in_ty_of_const_param =
     const parameters may not be used in the type of const parameters
 
+resolve_constructor_private_if_any_field_private =
+    a constructor is private if any of the fields is private
+
 resolve_elided_anonymous_lifetime_report_error =
     `&` without an explicit lifetime name cannot be used here
     .label = explicit lifetime name needed here
@@ -133,10 +152,20 @@ resolve_extern_crate_self_requires_renaming =
     `extern crate self;` requires renaming
     .suggestion = rename the `self` crate to be able to import it
 
+resolve_failed_resolve_unresolve_import = failed to resolve: unresolved import
+
+resolve_failed_resolve_unresolve_import_label = unresolved import
+
 resolve_forward_declared_generic_param =
     generic parameters with a default cannot use forward declared identifiers
     .label = defaulted generic parameters cannot be forward declared
 
+resolve_found_an_item_configured_out =
+    found an item that was configured out
+
+resolve_generic_arguments_in_macro_path =
+    generic arguments in macro path
+
 resolve_generic_params_from_outer_item =
     can't use {$is_self ->
         [true] `Self`
@@ -171,6 +200,12 @@ resolve_ident_bound_more_than_once_in_same_pattern =
     identifier `{$identifier}` is bound more than once in the same pattern
     .label = used in a pattern more than once
 
+resolve_ident_imported_here_but_it_is_desc =
+    `{$imported_ident}` is imported here, but it is {$imported_ident_desc}
+
+resolve_ident_in_scope_but_it_is_desc =
+    `{$imported_ident}` is in scope, but it is {$imported_ident_desc}
+
 resolve_imported_crate = `$crate` may not be imported
 
 resolve_imported_macro_not_found = imported macro not found
@@ -190,6 +225,13 @@ resolve_is_not_directly_importable =
     `{$target}` is not directly importable
     .label = cannot be imported directly
 
+resolve_is_private =
+    {$ident_descr} `{$ident}` is private
+    .label = private {$ident_descr}
+
+resolve_item_was_behind_feature =
+    the item is gated behind the `{$feature}` feature
+
 resolve_items_in_traits_are_not_importable =
     items in traits are not importable
 
@@ -217,6 +259,7 @@ resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments =
 
 resolve_macro_expected_found =
     expected {$expected}, found {$found} `{$macro_path}`
+    .label = not {$article} {$expected}
 
 resolve_macro_extern_deprecated =
     `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
@@ -237,11 +280,45 @@ resolve_missing_macro_rules_name = maybe you have forgotten to define a name for
 resolve_module_only =
     visibility must resolve to a module
 
+resolve_name_defined_multiple_time =
+    the name `{$name}` is defined multiple times
+    .note = `{$name}` must be defined only once in the {$descr} namespace of this {$container}
+
+resolve_name_defined_multiple_time_old_binding_definition =
+    previous definition of the {$old_kind} `{$name}` here
+
+resolve_name_defined_multiple_time_old_binding_import =
+    previous import of the {$old_kind} `{$name}` here
+
+resolve_name_defined_multiple_time_redefined =
+    `{$name}` redefined here
+
+resolve_name_defined_multiple_time_reimported =
+    `{$name}` reimported here
+
 resolve_name_is_already_used_as_generic_parameter =
     the name `{$name}` is already used for a generic parameter in this item's generic parameters
     .label = already used
     .first_use_of_name = first use of `{$name}`
 
+resolve_name_reserved_in_attribute_namespace =
+    name `{$ident}` is reserved in attribute namespace
+
+resolve_note_and_refers_to_the_item_defined_here =
+    {$first ->
+        [true] {$dots ->
+            [true] the {$binding_descr} `{$binding_name}` is defined here...
+            *[false] the {$binding_descr} `{$binding_name}` is defined here
+        }
+        *[false] {$dots ->
+            [true] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here...
+            *[false] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here
+        }
+    }
+
+resolve_outer_ident_is_not_publicly_reexported =
+    {$outer_ident_descr} `{$outer_ident}` is not publicly re-exported
+
 resolve_param_in_enum_discriminant =
     generic parameters may not be used in enum discriminant values
     .label = cannot perform const operation using `{$name}`
@@ -275,6 +352,8 @@ resolve_relative_2018 =
 resolve_remove_surrounding_derive =
     remove from the surrounding `derive()`
 
+resolve_remove_unnecessary_import = remove unnecessary import
+
 resolve_self_import_can_only_appear_once_in_the_list =
     `self` import can only appear once in an import list
     .label = can only appear once in an import list
@@ -296,13 +375,33 @@ resolve_self_in_generic_param_default =
     generic parameters cannot use `Self` in their defaults
     .label = `Self` in generic parameter default
 
+resolve_similarly_named_defined_here =
+    similarly named {$candidate_descr} `{$candidate}` defined here
+
+resolve_single_item_defined_here =
+    {$candidate_descr} `{$candidate}` defined here
+
 resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}`
     .label = 'static is a reserved lifetime name
 
+resolve_suggestion_import_ident_directly =
+    import `{$ident}` directly
+
+resolve_suggestion_import_ident_through_reexport =
+    import `{$ident}` through the re-export
+
 resolve_tool_module_imported =
     cannot use a tool module through an import
     .note = the tool module imported here
 
+resolve_tool_only_accepts_identifiers =
+    `{$tool}` only accepts identifiers
+    .label = not an identifier
+
+resolve_tool_was_already_registered =
+    tool `{$tool}` was already registered
+    .label = already registered here
+
 resolve_trait_impl_duplicate =
     duplicate definitions with name `{$name}`:
     .label = duplicate definition
@@ -368,3 +467,10 @@ resolve_variable_is_not_bound_in_all_patterns =
     variable `{$name}` is not bound in all patterns
 
 resolve_variable_not_in_all_patterns = variable not in all patterns
+
+resolve_you_could_import_this_desc = you could import this {$desc}
+
+resolve_trait_impl_mismatch =
+    item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
+    .label = does not match trait
+    .trait_impl_mismatch_label_item = item in trait
\ No newline at end of file
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index a367a5f21db2d..12484462f82f4 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -6,8 +6,8 @@ use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, Diag,
-    DiagCtxt, ErrorGuaranteed, MultiSpan, SuggestionStyle,
+    codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt,
+    ErrorGuaranteed, MultiSpan, SuggestionStyle,
 };
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
@@ -29,10 +29,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
 
-use crate::errors::{self,
-    AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion,
-    ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition,
-    MaybeMissingMacroRulesName,
+use crate::errors::{
+    self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
+    ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, MaybeMissingMacroRulesName,
 };
 use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
@@ -226,16 +225,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ModuleKind::Block => "block",
         };
 
-        let old_noun = match old_binding.is_import_user_facing() {
-            true => "import",
-            false => "definition",
-        };
-
-        let new_participle = match new_binding.is_import_user_facing() {
-            true => "imported",
-            false => "defined",
-        };
-
         let (name, span) =
             (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
 
@@ -254,35 +243,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             (TypeNS, _) => "type",
         };
 
-        let msg = format!("the name `{name}` is defined multiple times");
-
-        let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
-            (true, true) => struct_span_code_err!(self.dcx(), span, E0259, "{}", msg),
+        let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
+            (true, true) => E0259,
             (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
-                true => struct_span_code_err!(self.dcx(), span, E0254, "{}", msg),
-                false => struct_span_code_err!(self.dcx(), span, E0260, "{}", msg),
+                true => E0254,
+                false => E0260,
             },
             _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
-                (false, false) => struct_span_code_err!(self.dcx(), span, E0428, "{}", msg),
-                (true, true) => struct_span_code_err!(self.dcx(), span, E0252, "{}", msg),
-                _ => struct_span_code_err!(self.dcx(), span, E0255, "{}", msg),
+                (false, false) => E0428,
+                (true, true) => E0252,
+                _ => E0255,
             },
         };
 
-        err.note(format!(
-            "`{}` must be defined only once in the {} namespace of this {}",
-            name,
-            ns.descr(),
-            container
-        ));
-
-        err.span_label(span, format!("`{name}` re{new_participle} here"));
-        if !old_binding.span.is_dummy() && old_binding.span != span {
-            err.span_label(
-                self.tcx.sess.source_map().guess_head_span(old_binding.span),
-                format!("previous {old_noun} of the {old_kind} `{name}` here"),
-            );
-        }
+        let label = match new_binding.is_import_user_facing() {
+            true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name },
+            false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name },
+        };
+
+        let old_binding_label =
+            (!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
+                let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
+                match old_binding.is_import_user_facing() {
+                    true => errors::NameDefinedMultipleTimeOldBindingLabel::Import {
+                        span,
+                        name,
+                        old_kind,
+                    },
+                    false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
+                        span,
+                        name,
+                        old_kind,
+                    },
+                }
+            });
+
+        let mut err = self
+            .dcx()
+            .create_err(errors::NameDefinedMultipleTime {
+                span,
+                descr: ns.descr(),
+                container,
+                label,
+                old_binding_label,
+            })
+            .with_code(code);
 
         // See https://github.com/rust-lang/rust/issues/32354
         use NameBindingKind::Import;
@@ -330,20 +335,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         match import {
             Some((import, span, true)) if should_remove_import && import.is_nested() => {
-                self.add_suggestion_for_duplicate_nested_use(&mut err, import, span)
+                self.add_suggestion_for_duplicate_nested_use(&mut err, import, span);
             }
             Some((import, _, true)) if should_remove_import && !import.is_glob() => {
                 // Simple case - remove the entire import. Due to the above match arm, this can
                 // only be a single use so just remove it entirely.
-                err.tool_only_span_suggestion(
-                    import.use_span_with_attributes,
-                    "remove unnecessary import",
-                    "",
-                    Applicability::MaybeIncorrect,
+                err.subdiagnostic(
+                    self.tcx.dcx(),
+                    errors::ToolOnlyRemoveUnnecessaryImport {
+                        span: import.use_span_with_attributes,
+                    },
                 );
             }
             Some((import, span, _)) => {
-                self.add_suggestion_for_rename_of_use(&mut err, name, import, span)
+                self.add_suggestion_for_rename_of_use(&mut err, name, import, span);
             }
             _ => {}
         }
@@ -444,7 +449,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         binding_span: Span,
     ) {
         assert!(import.is_nested());
-        let message = "remove unnecessary import";
 
         // Two examples will be used to illustrate the span manipulations we're doing:
         //
@@ -460,22 +464,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // previous imports.
         if found_closing_brace {
             if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
-                err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect);
+                err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span });
             } else {
                 // Remove the entire line if we cannot extend the span back, this indicates an
                 // `issue_52891::{self}` case.
-                err.span_suggestion(
-                    import.use_span_with_attributes,
-                    message,
-                    "",
-                    Applicability::MaybeIncorrect,
+                err.subdiagnostic(
+                    self.dcx(),
+                    errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes },
                 );
             }
 
             return;
         }
 
-        err.span_suggestion(span, message, "", Applicability::MachineApplicable);
+        err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span });
     }
 
     pub(crate) fn lint_if_path_starts_with_module(
@@ -571,14 +573,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         resolution_error: ResolutionError<'a>,
     ) -> Diag<'_> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => {
+            ResolutionError::GenericParamsFromOuterItem(
+                outer_res,
+                has_generic_params,
+                def_kind,
+            ) => {
                 use errs::GenericParamsFromOuterItemLabel as Label;
                 let static_or_const = match def_kind {
-                    DefKind::Static{ .. } => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
+                    DefKind::Static { .. } => {
+                        Some(errs::GenericParamsFromOuterItemStaticOrConst::Static)
+                    }
                     DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
                     _ => None,
                 };
-                let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
+                let is_self =
+                    matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
                 let mut err = errs::GenericParamsFromOuterItem {
                     span,
                     label: None,
@@ -677,20 +686,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let origin_sp = origin.iter().copied().collect::<Vec<_>>();
 
                 let msp = MultiSpan::from_spans(target_sp.clone());
-                let mut err = self.dcx().create_err(errors::VariableIsNotBoundInAllPatterns {
-                    multispan: msp,
-                    name,
-                });
+                let mut err = self
+                    .dcx()
+                    .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
                 for sp in target_sp {
-                    err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName {
-                        span: sp,
-                        name,
-                    });
+                    err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name });
                 }
                 for sp in origin_sp {
-                    err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns {
-                        span: sp,
-                    });
+                    err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp });
                 }
                 if could_be_path {
                     let import_suggestions = self.lookup_import_candidates(
@@ -963,17 +966,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 code,
                 trait_item_span,
                 trait_path,
-            } => {
-                self.dcx().struct_span_err(
+            } => self
+                .dcx()
+                .create_err(errors::TraitImplMismatch {
                     span,
-                    format!(
-                        "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
-                    ),
-                )
-                .with_code(code)
-                .with_span_label(span, "does not match trait")
-                .with_span_label(trait_item_span, "item in trait")
-            }
+                    name,
+                    kind,
+                    trait_path,
+                    trait_item_span,
+                })
+                .with_code(code),
             ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
                 .dcx()
                 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
@@ -1534,17 +1536,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 };
                 if let crate::NameBindingKind::Import { import, .. } = binding.kind {
                     if !import.span.is_dummy() {
-                        err.span_note(
-                            import.span,
-                            format!("`{ident}` is imported here, but it is {desc}"),
-                        );
+                        let note = errors::IdentImporterHereButItIsDesc {
+                            span: import.span,
+                            imported_ident: ident,
+                            imported_ident_desc: &desc,
+                        };
+                        err.subdiagnostic(self.tcx.dcx(), note);
                         // Silence the 'unused import' warning we might get,
                         // since this diagnostic already covers that import.
                         self.record_use(ident, binding, Used::Other);
                         return;
                     }
                 }
-                err.note(format!("`{ident}` is in scope, but it is {desc}"));
+                let note = errors::IdentInScopeButItIsDesc {
+                    imported_ident: ident,
+                    imported_ident_desc: &desc,
+                };
+                err.subdiagnostic(self.tcx.dcx(), note);
                 return;
             }
         }
@@ -1584,20 +1592,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 //    |              ^
                 return false;
             }
-            let prefix = match suggestion.target {
-                SuggestionTarget::SimilarlyNamed => "similarly named ",
-                SuggestionTarget::SingleItem => "",
+            let span = self.tcx.sess.source_map().guess_head_span(def_span);
+            let candidate_descr = suggestion.res.descr();
+            let candidate = suggestion.candidate;
+            let label = match suggestion.target {
+                SuggestionTarget::SimilarlyNamed => {
+                    errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
+                }
+                SuggestionTarget::SingleItem => {
+                    errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
+                }
             };
-
-            err.span_label(
-                self.tcx.sess.source_map().guess_head_span(def_span),
-                format!(
-                    "{}{} `{}` defined here",
-                    prefix,
-                    suggestion.res.descr(),
-                    suggestion.candidate,
-                ),
-            );
+            err.subdiagnostic(self.tcx.dcx(), label);
         }
 
         let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
@@ -1751,16 +1757,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
 
         // Print the primary message.
-        let descr = get_descr(binding);
-        let mut err = struct_span_code_err!(
-            self.dcx(),
-            ident.span,
-            E0603,
-            "{} `{}` is private",
-            descr,
-            ident
-        );
-        err.span_label(ident.span, format!("private {descr}"));
+        let ident_descr = get_descr(binding);
+        let mut err =
+            self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
 
         let mut not_publicly_reexported = false;
         if let Some((this_res, outer_ident)) = outermost_res {
@@ -1784,10 +1783,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // If we suggest importing a public re-export, don't point at the definition.
             if point_to_def && ident.span != outer_ident.span {
                 not_publicly_reexported = true;
-                err.span_label(
-                    outer_ident.span,
-                    format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()),
-                );
+                let label = errors::OuterIdentIsNotPubliclyReexported {
+                    span: outer_ident.span,
+                    outer_ident_descr: this_res.descr(),
+                    outer_ident,
+                };
+                err.subdiagnostic(self.tcx.dcx(), label);
             }
         }
 
@@ -1801,18 +1802,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         {
             non_exhaustive = Some(attr.span);
         } else if let Some(span) = ctor_fields_span {
-            err.span_label(span, "a constructor is private if any of the fields is private");
+            let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
+            err.subdiagnostic(self.tcx.dcx(), label);
             if let Res::Def(_, d) = res
                 && let Some(fields) = self.field_visibility_spans.get(&d)
             {
-                err.multipart_suggestion_verbose(
-                    format!(
-                        "consider making the field{} publicly accessible",
-                        pluralize!(fields.len())
-                    ),
-                    fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
-                    Applicability::MaybeIncorrect,
-                );
+                let spans = fields.iter().map(|span| *span).collect();
+                let sugg =
+                    errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
+                err.subdiagnostic(self.tcx.dcx(), sugg);
             }
         }
 
@@ -1895,13 +1893,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
             }
             let first = binding == first_binding;
-            let msg = format!(
-                "{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
-                and_refers_to = if first { "" } else { "...and refers to " },
-                item = get_descr(binding),
-                which = if first { "" } else { " which" },
-                dots = if next_binding.is_some() { "..." } else { "" },
-            );
             let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
             let mut note_span = MultiSpan::from_span(def_span);
             if !first && binding.vis.is_public() {
@@ -1921,7 +1912,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     "cannot be constructed because it is `#[non_exhaustive]`",
                 );
             }
-            err.span_note(note_span, msg);
+            let note = errors::NoteAndRefersToTheItemDefinedHere {
+                span: note_span,
+                binding_descr: get_descr(binding),
+                binding_name: name,
+                first,
+                dots: next_binding.is_some(),
+            };
+            err.subdiagnostic(self.tcx.dcx(), note);
         }
         // We prioritize shorter paths, non-core imports and direct imports over the alternatives.
         sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
@@ -1935,15 +1933,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 continue;
             }
             let path = sugg.join("::");
-            err.span_suggestion_verbose(
-                dedup_span,
-                format!(
-                    "import `{ident}` {}",
-                    if reexport { "through the re-export" } else { "directly" }
-                ),
-                path,
-                Applicability::MachineApplicable,
-            );
+            let sugg = if reexport {
+                errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
+            } else {
+                errors::ImportIdent::Directly { span: dedup_span, ident, path }
+            };
+            err.subdiagnostic(self.tcx.dcx(), sugg);
             break;
         }
 
@@ -2523,13 +2518,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 continue;
             }
 
-            err.span_note(name.span, "found an item that was configured out");
+            let note = errors::FoundItemConfigureOut { span: name.span };
+            err.subdiagnostic(self.tcx.dcx(), note);
 
             if let MetaItemKind::List(nested) = &cfg.kind
                 && let NestedMetaItem::MetaItem(meta_item) = &nested[0]
                 && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
             {
-                err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol));
+                let note = errors::ItemWasBehindFeature { feature: feature_name.symbol };
+                err.subdiagnostic(self.tcx.dcx(), note);
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 9a140f98c7fb8..e1ab5b57c3cca 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,3 +1,4 @@
+#![allow(dead_code)]
 use rustc_errors::{codes::*, Applicability, MultiSpan};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{
@@ -525,8 +526,10 @@ pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span);
 #[diag(resolve_macro_expected_found)]
 pub(crate) struct MacroExpectedFound<'a> {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
     pub(crate) found: &'a str,
+    pub(crate) article: &'static str,
     pub(crate) expected: &'a str,
     pub(crate) macro_path: &'a str,
     #[subdiagnostic]
@@ -955,3 +958,267 @@ pub(crate) struct VariableNotInAllPatterns {
     #[primary_span]
     pub(crate) span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(resolve_name_defined_multiple_time)]
+#[note]
+pub(crate) struct NameDefinedMultipleTime {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) descr: &'static str,
+    pub(crate) container: &'static str,
+    #[subdiagnostic]
+    pub(crate) label: NameDefinedMultipleTimeLabel,
+    #[subdiagnostic]
+    pub(crate) old_binding_label: Option<NameDefinedMultipleTimeOldBindingLabel>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum NameDefinedMultipleTimeLabel {
+    #[label(resolve_name_defined_multiple_time_reimported)]
+    Reimported {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+    },
+    #[label(resolve_name_defined_multiple_time_redefined)]
+    Redefined {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum NameDefinedMultipleTimeOldBindingLabel {
+    #[label(resolve_name_defined_multiple_time_old_binding_import)]
+    Import {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        old_kind: &'static str,
+    },
+    #[label(resolve_name_defined_multiple_time_old_binding_definition)]
+    Definition {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        old_kind: &'static str,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_is_private, code = E0603)]
+pub(crate) struct IsPrivate<'a> {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) ident_descr: &'a str,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_generic_arguments_in_macro_path)]
+pub(crate) struct GenericArgumentsInMacroPath {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_attributes_starting_with_rustc_are_reserved)]
+pub(crate) struct AttributesStartingWithRustcAreReserved {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_use_through_an_import)]
+pub(crate) struct CannotUseThroughAnImport {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) article: &'static str,
+    pub(crate) descr: &'static str,
+    #[note]
+    pub(crate) binding_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_name_reserved_in_attribute_namespace)]
+pub(crate) struct NameReservedInAttributeNamespace {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_find_builtin_macro_with_name)]
+pub(crate) struct CannotFindBuiltinMacroWithName {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_tool_was_already_registered)]
+pub(crate) struct ToolWasAlreadyRegistered {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) tool: Ident,
+    #[label]
+    pub(crate) old_ident_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_tool_only_accepts_identifiers)]
+pub(crate) struct ToolOnlyAcceptsIdentifiers {
+    #[label]
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) tool: Symbol,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum DefinedHere {
+    #[label(resolve_similarly_named_defined_here)]
+    SimilarlyNamed {
+        #[primary_span]
+        span: Span,
+        candidate_descr: &'static str,
+        candidate: Symbol,
+    },
+    #[label(resolve_single_item_defined_here)]
+    SingleItem {
+        #[primary_span]
+        span: Span,
+        candidate_descr: &'static str,
+        candidate: Symbol,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[label(resolve_outer_ident_is_not_publicly_reexported)]
+pub(crate) struct OuterIdentIsNotPubliclyReexported {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) outer_ident_descr: &'static str,
+    pub(crate) outer_ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+#[label(resolve_constructor_private_if_any_field_private)]
+pub(crate) struct ConstructorPrivateIfAnyFieldPrivate {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    resolve_consider_making_the_field_public,
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub(crate) struct ConsiderMakingTheFieldPublic {
+    #[suggestion_part(code = "pub ")]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) number_of_fields: usize,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ImportIdent {
+    #[suggestion(
+        resolve_suggestion_import_ident_through_reexport,
+        code = "{path}",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    ThroughReExport {
+        #[primary_span]
+        span: Span,
+        ident: Ident,
+        path: String,
+    },
+    #[suggestion(
+        resolve_suggestion_import_ident_directly,
+        code = "{path}",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    Directly {
+        #[primary_span]
+        span: Span,
+        ident: Ident,
+        path: String,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_note_and_refers_to_the_item_defined_here)]
+pub(crate) struct NoteAndRefersToTheItemDefinedHere<'a> {
+    #[primary_span]
+    pub(crate) span: MultiSpan,
+    pub(crate) binding_descr: &'a str,
+    pub(crate) binding_name: Ident,
+    pub(crate) first: bool,
+    pub(crate) dots: bool,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(resolve_remove_unnecessary_import, code = "", applicability = "maybe-incorrect")]
+pub(crate) struct RemoveUnnecessaryImport {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    resolve_remove_unnecessary_import,
+    code = "",
+    applicability = "maybe-incorrect",
+    style = "tool-only"
+)]
+pub(crate) struct ToolOnlyRemoveUnnecessaryImport {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_ident_imported_here_but_it_is_desc)]
+pub(crate) struct IdentImporterHereButItIsDesc<'a> {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) imported_ident: Ident,
+    pub(crate) imported_ident_desc: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_ident_in_scope_but_it_is_desc)]
+pub(crate) struct IdentInScopeButItIsDesc<'a> {
+    pub(crate) imported_ident: Ident,
+    pub(crate) imported_ident_desc: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_found_an_item_configured_out)]
+pub(crate) struct FoundItemConfigureOut {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_item_was_behind_feature)]
+pub(crate) struct ItemWasBehindFeature {
+    pub(crate) feature: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_trait_impl_mismatch)]
+pub(crate) struct TraitImplMismatch {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) name: Symbol,
+    pub(crate) kind: &'static str,
+    pub(crate) trait_path: String,
+    #[label(resolve_trait_impl_mismatch_label_item)]
+    pub(crate) trait_item_span: Span,
+}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ec11bfd96daa7..33c9c7fcc6208 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -15,9 +15,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{
-    codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey,
-};
+use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index bedf79400e36b..2a23ed71753fa 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -123,20 +123,18 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
             match nested_meta.ident() {
                 Some(ident) => {
                     if let Some(old_ident) = registered_tools.replace(ident) {
-                        let msg = format!("{} `{}` was already registered", "tool", ident);
-                        tcx.dcx()
-                            .struct_span_err(ident.span, msg)
-                            .with_span_label(old_ident.span, "already registered here")
-                            .emit();
+                        tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered {
+                            span: ident.span,
+                            tool: ident,
+                            old_ident_span: old_ident.span,
+                        });
                     }
                 }
                 None => {
-                    let msg = format!("`{}` only accepts identifiers", sym::register_tool);
-                    let span = nested_meta.span();
-                    tcx.dcx()
-                        .struct_span_err(span, msg)
-                        .with_span_label(span, "not an identifier")
-                        .emit();
+                    tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers {
+                        span: nested_meta.span(),
+                        tool: sym::register_tool,
+                    });
                 }
             }
         }
@@ -485,13 +483,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Report errors for the resolved macro.
         for segment in &path.segments {
             if let Some(args) = &segment.args {
-                self.dcx().span_err(args.span(), "generic arguments in macro path");
+                self.dcx().emit_err(errors::GenericArgumentsInMacroPath { span: args.span() });
             }
             if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") {
-                self.dcx().span_err(
-                    segment.ident.span,
-                    "attributes starting with `rustc` are reserved for use by the `rustc` compiler",
-                );
+                self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved {
+                    span: segment.ident.span,
+                });
             }
         }
 
@@ -535,6 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let mut err = MacroExpectedFound {
                 span: path.span,
                 expected,
+                article,
                 found: res.descr(),
                 macro_path: &path_str,
                 remove_surrounding_derive: None,
@@ -550,10 +548,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str });
             }
 
-            self.dcx()
-                .create_err(err)
-                .with_span_label(path.span, format!("not {article} {expected}"))
-                .emit();
+            self.dcx().emit_err(err);
 
             return Ok((self.dummy_ext(kind), Res::Err));
         }
@@ -872,13 +867,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) {
         if let Some(Res::NonMacroAttr(kind)) = res {
             if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
-                let msg =
-                    format!("cannot use {} {} through an import", kind.article(), kind.descr());
-                let mut err = self.dcx().struct_span_err(span, msg);
-                if let Some(binding) = binding {
-                    err.span_note(binding.span, format!("the {} imported here", kind.descr()));
-                }
-                err.emit();
+                let binding_span = binding.map(|binding| binding.span);
+                self.dcx().emit_err(errors::CannotUseThroughAnImport {
+                    span,
+                    article: kind.article(),
+                    descr: kind.descr(),
+                    binding_span,
+                });
             }
         }
     }
@@ -889,10 +884,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if ident.name == sym::cfg || ident.name == sym::cfg_attr {
             let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
-                self.dcx().span_err(
-                    ident.span,
-                    format!("name `{ident}` is reserved in attribute namespace"),
-                );
+                self.dcx()
+                    .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident });
             }
         }
     }
@@ -923,8 +916,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
             } else {
-                let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
-                self.dcx().span_err(item.span, msg);
+                self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName {
+                    span: item.span,
+                    ident: item.ident,
+                });
             }
         }
 

From 992c5050217d93e3e07002fa978c152447d71910 Mon Sep 17 00:00:00 2001
From: Jean CASPAR <jean.caspar67610@gmail.com>
Date: Sat, 13 Apr 2024 14:02:10 +0100
Subject: [PATCH 06/22] Reorder error messages

---
 compiler/rustc_resolve/messages.ftl  | 19 ++++++-------------
 compiler/rustc_resolve/src/errors.rs |  1 -
 2 files changed, 6 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 95592b1c1dd6f..f824e4faf5d06 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -152,10 +152,6 @@ resolve_extern_crate_self_requires_renaming =
     `extern crate self;` requires renaming
     .suggestion = rename the `self` crate to be able to import it
 
-resolve_failed_resolve_unresolve_import = failed to resolve: unresolved import
-
-resolve_failed_resolve_unresolve_import_label = unresolved import
-
 resolve_forward_declared_generic_param =
     generic parameters with a default cannot use forward declared identifiers
     .label = defaulted generic parameters cannot be forward declared
@@ -194,8 +190,6 @@ resolve_ident_bound_more_than_once_in_parameter_list =
     identifier `{$identifier}` is bound more than once in this parameter list
     .label = used as parameter more than once
 
-resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here
-
 resolve_ident_bound_more_than_once_in_same_pattern =
     identifier `{$identifier}` is bound more than once in the same pattern
     .label = used in a pattern more than once
@@ -206,6 +200,8 @@ resolve_ident_imported_here_but_it_is_desc =
 resolve_ident_in_scope_but_it_is_desc =
     `{$imported_ident}` is in scope, but it is {$imported_ident_desc}
 
+resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here
+
 resolve_imported_crate = `$crate` may not be imported
 
 resolve_imported_macro_not_found = imported macro not found
@@ -408,6 +404,10 @@ resolve_trait_impl_duplicate =
     .old_span_label = previous definition here
     .trait_item_span = item in trait
 
+resolve_trait_impl_mismatch =
+    item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
+    .label = does not match trait
+    .trait_impl_mismatch_label_item = item in trait
 resolve_try_using_similarly_named_label =
     try using similarly named label
 
@@ -467,10 +467,3 @@ resolve_variable_is_not_bound_in_all_patterns =
     variable `{$name}` is not bound in all patterns
 
 resolve_variable_not_in_all_patterns = variable not in all patterns
-
-resolve_you_could_import_this_desc = you could import this {$desc}
-
-resolve_trait_impl_mismatch =
-    item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
-    .label = does not match trait
-    .trait_impl_mismatch_label_item = item in trait
\ No newline at end of file
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index e1ab5b57c3cca..b0329702d1143 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,4 +1,3 @@
-#![allow(dead_code)]
 use rustc_errors::{codes::*, Applicability, MultiSpan};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{

From ec3ac1dcd6f8c4cdd648246aa2169cf7ea05027f Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 14 Apr 2024 11:31:51 +0200
Subject: [PATCH 07/22] =?UTF-8?q?builtin-derive:=20tag=20=E2=86=92=20discr?=
 =?UTF-8?q?iminant?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/deriving/clone.rs                     |  4 +-
 .../src/deriving/cmp/partial_ord.rs           | 20 ++--
 .../src/deriving/debug.rs                     |  2 +-
 .../src/deriving/generic/mod.rs               | 88 ++++++++---------
 .../rustc_builtin_macros/src/deriving/hash.rs |  6 +-
 tests/ui/deriving/deriving-all-codegen.stdout | 94 +++++++++----------
 6 files changed, 107 insertions(+), 107 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 0a44bd42b9173..cb1c9ef90bde7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -181,8 +181,8 @@ fn cs_clone(
             all_fields = af;
             vdata = &variant.data;
         }
-        EnumTag(..) | AllFieldlessEnum(..) => {
-            cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
+        EnumDiscr(..) | AllFieldlessEnum(..) => {
+            cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",))
         }
         StaticEnum(..) | StaticStruct(..) => {
             cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 49fe89b18b091..63311c897aba9 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord(
         Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
 
     // Order in which to perform matching
-    let tag_then_data = if let Annotatable::Item(item) = item
+    let discr_then_data = if let Annotatable::Item(item) = item
         && let ItemKind::Enum(def, _) = &item.kind
     {
         let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
         match dataful.iter().filter(|&&b| b).count() {
-            // No data, placing the tag check first makes codegen simpler
+            // No data, placing the discriminant check first makes codegen simpler
             0 => true,
             1..=2 => false,
             _ => (0..dataful.len() - 1).any(|i| {
@@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord(
         attributes: thin_vec![cx.attr_word(sym::inline, span)],
         fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
         combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
-            cs_partial_cmp(cx, span, substr, tag_then_data)
+            cs_partial_cmp(cx, span, substr, discr_then_data)
         })),
     };
 
@@ -72,7 +72,7 @@ fn cs_partial_cmp(
     cx: &ExtCtxt<'_>,
     span: Span,
     substr: &Substructure<'_>,
-    tag_then_data: bool,
+    discr_then_data: bool,
 ) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
@@ -108,12 +108,12 @@ fn cs_partial_cmp(
                 //     cmp => cmp
                 // }
                 // ```
-                // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
-                //  against the enum variants. This means that we begin by comparing the enum tags,
+                // where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match`
+                // against the enum variants. This means that we begin by comparing the enum discriminants,
                 // before either inspecting their contents (if they match), or returning
-                // the `cmp::Ordering` of comparing the enum tags.
+                // the `cmp::Ordering` of comparing the enum discriminants.
                 // ```
-                // match partial_cmp(self_tag, other_tag) {
+                // match partial_cmp(self_discr, other_discr) {
                 //     Some(Ordering::Equal) => match (self, other)  {
                 //         (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
                 //         (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
@@ -126,12 +126,12 @@ fn cs_partial_cmp(
                 // ```
                 // match (self, other) {
                 //     (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
-                //     _ => partial_cmp(self_tag, other_tag)
+                //     _ => partial_cmp(self_discr, other_discr)
                 // }
                 // ```
                 // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
 
-                if !tag_then_data
+                if !discr_then_data
                     && let ExprKind::Match(_, arms, _) = &mut expr1.kind
                     && let Some(last) = arms.last_mut()
                     && let PatKind::Wild = last.pat.kind
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index e442b3520b275..8b681db967050 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -53,7 +53,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
         EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
         AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
-        EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
+        EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
             cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
         }
     };
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index e16d74eed4e07..f73106c18358d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -21,7 +21,7 @@
 //!   `struct T(i32, char)`).
 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
 //!   same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
-//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
+//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants.
 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
 //!   being derived upon is either an enum or struct respectively. (Any
 //!   argument with type Self is just grouped among the non-self
@@ -143,11 +143,11 @@
 //! )
 //! ```
 //!
-//! For the tags,
+//! For the discriminants,
 //!
 //! ```text
-//! EnumTag(
-//!     &[<ident of self tag>, <ident of other tag>],
+//! EnumDiscr(
+//!     &[<ident of self discriminant>, <ident of other discriminant>],
 //!     <expr to combine with>,
 //! )
 //! ```
@@ -315,10 +315,10 @@ pub enum SubstructureFields<'a> {
     /// variant.
     EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
 
-    /// The tag of an enum. The first field is a `FieldInfo` for the tags, as
+    /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
     /// if they were fields. The second field is the expression to combine the
-    /// tag expression with; it will be `None` if no match is necessary.
-    EnumTag(FieldInfo, Option<P<Expr>>),
+    /// discriminant expression with; it will be `None` if no match is necessary.
+    EnumDiscr(FieldInfo, Option<P<Expr>>),
 
     /// A static method where `Self` is a struct.
     StaticStruct(&'a ast::VariantData, StaticFields),
@@ -1137,9 +1137,9 @@ impl<'a> MethodDef<'a> {
     /// impl ::core::cmp::PartialEq for A {
     ///     #[inline]
     ///     fn eq(&self, other: &A) -> bool {
-    ///         let __self_tag = ::core::intrinsics::discriminant_value(self);
-    ///         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-    ///         __self_tag == __arg1_tag
+    ///         let __self_discr = ::core::intrinsics::discriminant_value(self);
+    ///         let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+    ///         __self_discr == __arg1_discr
     ///             && match (self, other) {
     ///                 (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
     ///                 _ => true,
@@ -1148,7 +1148,7 @@ impl<'a> MethodDef<'a> {
     /// }
     /// ```
     ///
-    /// Creates a tag check combined with a match for a tuple of all
+    /// Creates a discriminant check combined with a match for a tuple of all
     /// `selflike_args`, with an arm for each variant with fields, possibly an
     /// arm for each fieldless variant (if `unify_fieldless_variants` is not
     /// `Unify`), and possibly a default arm.
@@ -1169,7 +1169,7 @@ impl<'a> MethodDef<'a> {
         let span = trait_.span;
         let variants = &enum_def.variants;
 
-        // Traits that unify fieldless variants always use the tag(s).
+        // Traits that unify fieldless variants always use the discriminant(s).
         let unify_fieldless_variants =
             self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
 
@@ -1199,25 +1199,25 @@ impl<'a> MethodDef<'a> {
         //
         // e.g. for `PartialEq::eq` builds two statements:
         // ```
-        // let __self_tag = ::core::intrinsics::discriminant_value(self);
-        // let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        // let __self_discr = ::core::intrinsics::discriminant_value(self);
+        // let __arg1_discr = ::core::intrinsics::discriminant_value(other);
         // ```
-        let get_tag_pieces = |cx: &ExtCtxt<'_>| {
-            let tag_idents: Vec<_> = prefixes
+        let get_discr_pieces = |cx: &ExtCtxt<'_>| {
+            let discr_idents: Vec<_> = prefixes
                 .iter()
-                .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
+                .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span))
                 .collect();
 
-            let mut tag_exprs: Vec<_> = tag_idents
+            let mut discr_exprs: Vec<_> = discr_idents
                 .iter()
                 .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
                 .collect();
 
-            let self_expr = tag_exprs.remove(0);
-            let other_selflike_exprs = tag_exprs;
-            let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
+            let self_expr = discr_exprs.remove(0);
+            let other_selflike_exprs = discr_exprs;
+            let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
 
-            let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args)
+            let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
                 .map(|(&ident, selflike_arg)| {
                     let variant_value = deriving::call_intrinsic(
                         cx,
@@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> {
                 })
                 .collect();
 
-            (tag_field, tag_let_stmts)
+            (discr_field, discr_let_stmts)
         };
 
         // There are some special cases involving fieldless enums where no
@@ -1239,19 +1239,19 @@ impl<'a> MethodDef<'a> {
             if variants.len() > 1 {
                 match self.fieldless_variants_strategy {
                     FieldlessVariantsStrategy::Unify => {
-                        // If the type is fieldless and the trait uses the tag and
+                        // If the type is fieldless and the trait uses the discriminant and
                         // there are multiple variants, we need just an operation on
-                        // the tag(s).
-                        let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
-                        let mut tag_check = self.call_substructure_method(
+                        // the discriminant(s).
+                        let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
+                        let mut discr_check = self.call_substructure_method(
                             cx,
                             trait_,
                             type_ident,
                             nonselflike_args,
-                            &EnumTag(tag_field, None),
+                            &EnumDiscr(discr_field, None),
                         );
-                        tag_let_stmts.append(&mut tag_check.0);
-                        return BlockOrExpr(tag_let_stmts, tag_check.1);
+                        discr_let_stmts.append(&mut discr_check.0);
+                        return BlockOrExpr(discr_let_stmts, discr_check.1);
                     }
                     FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
                         return self.call_substructure_method(
@@ -1266,7 +1266,7 @@ impl<'a> MethodDef<'a> {
                 }
             } else if variants.len() == 1 {
                 // If there is a single variant, we don't need an operation on
-                // the tag(s). Just use the most degenerate result.
+                // the discriminant(s). Just use the most degenerate result.
                 return self.call_substructure_method(
                     cx,
                     trait_,
@@ -1380,22 +1380,22 @@ impl<'a> MethodDef<'a> {
             cx.expr_match(span, match_arg, match_arms)
         };
 
-        // If the trait uses the tag and there are multiple variants, we need
-        // to add a tag check operation before the match. Otherwise, the match
+        // If the trait uses the discriminant and there are multiple variants, we need
+        // to add a discriminant check operation before the match. Otherwise, the match
         // is enough.
         if unify_fieldless_variants && variants.len() > 1 {
-            let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
+            let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
 
-            // Combine a tag check with the match.
-            let mut tag_check_plus_match = self.call_substructure_method(
+            // Combine a discriminant check with the match.
+            let mut discr_check_plus_match = self.call_substructure_method(
                 cx,
                 trait_,
                 type_ident,
                 nonselflike_args,
-                &EnumTag(tag_field, Some(get_match_expr(selflike_args))),
+                &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
             );
-            tag_let_stmts.append(&mut tag_check_plus_match.0);
-            BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
+            discr_let_stmts.append(&mut discr_check_plus_match.0);
+            BlockOrExpr(discr_let_stmts, discr_check_plus_match.1)
         } else {
             BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
         }
@@ -1701,16 +1701,16 @@ where
                 rest.iter().rfold(base_expr, op)
             }
         }
-        EnumTag(tag_field, match_expr) => {
-            let tag_check_expr = f(cx, CsFold::Single(tag_field));
+        EnumDiscr(discr_field, match_expr) => {
+            let discr_check_expr = f(cx, CsFold::Single(discr_field));
             if let Some(match_expr) = match_expr {
                 if use_foldl {
-                    f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
+                    f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone()))
                 } else {
-                    f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
+                    f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr))
                 }
             } else {
-                tag_check_expr
+                discr_check_expr
             }
         }
         StaticEnum(..) | StaticStruct(..) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 6bb61311bd281..41e27f6558668 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -66,9 +66,9 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'
                 fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
             (stmts, None)
         }
-        EnumTag(tag_field, match_expr) => {
-            assert!(tag_field.other_selflike_exprs.is_empty());
-            let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
+        EnumDiscr(discr_field, match_expr) => {
+            assert!(discr_field.other_selflike_exprs.is_empty());
+            let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())];
             (stmts, match_expr.clone())
         }
         _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index a027452797554..9f8a9f30ff682 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -1005,8 +1005,8 @@ impl ::core::default::Default for Fieldless {
 impl ::core::hash::Hash for Fieldless {
     #[inline]
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        ::core::hash::Hash::hash(&__self_tag, state)
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        ::core::hash::Hash::hash(&__self_discr, state)
     }
 }
 #[automatically_derived]
@@ -1015,9 +1015,9 @@ impl ::core::marker::StructuralPartialEq for Fieldless { }
 impl ::core::cmp::PartialEq for Fieldless {
     #[inline]
     fn eq(&self, other: &Fieldless) -> bool {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        __self_tag == __arg1_tag
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        __self_discr == __arg1_discr
     }
 }
 #[automatically_derived]
@@ -1032,18 +1032,18 @@ impl ::core::cmp::PartialOrd for Fieldless {
     #[inline]
     fn partial_cmp(&self, other: &Fieldless)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr)
     }
 }
 #[automatically_derived]
 impl ::core::cmp::Ord for Fieldless {
     #[inline]
     fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
     }
 }
 
@@ -1096,8 +1096,8 @@ impl ::core::default::Default for Mixed {
 impl ::core::hash::Hash for Mixed {
     #[inline]
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        ::core::hash::Hash::hash(&__self_tag, state);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        ::core::hash::Hash::hash(&__self_discr, state);
         match self {
             Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state),
             Mixed::S { d1: __self_0, d2: __self_1 } => {
@@ -1114,9 +1114,9 @@ impl ::core::marker::StructuralPartialEq for Mixed { }
 impl ::core::cmp::PartialEq for Mixed {
     #[inline]
     fn eq(&self, other: &Mixed) -> bool {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        __self_tag == __arg1_tag &&
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        __self_discr == __arg1_discr &&
             match (self, other) {
                 (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
                     *__self_0 == *__arg1_0,
@@ -1143,8 +1143,8 @@ impl ::core::cmp::PartialOrd for Mixed {
     #[inline]
     fn partial_cmp(&self, other: &Mixed)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
         match (self, other) {
             (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
                 ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
@@ -1157,8 +1157,8 @@ impl ::core::cmp::PartialOrd for Mixed {
                     cmp => cmp,
                 },
             _ =>
-                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
-                    &__arg1_tag),
+                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
+                    &__arg1_discr),
         }
     }
 }
@@ -1166,9 +1166,9 @@ impl ::core::cmp::PartialOrd for Mixed {
 impl ::core::cmp::Ord for Mixed {
     #[inline]
     fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
             ::core::cmp::Ordering::Equal =>
                 match (self, other) {
                     (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
@@ -1225,8 +1225,8 @@ impl ::core::fmt::Debug for Fielded {
 impl ::core::hash::Hash for Fielded {
     #[inline]
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        ::core::hash::Hash::hash(&__self_tag, state);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        ::core::hash::Hash::hash(&__self_discr, state);
         match self {
             Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state),
             Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state),
@@ -1240,9 +1240,9 @@ impl ::core::marker::StructuralPartialEq for Fielded { }
 impl ::core::cmp::PartialEq for Fielded {
     #[inline]
     fn eq(&self, other: &Fielded) -> bool {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        __self_tag == __arg1_tag &&
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        __self_discr == __arg1_discr &&
             match (self, other) {
                 (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
                     *__self_0 == *__arg1_0,
@@ -1270,8 +1270,8 @@ impl ::core::cmp::PartialOrd for Fielded {
     #[inline]
     fn partial_cmp(&self, other: &Fielded)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
         match (self, other) {
             (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
                 ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
@@ -1280,8 +1280,8 @@ impl ::core::cmp::PartialOrd for Fielded {
             (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
                 ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
             _ =>
-                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
-                    &__arg1_tag),
+                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
+                    &__arg1_discr),
         }
     }
 }
@@ -1289,9 +1289,9 @@ impl ::core::cmp::PartialOrd for Fielded {
 impl ::core::cmp::Ord for Fielded {
     #[inline]
     fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
             ::core::cmp::Ordering::Equal =>
                 match (self, other) {
                     (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
@@ -1346,8 +1346,8 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
     EnumGeneric<T, U> {
     #[inline]
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        ::core::hash::Hash::hash(&__self_tag, state);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        ::core::hash::Hash::hash(&__self_discr, state);
         match self {
             EnumGeneric::One(__self_0) =>
                 ::core::hash::Hash::hash(__self_0, state),
@@ -1363,9 +1363,9 @@ impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
     ::core::cmp::PartialEq for EnumGeneric<T, U> {
     #[inline]
     fn eq(&self, other: &EnumGeneric<T, U>) -> bool {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        __self_tag == __arg1_tag &&
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        __self_discr == __arg1_discr &&
             match (self, other) {
                 (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
                     *__self_0 == *__arg1_0,
@@ -1392,16 +1392,16 @@ impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd>
     #[inline]
     fn partial_cmp(&self, other: &EnumGeneric<T, U>)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
         match (self, other) {
             (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
                 ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
             (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
                 ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
             _ =>
-                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
-                    &__arg1_tag),
+                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
+                    &__arg1_discr),
         }
     }
 }
@@ -1410,9 +1410,9 @@ impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for
     EnumGeneric<T, U> {
     #[inline]
     fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering {
-        let __self_tag = ::core::intrinsics::discriminant_value(self);
-        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
+        let __self_discr = ::core::intrinsics::discriminant_value(self);
+        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
             ::core::cmp::Ordering::Equal =>
                 match (self, other) {
                     (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>

From be7fb2ed554757260b018fda581d416271d2fae3 Mon Sep 17 00:00:00 2001
From: Tobias Decking <Tobias.Decking@gmail.com>
Date: Sun, 14 Apr 2024 14:56:41 +0200
Subject: [PATCH 08/22] Update encode.rs

---
 .../rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index ed7cd8c2da745..40cd0c14b05f4 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -736,7 +736,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
 /// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
 fn to_disambiguator(num: u64) -> String {
     if let Some(num) = num.checked_sub(1) {
-        format!("s{}_", base_n::encode(num as u128, 62))
+        format!("s{}_", base_n::encode(num as u128, base_n::ALPHANUMERIC_ONLY))
     } else {
         "s_".to_string()
     }
@@ -746,7 +746,7 @@ fn to_disambiguator(num: u64) -> String {
 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
 fn to_seq_id(num: usize) -> String {
     if let Some(num) = num.checked_sub(1) {
-        base_n::encode(num as u128, 36).to_uppercase()
+        base_n::encode(num as u128, base_n::CASE_INSENSITIVE).to_uppercase()
     } else {
         "".to_string()
     }

From e5cf30cd63422ac689ec419a3bee0b35d75ca7d8 Mon Sep 17 00:00:00 2001
From: Tobias Decking <Tobias.Decking@gmail.com>
Date: Sun, 14 Apr 2024 15:01:04 +0200
Subject: [PATCH 09/22] Update v0.rs

---
 compiler/rustc_symbol_mangling/src/v0.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index cb255fabfe21a..58b67c77a6150 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -831,7 +831,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
 ///   e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
 pub(crate) fn push_integer_62(x: u64, output: &mut String) {
     if let Some(x) = x.checked_sub(1) {
-        base_n::push_str(x as u128, 62, output);
+        base_n::push_str(x as u128, base_n::ALPHANUMERIC_ONLY, output);
     }
     output.push('_');
 }

From b09c17774399bc93ba098cd05cb6c57155f8360b Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 14 Apr 2024 11:36:37 -0400
Subject: [PATCH 10/22] Don't leak unnameable types in -> _ recover

---
 compiler/rustc_hir_analysis/src/collect.rs    | 27 ++++++++-----------
 .../src/variance/constraints.rs               |  2 +-
 tests/ui/variance/leaking-unnameables.rs      | 13 +++++++++
 tests/ui/variance/leaking-unnameables.stderr  | 12 +++++++++
 4 files changed, 37 insertions(+), 17 deletions(-)
 create mode 100644 tests/ui/variance/leaking-unnameables.rs
 create mode 100644 tests/ui/variance/leaking-unnameables.stderr

diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index c1bf65367aab5..1085caa310b6d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1373,16 +1373,16 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             // Don't leak types into signatures unless they're nameable!
             // For example, if a function returns itself, we don't want that
             // recursive function definition to leak out into the fn sig.
-            let mut should_recover = false;
+            let mut recovered_ret_ty = None;
 
-            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
+            if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
-                    ret_ty,
+                    suggestable_ret_ty,
                     Applicability::MachineApplicable,
                 );
-                should_recover = true;
+                recovered_ret_ty = Some(suggestable_ret_ty);
             } else if let Some(sugg) =
                 suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
             {
@@ -1404,18 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             }
 
             let guar = diag.emit();
-
-            if should_recover {
-                ty::Binder::dummy(fn_sig)
-            } else {
-                ty::Binder::dummy(tcx.mk_fn_sig(
-                    fn_sig.inputs().iter().copied(),
-                    Ty::new_error(tcx, guar),
-                    fn_sig.c_variadic,
-                    fn_sig.unsafety,
-                    fn_sig.abi,
-                ))
-            }
+            ty::Binder::dummy(tcx.mk_fn_sig(
+                fn_sig.inputs().iter().copied(),
+                recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
+                fn_sig.c_variadic,
+                fn_sig.unsafety,
+                fn_sig.abi,
+            ))
         }
         None => icx.lowerer().lower_fn_ty(
             hir_id,
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 20e4110e1378d..eeb8b02850521 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -236,7 +236,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => {
-                bug!("Unexpected coroutine/closure type in variance computation");
+                bug!("Unexpected unnameable type in variance computation: {ty}");
             }
 
             ty::Ref(region, ty, mutbl) => {
diff --git a/tests/ui/variance/leaking-unnameables.rs b/tests/ui/variance/leaking-unnameables.rs
new file mode 100644
index 0000000000000..e51d3779d34b5
--- /dev/null
+++ b/tests/ui/variance/leaking-unnameables.rs
@@ -0,0 +1,13 @@
+// Test variance computation doesn't explode when we leak unnameable
+// types due to `-> _` recovery.
+
+pub struct Type<'a>(&'a ());
+
+pub fn g() {}
+
+pub fn f<T>() -> _ {
+   //~^ ERROR the placeholder `_` is not allowed within types on item signatures
+   g
+}
+
+fn main() {}
diff --git a/tests/ui/variance/leaking-unnameables.stderr b/tests/ui/variance/leaking-unnameables.stderr
new file mode 100644
index 0000000000000..92afe952801d0
--- /dev/null
+++ b/tests/ui/variance/leaking-unnameables.stderr
@@ -0,0 +1,12 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/leaking-unnameables.rs:8:18
+   |
+LL | pub fn f<T>() -> _ {
+   |                  ^
+   |                  |
+   |                  not allowed in type signatures
+   |                  help: replace with the correct return type: `fn()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0121`.

From 398da593a53161c1ef9ca7dabbc5e9edf67deac6 Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Sun, 14 Apr 2024 15:15:03 +0000
Subject: [PATCH 11/22] Merge `WithNumNodes` into DirectedGraph

---
 .../rustc_borrowck/src/constraints/graph.rs   |  2 --
 .../src/graph/iterate/mod.rs                  | 24 +++++++++----------
 .../rustc_data_structures/src/graph/mod.rs    | 13 ++++------
 .../src/graph/reference.rs                    |  2 --
 .../src/graph/scc/mod.rs                      | 14 +++++------
 .../rustc_data_structures/src/graph/tests.rs  | 10 ++++----
 .../src/graph/vec_graph/mod.rs                |  4 +---
 compiler/rustc_middle/src/mir/basic_blocks.rs |  2 --
 .../rustc_middle/src/mir/generic_graphviz.rs  |  4 ++--
 .../src/coverage/counters.rs                  |  2 +-
 .../rustc_mir_transform/src/coverage/graph.rs |  4 +---
 .../rustc_mir_transform/src/coverage/spans.rs |  2 +-
 .../rustc_mir_transform/src/coverage/tests.rs |  2 +-
 13 files changed, 33 insertions(+), 52 deletions(-)

diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 8b7d9ec2cd671..470da9cbae611 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -216,9 +216,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D>
 
 impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
     type Node = RegionVid;
-}
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
     fn num_nodes(&self) -> usize {
         self.constraint_graph.first_constraints.len()
     }
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 9eb4b5278c079..c46fdb4e4f797 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,4 +1,4 @@
-use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
+use super::{DirectedGraph, WithStartNode, WithSuccessors};
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use std::ops::ControlFlow;
@@ -6,14 +6,14 @@ use std::ops::ControlFlow;
 #[cfg(test)]
 mod tests;
 
-pub fn post_order_from<G: DirectedGraph + WithSuccessors + WithNumNodes>(
+pub fn post_order_from<G: DirectedGraph + WithSuccessors>(
     graph: &G,
     start_node: G::Node,
 ) -> Vec<G::Node> {
     post_order_from_to(graph, start_node, None)
 }
 
-pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
+pub fn post_order_from_to<G: DirectedGraph + WithSuccessors>(
     graph: &G,
     start_node: G::Node,
     end_node: Option<G::Node>,
@@ -27,7 +27,7 @@ pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
     result
 }
 
-fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
+fn post_order_walk<G: DirectedGraph + WithSuccessors>(
     graph: &G,
     node: G::Node,
     result: &mut Vec<G::Node>,
@@ -60,7 +60,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
     }
 }
 
-pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
+pub fn reverse_post_order<G: DirectedGraph + WithSuccessors>(
     graph: &G,
     start_node: G::Node,
 ) -> Vec<G::Node> {
@@ -72,7 +72,7 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
 /// A "depth-first search" iterator for a directed graph.
 pub struct DepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     graph: &'graph G,
     stack: Vec<G::Node>,
@@ -81,7 +81,7 @@ where
 
 impl<'graph, G> DepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     pub fn new(graph: &'graph G) -> Self {
         Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
@@ -127,7 +127,7 @@ where
 
 impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let mut f = fmt.debug_set();
@@ -140,7 +140,7 @@ where
 
 impl<G> Iterator for DepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     type Item = G::Node;
 
@@ -201,7 +201,7 @@ struct Event<N> {
 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
 pub struct TriColorDepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     graph: &'graph G,
     stack: Vec<Event<G::Node>>,
@@ -211,7 +211,7 @@ where
 
 impl<'graph, G> TriColorDepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithSuccessors,
 {
     pub fn new(graph: &'graph G) -> Self {
         TriColorDepthFirstSearch {
@@ -278,7 +278,7 @@ where
 
 impl<G> TriColorDepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
+    G: ?Sized + DirectedGraph + WithSuccessors + WithStartNode,
 {
     /// Performs a depth-first search, starting from `G::start_node()`.
     ///
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index e06ab2fe36b92..853b8f1775e06 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -12,9 +12,7 @@ mod tests;
 
 pub trait DirectedGraph {
     type Node: Idx;
-}
 
-pub trait WithNumNodes: DirectedGraph {
     fn num_nodes(&self) -> usize;
 }
 
@@ -28,10 +26,7 @@ where
 {
     fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter;
 
-    fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self>
-    where
-        Self: WithNumNodes,
-    {
+    fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> {
         iterate::DepthFirstSearch::new(self).with_start_node(from)
     }
 }
@@ -60,20 +55,20 @@ pub trait WithStartNode: DirectedGraph {
 }
 
 pub trait ControlFlowGraph:
-    DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
+    DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
 {
     // convenient trait
 }
 
 impl<T> ControlFlowGraph for T where
-    T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
+    T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
 {
 }
 
 /// Returns `true` if the graph has a cycle that is reachable from the start node.
 pub fn is_cyclic<G>(graph: &G) -> bool
 where
-    G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+    G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors,
 {
     iterate::TriColorDepthFirstSearch::new(graph)
         .run_from_start(&mut iterate::CycleDetector)
diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs
index c259fe56c1509..d15513c95db5d 100644
--- a/compiler/rustc_data_structures/src/graph/reference.rs
+++ b/compiler/rustc_data_structures/src/graph/reference.rs
@@ -2,9 +2,7 @@ use super::*;
 
 impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G {
     type Node = G::Node;
-}
 
-impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G {
     fn num_nodes(&self) -> usize {
         (**self).num_nodes()
     }
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index b54d75f7ed703..a9967c2ecbb49 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -7,7 +7,7 @@
 
 use crate::fx::FxHashSet;
 use crate::graph::vec_graph::VecGraph;
-use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
+use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use std::ops::Range;
 
@@ -39,7 +39,7 @@ pub struct SccData<S: Idx> {
 }
 
 impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
-    pub fn new(graph: &(impl DirectedGraph<Node = N> + WithNumNodes + WithSuccessors)) -> Self {
+    pub fn new(graph: &(impl DirectedGraph<Node = N> + WithSuccessors)) -> Self {
         SccsConstruction::construct(graph)
     }
 
@@ -89,17 +89,15 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
     }
 }
 
-impl<N: Idx, S: Idx> DirectedGraph for Sccs<N, S> {
+impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
     type Node = S;
-}
 
-impl<N: Idx, S: Idx + Ord> WithNumNodes for Sccs<N, S> {
     fn num_nodes(&self) -> usize {
         self.num_sccs()
     }
 }
 
-impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> {
+impl<N: Idx, S: Idx + Ord> WithNumEdges for Sccs<N, S> {
     fn num_edges(&self) -> usize {
         self.scc_data.all_successors.len()
     }
@@ -158,7 +156,7 @@ impl<S: Idx> SccData<S> {
     }
 }
 
-struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> {
+struct SccsConstruction<'c, G: DirectedGraph + WithSuccessors, S: Idx> {
     graph: &'c G,
 
     /// The state of each node; used during walk to record the stack
@@ -218,7 +216,7 @@ enum WalkReturn<S> {
 
 impl<'c, G, S> SccsConstruction<'c, G, S>
 where
-    G: DirectedGraph + WithNumNodes + WithSuccessors,
+    G: DirectedGraph + WithSuccessors,
     S: Idx,
 {
     /// Identifies SCCs in the graph `G` and computes the resulting
diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs
index 7f4ef906b361e..df58b965ccf44 100644
--- a/compiler/rustc_data_structures/src/graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/tests.rs
@@ -36,6 +36,10 @@ impl TestGraph {
 
 impl DirectedGraph for TestGraph {
     type Node = usize;
+
+    fn num_nodes(&self) -> usize {
+        self.num_nodes
+    }
 }
 
 impl WithStartNode for TestGraph {
@@ -44,12 +48,6 @@ impl WithStartNode for TestGraph {
     }
 }
 
-impl WithNumNodes for TestGraph {
-    fn num_nodes(&self) -> usize {
-        self.num_nodes
-    }
-}
-
 impl WithPredecessors for TestGraph {
     fn predecessors(&self, node: usize) -> <Self as GraphPredecessors<'_>>::Iter {
         self.predecessors[&node].iter().cloned()
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 00f6266ce1df7..79efe3fb8e062 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -1,4 +1,4 @@
-use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
+use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors};
 use rustc_index::{Idx, IndexVec};
 
 #[cfg(test)]
@@ -80,9 +80,7 @@ impl<N: Idx + Ord> VecGraph<N> {
 
 impl<N: Idx> DirectedGraph for VecGraph<N> {
     type Node = N;
-}
 
-impl<N: Idx> WithNumNodes for VecGraph<N> {
     fn num_nodes(&self) -> usize {
         self.node_starts.len() - 1
     }
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 3ecd5b9cd3456..80a9b460f3561 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -141,9 +141,7 @@ impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
 
 impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
     type Node = BasicBlock;
-}
 
-impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
     #[inline]
     fn num_nodes(&self) -> usize {
         self.basic_blocks.len()
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index 299b50525cb1e..f22f113e49308 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -5,7 +5,7 @@ use std::io::{self, Write};
 
 pub struct GraphvizWriter<
     'a,
-    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
+    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > {
@@ -19,7 +19,7 @@ pub struct GraphvizWriter<
 
 impl<
     'a,
-    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
+    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 69dc4f2ddea71..6e73a476421f2 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -2,7 +2,7 @@ use std::fmt::{self, Debug};
 
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::WithNumNodes;
+use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index ed8c4d8283d98..4cbad47cdc872 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{self, Dominators};
-use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
+use rustc_data_structures::graph::{self, DirectedGraph, GraphSuccessors, WithStartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
@@ -193,9 +193,7 @@ impl IndexMut<BasicCoverageBlock> for CoverageGraph {
 
 impl graph::DirectedGraph for CoverageGraph {
     type Node = BasicCoverageBlock;
-}
 
-impl graph::WithNumNodes for CoverageGraph {
     #[inline]
     fn num_nodes(&self) -> usize {
         self.bcbs.len()
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 672de1fbe60fd..03ede88668842 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::graph::WithNumNodes;
+use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir;
 use rustc_span::{BytePos, Span};
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 569998de35e0b..631cc3c6f0505 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -28,8 +28,8 @@ use super::counters;
 use super::graph::{self, BasicCoverageBlock};
 
 use itertools::Itertools;
-use rustc_data_structures::graph::WithNumNodes;
 use rustc_data_structures::graph::WithSuccessors;
+use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::ty;

From 0d5fc9bf584f0e8700f0c3d2854bb6c70453f624 Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Sun, 14 Apr 2024 15:40:26 +0000
Subject: [PATCH 12/22] Merge `{With,Graph}{Successors,Predecessors}` into
 `{Successors,Predecessors}`

Now with GAT!
---
 .../rustc_borrowck/src/constraints/graph.rs   | 13 ++----
 compiler/rustc_borrowck/src/dataflow.rs       |  2 +-
 .../src/region_infer/reverse_sccs.rs          |  2 +-
 .../src/type_check/liveness/trace.rs          |  2 +-
 .../src/graph/iterate/mod.rs                  | 24 +++++------
 .../rustc_data_structures/src/graph/mod.rs    | 43 ++++++-------------
 .../src/graph/reference.rs                    | 22 ++++------
 .../src/graph/scc/mod.rs                      | 18 +++-----
 .../rustc_data_structures/src/graph/tests.rs  | 22 ++++------
 .../src/graph/vec_graph/mod.rs                | 12 ++----
 compiler/rustc_hir_typeck/src/fallback.rs     |  2 +-
 compiler/rustc_middle/src/mir/basic_blocks.rs | 20 +++------
 .../rustc_middle/src/mir/generic_graphviz.rs  |  4 +-
 .../rustc_mir_transform/src/coverage/graph.rs | 22 +++-------
 .../rustc_mir_transform/src/coverage/tests.rs |  3 +-
 15 files changed, 78 insertions(+), 133 deletions(-)

diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 470da9cbae611..2dfaeb3ae7605 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -222,15 +222,10 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph
     }
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
-    fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
+impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> {
+    type Successors<'g> = Successors<'s, 'tcx, D> where Self: 'g;
+
+    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
         self.outgoing_regions(node)
     }
 }
-
-impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_>
-    for RegionGraph<'s, 'tcx, D>
-{
-    type Item = RegionVid;
-    type Iter = Successors<'s, 'tcx, D>;
-}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index bc5bd7879563a..c185986a7d8d9 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::graph::WithSuccessors;
+use rustc_data_structures::graph::Successors;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{
     self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index f94001de357a9..7d7a3c09370f8 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -2,7 +2,7 @@ use crate::constraints::ConstraintSccIndex;
 use crate::RegionInferenceContext;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::vec_graph::VecGraph;
-use rustc_data_structures::graph::WithSuccessors;
+use rustc_data_structures::graph::Successors;
 use rustc_middle::ty::RegionVid;
 use std::ops::Range;
 
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 8bdefdfc0ac99..5b92dca430f90 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::graph::WithSuccessors;
+use rustc_data_structures::graph::Successors;
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index c46fdb4e4f797..3ead608cd0b8d 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,4 +1,4 @@
-use super::{DirectedGraph, WithStartNode, WithSuccessors};
+use super::{DirectedGraph, Successors, WithStartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use std::ops::ControlFlow;
@@ -6,14 +6,14 @@ use std::ops::ControlFlow;
 #[cfg(test)]
 mod tests;
 
-pub fn post_order_from<G: DirectedGraph + WithSuccessors>(
+pub fn post_order_from<G: DirectedGraph + Successors>(
     graph: &G,
     start_node: G::Node,
 ) -> Vec<G::Node> {
     post_order_from_to(graph, start_node, None)
 }
 
-pub fn post_order_from_to<G: DirectedGraph + WithSuccessors>(
+pub fn post_order_from_to<G: DirectedGraph + Successors>(
     graph: &G,
     start_node: G::Node,
     end_node: Option<G::Node>,
@@ -27,7 +27,7 @@ pub fn post_order_from_to<G: DirectedGraph + WithSuccessors>(
     result
 }
 
-fn post_order_walk<G: DirectedGraph + WithSuccessors>(
+fn post_order_walk<G: DirectedGraph + Successors>(
     graph: &G,
     node: G::Node,
     result: &mut Vec<G::Node>,
@@ -60,7 +60,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors>(
     }
 }
 
-pub fn reverse_post_order<G: DirectedGraph + WithSuccessors>(
+pub fn reverse_post_order<G: DirectedGraph + Successors>(
     graph: &G,
     start_node: G::Node,
 ) -> Vec<G::Node> {
@@ -72,7 +72,7 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors>(
 /// A "depth-first search" iterator for a directed graph.
 pub struct DepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     graph: &'graph G,
     stack: Vec<G::Node>,
@@ -81,7 +81,7 @@ where
 
 impl<'graph, G> DepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     pub fn new(graph: &'graph G) -> Self {
         Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
@@ -127,7 +127,7 @@ where
 
 impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let mut f = fmt.debug_set();
@@ -140,7 +140,7 @@ where
 
 impl<G> Iterator for DepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     type Item = G::Node;
 
@@ -201,7 +201,7 @@ struct Event<N> {
 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
 pub struct TriColorDepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     graph: &'graph G,
     stack: Vec<Event<G::Node>>,
@@ -211,7 +211,7 @@ where
 
 impl<'graph, G> TriColorDepthFirstSearch<'graph, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors,
+    G: ?Sized + DirectedGraph + Successors,
 {
     pub fn new(graph: &'graph G) -> Self {
         TriColorDepthFirstSearch {
@@ -278,7 +278,7 @@ where
 
 impl<G> TriColorDepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + WithSuccessors + WithStartNode,
+    G: ?Sized + DirectedGraph + Successors + WithStartNode,
 {
     /// Performs a depth-first search, starting from `G::start_node()`.
     ///
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 853b8f1775e06..ef1dac1509e3c 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -20,55 +20,40 @@ pub trait WithNumEdges: DirectedGraph {
     fn num_edges(&self) -> usize;
 }
 
-pub trait WithSuccessors: DirectedGraph
-where
-    Self: for<'graph> GraphSuccessors<'graph, Item = <Self as DirectedGraph>::Node>,
-{
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter;
+pub trait Successors: DirectedGraph {
+    type Successors<'g>: Iterator<Item = Self::Node>
+    where
+        Self: 'g;
+
+    fn successors(&self, node: Self::Node) -> Self::Successors<'_>;
 
     fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> {
         iterate::DepthFirstSearch::new(self).with_start_node(from)
     }
 }
 
-#[allow(unused_lifetimes)]
-pub trait GraphSuccessors<'graph> {
-    type Item;
-    type Iter: Iterator<Item = Self::Item>;
-}
+pub trait Predecessors: DirectedGraph {
+    type Predecessors<'g>: Iterator<Item = Self::Node>
+    where
+        Self: 'g;
 
-pub trait WithPredecessors: DirectedGraph
-where
-    Self: for<'graph> GraphPredecessors<'graph, Item = <Self as DirectedGraph>::Node>,
-{
-    fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter;
-}
-
-#[allow(unused_lifetimes)]
-pub trait GraphPredecessors<'graph> {
-    type Item;
-    type Iter: Iterator<Item = Self::Item>;
+    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>;
 }
 
 pub trait WithStartNode: DirectedGraph {
     fn start_node(&self) -> Self::Node;
 }
 
-pub trait ControlFlowGraph:
-    DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
-{
+pub trait ControlFlowGraph: DirectedGraph + WithStartNode + Predecessors + Successors {
     // convenient trait
 }
 
-impl<T> ControlFlowGraph for T where
-    T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors
-{
-}
+impl<T> ControlFlowGraph for T where T: DirectedGraph + WithStartNode + Predecessors + Successors {}
 
 /// Returns `true` if the graph has a cycle that is reachable from the start node.
 pub fn is_cyclic<G>(graph: &G) -> bool
 where
-    G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors,
+    G: ?Sized + DirectedGraph + WithStartNode + Successors,
 {
     iterate::TriColorDepthFirstSearch::new(graph)
         .run_from_start(&mut iterate::CycleDetector)
diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs
index d15513c95db5d..fb4868f0d474f 100644
--- a/compiler/rustc_data_structures/src/graph/reference.rs
+++ b/compiler/rustc_data_structures/src/graph/reference.rs
@@ -14,24 +14,18 @@ impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
     }
 }
 
-impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G {
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
+impl<'graph, G: Successors> Successors for &'graph G {
+    type Successors<'g> = G::Successors<'g> where 'graph: 'g;
+
+    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
         (**self).successors(node)
     }
 }
 
-impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G {
-    fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter {
+impl<'graph, G: Predecessors> Predecessors for &'graph G {
+    type Predecessors<'g> = G::Predecessors<'g> where 'graph: 'g;
+
+    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
         (**self).predecessors(node)
     }
 }
-
-impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G {
-    type Item = G::Node;
-    type Iter = <G as GraphPredecessors<'iter>>::Iter;
-}
-
-impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G {
-    type Item = G::Node;
-    type Iter = <G as GraphSuccessors<'iter>>::Iter;
-}
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index a9967c2ecbb49..f8f2f3cf0ce09 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -7,7 +7,7 @@
 
 use crate::fx::FxHashSet;
 use crate::graph::vec_graph::VecGraph;
-use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors};
+use crate::graph::{DirectedGraph, Successors, WithNumEdges};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use std::ops::Range;
 
@@ -39,7 +39,7 @@ pub struct SccData<S: Idx> {
 }
 
 impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
-    pub fn new(graph: &(impl DirectedGraph<Node = N> + WithSuccessors)) -> Self {
+    pub fn new(graph: &(impl DirectedGraph<Node = N> + Successors)) -> Self {
         SccsConstruction::construct(graph)
     }
 
@@ -103,14 +103,10 @@ impl<N: Idx, S: Idx + Ord> WithNumEdges for Sccs<N, S> {
     }
 }
 
-impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
-    type Item = S;
+impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
+    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, S>>;
 
-    type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>;
-}
-
-impl<N: Idx, S: Idx + Ord> WithSuccessors for Sccs<N, S> {
-    fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter {
+    fn successors(&self, node: S) -> Self::Successors<'_> {
         self.successors(node).iter().cloned()
     }
 }
@@ -156,7 +152,7 @@ impl<S: Idx> SccData<S> {
     }
 }
 
-struct SccsConstruction<'c, G: DirectedGraph + WithSuccessors, S: Idx> {
+struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> {
     graph: &'c G,
 
     /// The state of each node; used during walk to record the stack
@@ -216,7 +212,7 @@ enum WalkReturn<S> {
 
 impl<'c, G, S> SccsConstruction<'c, G, S>
 where
-    G: DirectedGraph + WithSuccessors,
+    G: DirectedGraph + Successors,
     S: Idx,
 {
     /// Identifies SCCs in the graph `G` and computes the resulting
diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs
index df58b965ccf44..9cd8261be6ccb 100644
--- a/compiler/rustc_data_structures/src/graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/tests.rs
@@ -48,24 +48,18 @@ impl WithStartNode for TestGraph {
     }
 }
 
-impl WithPredecessors for TestGraph {
-    fn predecessors(&self, node: usize) -> <Self as GraphPredecessors<'_>>::Iter {
+impl Predecessors for TestGraph {
+    type Predecessors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
+
+    fn predecessors(&self, node: usize) -> Self::Predecessors<'_> {
         self.predecessors[&node].iter().cloned()
     }
 }
 
-impl WithSuccessors for TestGraph {
-    fn successors(&self, node: usize) -> <Self as GraphSuccessors<'_>>::Iter {
+impl Successors for TestGraph {
+    type Successors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
+
+    fn successors(&self, node: usize) -> Self::Successors<'_> {
         self.successors[&node].iter().cloned()
     }
 }
-
-impl<'graph> GraphPredecessors<'graph> for TestGraph {
-    type Item = usize;
-    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
-}
-
-impl<'graph> GraphSuccessors<'graph> for TestGraph {
-    type Item = usize;
-    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
-}
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 79efe3fb8e062..8b75fd9f63361 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -1,4 +1,4 @@
-use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithSuccessors};
+use crate::graph::{DirectedGraph, Successors, WithNumEdges};
 use rustc_index::{Idx, IndexVec};
 
 #[cfg(test)]
@@ -92,14 +92,10 @@ impl<N: Idx> WithNumEdges for VecGraph<N> {
     }
 }
 
-impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
-    type Item = N;
+impl<N: Idx + Ord> Successors for VecGraph<N> {
+    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, N>>;
 
-    type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>;
-}
-
-impl<N: Idx + Ord> WithSuccessors for VecGraph<N> {
-    fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter {
+    fn successors(&self, node: N) -> Self::Successors<'_> {
         self.successors(node).iter().cloned()
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index fe1e4e74973f0..4efedb4a4a63c 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,6 +1,6 @@
 use crate::FnCtxt;
 use rustc_data_structures::{
-    graph::WithSuccessors,
+    graph::Successors,
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 80a9b460f3561..5fc2940954f9b 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -155,26 +155,20 @@ impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
     }
 }
 
-impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
+impl<'tcx> graph::Successors for BasicBlocks<'tcx> {
+    type Successors<'b> = Successors<'b> where 'tcx: 'b;
+
     #[inline]
-    fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
+    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
         self.basic_blocks[node].terminator().successors()
     }
 }
 
-impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
-    type Item = BasicBlock;
-    type Iter = Successors<'b>;
-}
-
-impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
-    type Item = BasicBlock;
-    type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
-}
+impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> {
+    type Predecessors<'b> = std::iter::Copied<std::slice::Iter<'b, BasicBlock>> where 'tcx: 'b;
 
-impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
     #[inline]
-    fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
+    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
         self.predecessors()[node].iter().copied()
     }
 }
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index f22f113e49308..b49fdbada5f65 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -5,7 +5,7 @@ use std::io::{self, Write};
 
 pub struct GraphvizWriter<
     'a,
-    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode,
+    G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > {
@@ -19,7 +19,7 @@ pub struct GraphvizWriter<
 
 impl<
     'a,
-    G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode,
+    G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 4cbad47cdc872..b51ee3a07233c 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{self, Dominators};
-use rustc_data_structures::graph::{self, DirectedGraph, GraphSuccessors, WithStartNode};
+use rustc_data_structures::graph::{self, DirectedGraph, WithStartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
@@ -208,28 +208,20 @@ impl graph::WithStartNode for CoverageGraph {
     }
 }
 
-type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>;
+impl graph::Successors for CoverageGraph {
+    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, BasicCoverageBlock>>;
 
-impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph {
-    type Item = BasicCoverageBlock;
-    type Iter = std::iter::Cloned<BcbSuccessors<'graph>>;
-}
-
-impl graph::WithSuccessors for CoverageGraph {
     #[inline]
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
+    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
         self.successors[node].iter().cloned()
     }
 }
 
-impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph {
-    type Item = BasicCoverageBlock;
-    type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>;
-}
+impl graph::Predecessors for CoverageGraph {
+    type Predecessors<'g> = std::iter::Copied<std::slice::Iter<'g, BasicCoverageBlock>>;
 
-impl graph::WithPredecessors for CoverageGraph {
     #[inline]
-    fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
+    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
         self.predecessors[node].iter().copied()
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 631cc3c6f0505..cf1a2b399f951 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -28,8 +28,7 @@ use super::counters;
 use super::graph::{self, BasicCoverageBlock};
 
 use itertools::Itertools;
-use rustc_data_structures::graph::WithSuccessors;
-use rustc_data_structures::graph::DirectedGraph;
+use rustc_data_structures::graph::{DirectedGraph, Successors};
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::ty;

From f5144938bd33af48a1b06fc5e11f7f30132be895 Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Sun, 14 Apr 2024 15:51:29 +0000
Subject: [PATCH 13/22] Rename `WithNumEdges` => `NumEdges` and `WithStartNode`
 => `StartNode`

---
 .../src/graph/iterate/mod.rs                     |  4 ++--
 compiler/rustc_data_structures/src/graph/mod.rs  | 16 ++++++++--------
 .../rustc_data_structures/src/graph/reference.rs |  2 +-
 .../rustc_data_structures/src/graph/scc/mod.rs   |  4 ++--
 .../rustc_data_structures/src/graph/tests.rs     |  2 +-
 .../src/graph/vec_graph/mod.rs                   |  4 ++--
 compiler/rustc_middle/src/mir/basic_blocks.rs    |  2 +-
 .../rustc_middle/src/mir/generic_graphviz.rs     |  4 ++--
 .../rustc_mir_transform/src/coverage/graph.rs    |  4 ++--
 9 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 3ead608cd0b8d..7a77f2c0dbbf1 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,4 +1,4 @@
-use super::{DirectedGraph, Successors, WithStartNode};
+use super::{DirectedGraph, StartNode, Successors};
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use std::ops::ControlFlow;
@@ -278,7 +278,7 @@ where
 
 impl<G> TriColorDepthFirstSearch<'_, G>
 where
-    G: ?Sized + DirectedGraph + Successors + WithStartNode,
+    G: ?Sized + DirectedGraph + Successors + StartNode,
 {
     /// Performs a depth-first search, starting from `G::start_node()`.
     ///
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index ef1dac1509e3c..5758ffce6760a 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -16,10 +16,14 @@ pub trait DirectedGraph {
     fn num_nodes(&self) -> usize;
 }
 
-pub trait WithNumEdges: DirectedGraph {
+pub trait NumEdges: DirectedGraph {
     fn num_edges(&self) -> usize;
 }
 
+pub trait StartNode: DirectedGraph {
+    fn start_node(&self) -> Self::Node;
+}
+
 pub trait Successors: DirectedGraph {
     type Successors<'g>: Iterator<Item = Self::Node>
     where
@@ -40,20 +44,16 @@ pub trait Predecessors: DirectedGraph {
     fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>;
 }
 
-pub trait WithStartNode: DirectedGraph {
-    fn start_node(&self) -> Self::Node;
-}
-
-pub trait ControlFlowGraph: DirectedGraph + WithStartNode + Predecessors + Successors {
+pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {
     // convenient trait
 }
 
-impl<T> ControlFlowGraph for T where T: DirectedGraph + WithStartNode + Predecessors + Successors {}
+impl<T> ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {}
 
 /// Returns `true` if the graph has a cycle that is reachable from the start node.
 pub fn is_cyclic<G>(graph: &G) -> bool
 where
-    G: ?Sized + DirectedGraph + WithStartNode + Successors,
+    G: ?Sized + DirectedGraph + StartNode + Successors,
 {
     iterate::TriColorDepthFirstSearch::new(graph)
         .run_from_start(&mut iterate::CycleDetector)
diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs
index fb4868f0d474f..16b019374be7f 100644
--- a/compiler/rustc_data_structures/src/graph/reference.rs
+++ b/compiler/rustc_data_structures/src/graph/reference.rs
@@ -8,7 +8,7 @@ impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G {
     }
 }
 
-impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
+impl<'graph, G: StartNode> StartNode for &'graph G {
     fn start_node(&self) -> Self::Node {
         (**self).start_node()
     }
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index f8f2f3cf0ce09..1cd0edfe57fd4 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -7,7 +7,7 @@
 
 use crate::fx::FxHashSet;
 use crate::graph::vec_graph::VecGraph;
-use crate::graph::{DirectedGraph, Successors, WithNumEdges};
+use crate::graph::{DirectedGraph, NumEdges, Successors};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use std::ops::Range;
 
@@ -97,7 +97,7 @@ impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
     }
 }
 
-impl<N: Idx, S: Idx + Ord> WithNumEdges for Sccs<N, S> {
+impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
     fn num_edges(&self) -> usize {
         self.scc_data.all_successors.len()
     }
diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs
index 9cd8261be6ccb..118b6bd3eb687 100644
--- a/compiler/rustc_data_structures/src/graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/tests.rs
@@ -42,7 +42,7 @@ impl DirectedGraph for TestGraph {
     }
 }
 
-impl WithStartNode for TestGraph {
+impl StartNode for TestGraph {
     fn start_node(&self) -> usize {
         self.start_node
     }
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 8b75fd9f63361..3f9d8ec0acabb 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -1,4 +1,4 @@
-use crate::graph::{DirectedGraph, Successors, WithNumEdges};
+use crate::graph::{DirectedGraph, NumEdges, Successors};
 use rustc_index::{Idx, IndexVec};
 
 #[cfg(test)]
@@ -86,7 +86,7 @@ impl<N: Idx> DirectedGraph for VecGraph<N> {
     }
 }
 
-impl<N: Idx> WithNumEdges for VecGraph<N> {
+impl<N: Idx> NumEdges for VecGraph<N> {
     fn num_edges(&self) -> usize {
         self.edge_targets.len()
     }
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 5fc2940954f9b..36e067c130641 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -148,7 +148,7 @@ impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
     }
 }
 
-impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
+impl<'tcx> graph::StartNode for BasicBlocks<'tcx> {
     #[inline]
     fn start_node(&self) -> Self::Node {
         START_BLOCK
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index b49fdbada5f65..809d4cdce8dec 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -5,7 +5,7 @@ use std::io::{self, Write};
 
 pub struct GraphvizWriter<
     'a,
-    G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
+    G: graph::DirectedGraph + graph::Successors + graph::StartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > {
@@ -19,7 +19,7 @@ pub struct GraphvizWriter<
 
 impl<
     'a,
-    G: graph::DirectedGraph + graph::Successors + graph::WithStartNode,
+    G: graph::DirectedGraph + graph::Successors + graph::StartNode,
     NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
     EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index b51ee3a07233c..c187466403f83 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{self, Dominators};
-use rustc_data_structures::graph::{self, DirectedGraph, WithStartNode};
+use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
@@ -200,7 +200,7 @@ impl graph::DirectedGraph for CoverageGraph {
     }
 }
 
-impl graph::WithStartNode for CoverageGraph {
+impl graph::StartNode for CoverageGraph {
     #[inline]
     fn start_node(&self) -> Self::Node {
         self.bcb_from_bb(mir::START_BLOCK)

From 3124fa93107d406dc77e56a0b8a5b372349a73ab Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Sun, 14 Apr 2024 15:53:38 +0000
Subject: [PATCH 14/22] Document `ControlFlowGraph`

---
 compiler/rustc_data_structures/src/graph/mod.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 5758ffce6760a..189474395eec1 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -44,10 +44,8 @@ pub trait Predecessors: DirectedGraph {
     fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>;
 }
 
-pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {
-    // convenient trait
-}
-
+/// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`].
+pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {}
 impl<T> ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {}
 
 /// Returns `true` if the graph has a cycle that is reachable from the start node.

From e8d2221e3bbb4e8971c97395463036ebd6e7b23d Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Sun, 14 Apr 2024 16:03:08 +0000
Subject: [PATCH 15/22] Make `depth_first_search` into a standalone function

Does not necessarily change much, but we never overwrite it, so I see no reason
for it to be in the `Successors` trait. (+we already have a similar `is_cyclic`)
---
 compiler/rustc_borrowck/src/dataflow.rs               |  4 ++--
 .../rustc_borrowck/src/region_infer/reverse_sccs.rs   |  5 ++---
 .../rustc_borrowck/src/type_check/liveness/trace.rs   |  6 ++++--
 compiler/rustc_data_structures/src/graph/mod.rs       | 11 +++++++----
 .../src/graph/vec_graph/tests.rs                      |  4 +++-
 compiler/rustc_hir_typeck/src/fallback.rs             |  8 +++-----
 6 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index c185986a7d8d9..ec7d4582a6013 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::graph::Successors;
+use rustc_data_structures::graph;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{
     self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
@@ -262,7 +262,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
 
         // We first handle the cases where the loan doesn't go out of scope, depending on the issuing
         // region's successors.
-        for successor in self.regioncx.region_graph().depth_first_search(issuing_region) {
+        for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
             // 1. Via applied member constraints
             //
             // The issuing region can flow into the choice regions, and they are either:
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 7d7a3c09370f8..97ddc45ee476d 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -1,8 +1,8 @@
 use crate::constraints::ConstraintSccIndex;
 use crate::RegionInferenceContext;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::graph;
 use rustc_data_structures::graph::vec_graph::VecGraph;
-use rustc_data_structures::graph::Successors;
 use rustc_middle::ty::RegionVid;
 use std::ops::Range;
 
@@ -23,8 +23,7 @@ impl ReverseSccGraph {
         scc0: ConstraintSccIndex,
     ) -> impl Iterator<Item = RegionVid> + 'a {
         let mut duplicates = FxIndexSet::default();
-        self.graph
-            .depth_first_search(scc0)
+        graph::depth_first_search(&self.graph, scc0)
             .flat_map(move |scc1| {
                 self.scc_regions
                     .get(&scc1)
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 5b92dca430f90..6cc0e67c0f801 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::graph::Successors;
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
@@ -64,7 +63,10 @@ pub(super) fn trace<'mir, 'tcx>(
         // Traverse each issuing region's constraints, and record the loan as flowing into the
         // outlived region.
         for (loan, issuing_region_data) in borrow_set.iter_enumerated() {
-            for succ in region_graph.depth_first_search(issuing_region_data.region) {
+            for succ in rustc_data_structures::graph::depth_first_search(
+                &region_graph,
+                issuing_region_data.region,
+            ) {
                 // We don't need to mention that a loan flows into its issuing region.
                 if succ == issuing_region_data.region {
                     continue;
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 189474395eec1..61bee2ee0bba5 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -30,10 +30,6 @@ pub trait Successors: DirectedGraph {
         Self: 'g;
 
     fn successors(&self, node: Self::Node) -> Self::Successors<'_>;
-
-    fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> {
-        iterate::DepthFirstSearch::new(self).with_start_node(from)
-    }
 }
 
 pub trait Predecessors: DirectedGraph {
@@ -57,3 +53,10 @@ where
         .run_from_start(&mut iterate::CycleDetector)
         .is_some()
 }
+
+pub fn depth_first_search<G>(graph: &G, from: G::Node) -> iterate::DepthFirstSearch<'_, G>
+where
+    G: ?Sized + Successors,
+{
+    iterate::DepthFirstSearch::new(graph).with_start_node(from)
+}
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
index 7c866da60090f..87c8d25f09492 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
@@ -1,3 +1,5 @@
+use crate::graph;
+
 use super::*;
 
 fn create_graph() -> VecGraph<usize> {
@@ -37,6 +39,6 @@ fn successors() {
 #[test]
 fn dfs() {
     let graph = create_graph();
-    let dfs: Vec<_> = graph.depth_first_search(0).collect();
+    let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect();
     assert_eq!(dfs, vec![0, 1, 3, 4, 2]);
 }
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4efedb4a4a63c..69399b50695d1 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,7 +1,6 @@
 use crate::FnCtxt;
 use rustc_data_structures::{
-    graph::Successors,
-    graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
+    graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
@@ -300,7 +299,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
                 debug!(
                     "calculate_diverging_fallback: root_vid={:?} reaches {:?}",
                     root_vid,
-                    coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>()
+                    graph::depth_first_search(&coercion_graph, root_vid).collect::<Vec<_>>()
                 );
 
                 // drain the iterator to visit all nodes reachable from this node
@@ -342,8 +341,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         for &diverging_vid in &diverging_vids {
             let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
             let root_vid = self.root_var(diverging_vid);
-            let can_reach_non_diverging = coercion_graph
-                .depth_first_search(root_vid)
+            let can_reach_non_diverging = graph::depth_first_search(&coercion_graph, root_vid)
                 .any(|n| roots_reachable_from_non_diverging.visited(n));
 
             let infer_var_infos: UnordBag<_> = self

From 80dc3d14c959f136d7b34ff1dedc572afa179ab1 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 14 Apr 2024 18:09:40 +0200
Subject: [PATCH 16/22] move the LargeAssignments lint logic into its own file

---
 compiler/rustc_monomorphize/src/collector.rs  | 146 +----------------
 .../src/collector/move_check.rs               | 155 ++++++++++++++++++
 2 files changed, 161 insertions(+), 140 deletions(-)
 create mode 100644 compiler/rustc_monomorphize/src/collector/move_check.rs

diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index ee6c154e6e84e..36d623fd93e12 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -205,6 +205,8 @@
 //! this is not implemented however: a mono item will be produced
 //! regardless of whether it is actually needed or not.
 
+mod move_check;
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock};
 use rustc_hir as hir;
@@ -227,7 +229,6 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_session::config::EntryFnType;
-use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
 use rustc_session::Limit;
 use rustc_span::source_map::{dummy_spanned, respan, Spanned};
 use rustc_span::symbol::{sym, Ident};
@@ -236,9 +237,9 @@ use rustc_target::abi::Size;
 use std::path::PathBuf;
 
 use crate::errors::{
-    self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit,
-    TypeLengthLimit,
+    self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit,
 };
+use move_check::MoveCheckState;
 
 #[derive(PartialEq)]
 pub enum MonoItemCollectionStrategy {
@@ -667,11 +668,8 @@ struct MirUsedCollector<'a, 'tcx> {
     /// Note that this contains *not-monomorphized* items!
     used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>,
     instance: Instance<'tcx>,
-    /// Spans for move size lints already emitted. Helps avoid duplicate lints.
-    move_size_spans: Vec<Span>,
     visiting_call_terminator: bool,
-    /// Set of functions for which it is OK to move large data into.
-    skip_move_check_fns: Option<Vec<DefId>>,
+    move_check: move_check::MoveCheckState,
 }
 
 impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -687,124 +685,6 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         )
     }
 
-    fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
-        let limit = self.tcx.move_size_limit();
-        if limit.0 == 0 {
-            return;
-        }
-
-        // This function is called by visit_operand() which visits _all_
-        // operands, including TerminatorKind::Call operands. But if
-        // check_fn_args_move_size() has been called, the operands have already
-        // been visited. Do not visit them again.
-        if self.visiting_call_terminator {
-            return;
-        }
-
-        let source_info = self.body.source_info(location);
-        debug!(?source_info);
-
-        if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
-            self.lint_large_assignment(limit.0, too_large_size, location, source_info.span);
-        };
-    }
-
-    fn check_fn_args_move_size(
-        &mut self,
-        callee_ty: Ty<'tcx>,
-        args: &[Spanned<mir::Operand<'tcx>>],
-        fn_span: Span,
-        location: Location,
-    ) {
-        let limit = self.tcx.move_size_limit();
-        if limit.0 == 0 {
-            return;
-        }
-
-        if args.is_empty() {
-            return;
-        }
-
-        // Allow large moves into container types that themselves are cheap to move
-        let ty::FnDef(def_id, _) = *callee_ty.kind() else {
-            return;
-        };
-        if self
-            .skip_move_check_fns
-            .get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
-            .contains(&def_id)
-        {
-            return;
-        }
-
-        debug!(?def_id, ?fn_span);
-
-        for arg in args {
-            // Moving args into functions is typically implemented with pointer
-            // passing at the llvm-ir level and not by memcpy's. So always allow
-            // moving args into functions.
-            let operand: &mir::Operand<'tcx> = &arg.node;
-            if let mir::Operand::Move(_) = operand {
-                continue;
-            }
-
-            if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
-                self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
-            };
-        }
-    }
-
-    fn operand_size_if_too_large(
-        &mut self,
-        limit: Limit,
-        operand: &mir::Operand<'tcx>,
-    ) -> Option<Size> {
-        let ty = operand.ty(self.body, self.tcx);
-        let ty = self.monomorphize(ty);
-        let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
-            return None;
-        };
-        if layout.size.bytes_usize() > limit.0 {
-            debug!(?layout);
-            Some(layout.size)
-        } else {
-            None
-        }
-    }
-
-    fn lint_large_assignment(
-        &mut self,
-        limit: usize,
-        too_large_size: Size,
-        location: Location,
-        span: Span,
-    ) {
-        let source_info = self.body.source_info(location);
-        debug!(?source_info);
-        for reported_span in &self.move_size_spans {
-            if reported_span.overlaps(span) {
-                return;
-            }
-        }
-        let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
-        debug!(?lint_root);
-        let Some(lint_root) = lint_root else {
-            // This happens when the issue is in a function from a foreign crate that
-            // we monomorphized in the current crate. We can't get a `HirId` for things
-            // in other crates.
-            // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
-            // but correct span? This would make the lint at least accept crate-level lint attributes.
-            return;
-        };
-        self.tcx.emit_node_span_lint(
-            LARGE_ASSIGNMENTS,
-            lint_root,
-            span,
-            LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 },
-        );
-        self.move_size_spans.push(span);
-    }
-
     /// Evaluates a *not yet monomorphized* constant.
     fn eval_constant(
         &mut self,
@@ -1367,19 +1247,6 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
     return None;
 }
 
-fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
-    let fns = [
-        (tcx.lang_items().owned_box(), "new"),
-        (tcx.get_diagnostic_item(sym::Rc), "new"),
-        (tcx.get_diagnostic_item(sym::Arc), "new"),
-    ];
-    fns.into_iter()
-        .filter_map(|(def_id, fn_name)| {
-            def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
-        })
-        .collect::<Vec<_>>()
-}
-
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
 ///
 /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
@@ -1409,9 +1276,8 @@ fn collect_items_of_instance<'tcx>(
         used_items,
         used_mentioned_items: &mut used_mentioned_items,
         instance,
-        move_size_spans: vec![],
         visiting_call_terminator: false,
-        skip_move_check_fns: None,
+        move_check: MoveCheckState::new(),
     };
 
     if mode == CollectionMode::UsedItems {
diff --git a/compiler/rustc_monomorphize/src/collector/move_check.rs b/compiler/rustc_monomorphize/src/collector/move_check.rs
new file mode 100644
index 0000000000000..4cc7275ab8069
--- /dev/null
+++ b/compiler/rustc_monomorphize/src/collector/move_check.rs
@@ -0,0 +1,155 @@
+use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
+
+use super::*;
+use crate::errors::LargeAssignmentsLint;
+
+pub(super) struct MoveCheckState {
+    /// Spans for move size lints already emitted. Helps avoid duplicate lints.
+    move_size_spans: Vec<Span>,
+    /// Set of functions for which it is OK to move large data into.
+    skip_move_check_fns: Option<Vec<DefId>>,
+}
+
+impl MoveCheckState {
+    pub(super) fn new() -> Self {
+        MoveCheckState { move_size_spans: vec![], skip_move_check_fns: None }
+    }
+}
+
+impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
+    pub(super) fn check_operand_move_size(
+        &mut self,
+        operand: &mir::Operand<'tcx>,
+        location: Location,
+    ) {
+        let limit = self.tcx.move_size_limit();
+        if limit.0 == 0 {
+            return;
+        }
+
+        // This function is called by visit_operand() which visits _all_
+        // operands, including TerminatorKind::Call operands. But if
+        // check_fn_args_move_size() has been called, the operands have already
+        // been visited. Do not visit them again.
+        if self.visiting_call_terminator {
+            return;
+        }
+
+        let source_info = self.body.source_info(location);
+        debug!(?source_info);
+
+        if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
+            self.lint_large_assignment(limit.0, too_large_size, location, source_info.span);
+        };
+    }
+
+    pub(super) fn check_fn_args_move_size(
+        &mut self,
+        callee_ty: Ty<'tcx>,
+        args: &[Spanned<mir::Operand<'tcx>>],
+        fn_span: Span,
+        location: Location,
+    ) {
+        let limit = self.tcx.move_size_limit();
+        if limit.0 == 0 {
+            return;
+        }
+
+        if args.is_empty() {
+            return;
+        }
+
+        // Allow large moves into container types that themselves are cheap to move
+        let ty::FnDef(def_id, _) = *callee_ty.kind() else {
+            return;
+        };
+        if self
+            .move_check
+            .skip_move_check_fns
+            .get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
+            .contains(&def_id)
+        {
+            return;
+        }
+
+        debug!(?def_id, ?fn_span);
+
+        for arg in args {
+            // Moving args into functions is typically implemented with pointer
+            // passing at the llvm-ir level and not by memcpy's. So always allow
+            // moving args into functions.
+            let operand: &mir::Operand<'tcx> = &arg.node;
+            if let mir::Operand::Move(_) = operand {
+                continue;
+            }
+
+            if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
+                self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
+            };
+        }
+    }
+
+    fn operand_size_if_too_large(
+        &mut self,
+        limit: Limit,
+        operand: &mir::Operand<'tcx>,
+    ) -> Option<Size> {
+        let ty = operand.ty(self.body, self.tcx);
+        let ty = self.monomorphize(ty);
+        let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
+            return None;
+        };
+        if layout.size.bytes_usize() > limit.0 {
+            debug!(?layout);
+            Some(layout.size)
+        } else {
+            None
+        }
+    }
+
+    fn lint_large_assignment(
+        &mut self,
+        limit: usize,
+        too_large_size: Size,
+        location: Location,
+        span: Span,
+    ) {
+        let source_info = self.body.source_info(location);
+        debug!(?source_info);
+        for reported_span in &self.move_check.move_size_spans {
+            if reported_span.overlaps(span) {
+                return;
+            }
+        }
+        let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
+        debug!(?lint_root);
+        let Some(lint_root) = lint_root else {
+            // This happens when the issue is in a function from a foreign crate that
+            // we monomorphized in the current crate. We can't get a `HirId` for things
+            // in other crates.
+            // FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
+            // but correct span? This would make the lint at least accept crate-level lint attributes.
+            return;
+        };
+        self.tcx.emit_node_span_lint(
+            LARGE_ASSIGNMENTS,
+            lint_root,
+            span,
+            LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 },
+        );
+        self.move_check.move_size_spans.push(span);
+    }
+}
+
+fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
+    let fns = [
+        (tcx.lang_items().owned_box(), "new"),
+        (tcx.get_diagnostic_item(sym::Rc), "new"),
+        (tcx.get_diagnostic_item(sym::Arc), "new"),
+    ];
+    fns.into_iter()
+        .filter_map(|(def_id, fn_name)| {
+            def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
+        })
+        .collect::<Vec<_>>()
+}

From bf3deccdadffbd5903268cca74a60f7101f7e9c3 Mon Sep 17 00:00:00 2001
From: Mark Rousskov <mark.simulacrum@gmail.com>
Date: Sun, 14 Apr 2024 15:48:05 -0400
Subject: [PATCH 17/22] Fix UB in LLVM FFI when passing zero or >1 bundle

Rust passes a *const &OperandBundleDef to these APIs, usually from a
Vec<&OperandBundleDef> or so. Previously we were dereferencing that
pointer and passing it to the ArrayRef constructor with some length (N).

This meant that if the length was 0, we were dereferencing a pointer to
nowhere, and if the length was >1 then loading the *second* element
somewhere in LLVM would've been reading past the end.

Since Rust can't hold OperandBundleDef by-value we're forced to indirect
through a vector that copies out the OperandBundleDefs from the
by-reference list on the Rust side in order to match the LLVM expected
API.
---
 .../rustc_llvm/llvm-wrapper/RustWrapper.cpp   | 35 +++++++++++++++----
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 37c2da4c23a1a..6e11fd629e4d3 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1524,13 +1524,21 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
 
 extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                                           LLVMValueRef *Args, unsigned NumArgs,
-                                          OperandBundleDef **OpBundles,
+                                          OperandBundleDef **OpBundlesIndirect,
                                           unsigned NumOpBundles) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
+
+  // FIXME: Is there a way around this?
+  SmallVector<OperandBundleDef> OpBundles;
+  OpBundles.reserve(NumOpBundles);
+  for (unsigned i = 0; i < NumOpBundles; ++i) {
+    OpBundles.push_back(*OpBundlesIndirect[i]);
+  }
+
   return wrap(unwrap(B)->CreateCall(
       FTy, Callee, ArrayRef<Value*>(unwrap(Args), NumArgs),
-      ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles)));
+      ArrayRef<OperandBundleDef>(OpBundles)));
 }
 
 extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
@@ -1570,13 +1578,21 @@ extern "C" LLVMValueRef
 LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                     LLVMValueRef *Args, unsigned NumArgs,
                     LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
-                    OperandBundleDef **OpBundles, unsigned NumOpBundles,
+                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
                     const char *Name) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
+
+  // FIXME: Is there a way around this?
+  SmallVector<OperandBundleDef> OpBundles;
+  OpBundles.reserve(NumOpBundles);
+  for (unsigned i = 0; i < NumOpBundles; ++i) {
+    OpBundles.push_back(*OpBundlesIndirect[i]);
+  }
+
   return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
                                       ArrayRef<Value*>(unwrap(Args), NumArgs),
-                                      ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
+                                      ArrayRef<OperandBundleDef>(OpBundles),
                                       Name));
 }
 
@@ -1585,7 +1601,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                     LLVMBasicBlockRef DefaultDest,
                     LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
                     LLVMValueRef *Args, unsigned NumArgs,
-                    OperandBundleDef **OpBundles, unsigned NumOpBundles,
+                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
                     const char *Name) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
@@ -1597,11 +1613,18 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
     IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i]));
   }
 
+  // FIXME: Is there a way around this?
+  SmallVector<OperandBundleDef> OpBundles;
+  OpBundles.reserve(NumOpBundles);
+  for (unsigned i = 0; i < NumOpBundles; ++i) {
+    OpBundles.push_back(*OpBundlesIndirect[i]);
+  }
+
   return wrap(unwrap(B)->CreateCallBr(
       FTy, Callee, unwrap(DefaultDest),
       ArrayRef<BasicBlock*>(IndirectDestsUnwrapped),
       ArrayRef<Value*>(unwrap(Args), NumArgs),
-      ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
+      ArrayRef<OperandBundleDef>(OpBundles),
       Name));
 }
 

From 510720e9fcb1181cc2e634fe6edddadf2d2c4993 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 6 Apr 2024 14:43:39 +0200
Subject: [PATCH 18/22] libtest: also measure time in Miri

---
 library/test/src/console.rs             | 6 ++----
 src/bootstrap/src/utils/render_tests.rs | 2 +-
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index f3918ba333aa0..7e224d60d9dc5 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -315,10 +315,8 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
 
     // Prevent the usage of `Instant` in some cases:
     // - It's currently not supported for wasm targets.
-    // - We disable it for miri because it's not available when isolation is enabled.
-    let is_instant_unsupported = (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi"))
-        || cfg!(target_os = "zkvm")
-        || cfg!(miri);
+    let is_instant_unsupported =
+        (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) || cfg!(target_os = "zkvm");
 
     let start_time = (!is_instant_unsupported).then(Instant::now);
     run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 95cd55c9a3d7c..16e0c2ac18517 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -377,7 +377,7 @@ struct SuiteOutcome {
     measured: usize,
     filtered_out: usize,
     /// The time it took to execute this test suite, or `None` if time measurement was not possible
-    /// (e.g. due to running inside Miri).
+    /// (e.g. due to running on wasm).
     exec_time: Option<f64>,
 }
 

From 24dac6cd4545be87ad702b63be7532c92878eee8 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 15 Apr 2024 10:15:14 +0200
Subject: [PATCH 19/22] disable create_dir_all_bare on all(miri, windows)

---
 library/std/tests/create_dir_all_bare.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs
index fe789323f97c0..fd2a7f906f839 100644
--- a/library/std/tests/create_dir_all_bare.rs
+++ b/library/std/tests/create_dir_all_bare.rs
@@ -31,6 +31,7 @@ impl Drop for CurrentDir {
 }
 
 #[test]
+#[cfg_attr(all(miri, windows), ignore)] // File system access on Windows not supported by Miri
 fn create_dir_all_bare() {
     let tmpdir = common::tmpdir();
     CurrentDir::with(tmpdir.path(), || {

From 7d1ee8c0fbba7649153d084da2897b4ac7093d51 Mon Sep 17 00:00:00 2001
From: mountcount <cuimoman@outlook.com>
Date: Tue, 9 Apr 2024 15:29:17 +0800
Subject: [PATCH 20/22] Fix some typos in doc

Signed-off-by: mountcount <cuimoman@outlook.com>
---
 src/doc/unstable-book/src/compiler-flags/check-cfg.md      | 4 ++--
 src/doc/unstable-book/src/compiler-flags/shell-argfiles.md | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index 90a006b0a1ee2..836929aba0bf5 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -37,7 +37,7 @@ present in the list of expected values. If `"value"` is not in it, then `rustc`
 the future.*
 
 To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside
-`values()`: `values(none())`. It can be followed or precessed by any number of `"value"`.
+`values()`: `values(none())`. It can be followed or preceded by any number of `"value"`.
 
 To enable checking of values, but to provide an *none*/empty set of expected values
 (ie. expect `#[cfg(name)]`), use these forms:
@@ -163,7 +163,7 @@ fn poke_platypus() {}
 fn tame_lion() {}
 
 #[cfg(windows = "unix")]     // This condition is UNEXPECTED, as while 'windows' is a well known
-                             // condition name, it doens't expect any values
+                             // condition name, it doesn't expect any values
 fn tame_windows() {}
 ```
 
diff --git a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md
index 4f3c780972de5..9e765301206ed 100644
--- a/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md
+++ b/src/doc/unstable-book/src/compiler-flags/shell-argfiles.md
@@ -8,4 +8,4 @@ arguments from argfiles specified with `@shell:<path>`.
 
 Because this feature controls the parsing of input arguments, the
 `-Zshell-argfiles` flag must be present before the argument specifying the
-shell-style arguemnt file.
+shell-style argument file.

From 235d45e9c9c2c66b540cfa6601cc32315a4659c3 Mon Sep 17 00:00:00 2001
From: Kjetil Kjeka <kjetil@muybridge.com>
Date: Wed, 3 Apr 2024 16:25:05 +0200
Subject: [PATCH 21/22] Distribute LLVM bitcode linker as a preview component

---
 src/bootstrap/src/core/build_steps/dist.rs    | 48 +++++++++++++++++++
 src/bootstrap/src/core/build_steps/install.rs |  9 ++++
 src/bootstrap/src/core/build_steps/tool.rs    |  8 ++--
 src/bootstrap/src/core/builder.rs             |  1 +
 src/bootstrap/src/utils/tarball.rs            |  8 ++++
 .../src/compiler-flags/codegen-options.md     |  4 ++
 src/tools/llvm-bitcode-linker/src/linker.rs   | 13 +++--
 7 files changed, 84 insertions(+), 7 deletions(-)

diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index b51d3e157887b..78176665929b6 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1548,6 +1548,7 @@ impl Step for Extended {
             compiler: builder.compiler(stage, target),
             backend: "cranelift".to_string(),
         });
+        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target});
 
         let etc = builder.src.join("src/etc/installer");
 
@@ -2224,6 +2225,53 @@ impl Step for LlvmTools {
     }
 }
 
+#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+pub struct LlvmBitcodeLinker {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for LlvmBitcodeLinker {
+    type Output = Option<GeneratedTarball>;
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker");
+        run.alias("llvm-bitcode-linker").default_condition(default)
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(LlvmBitcodeLinker {
+            compiler: run.builder.compiler_for(
+                run.builder.top_stage,
+                run.builder.config.build,
+                run.target,
+            ),
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
+        let compiler = self.compiler;
+        let target = self.target;
+
+        let llbc_linker =
+            builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] });
+
+        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
+
+        // Prepare the image directory
+        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
+        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
+        tarball.is_preview(true);
+
+        tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755);
+
+        Some(tarball.generate())
+    }
+}
+
 // Tarball intended for internal consumption to ease rustc/std development.
 //
 // Should not be considered stable by end users.
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 41920fabaa974..767c0f6936494 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -300,6 +300,15 @@ install!((self, builder, _config),
             );
         }
     };
+    LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, {
+        if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) {
+            install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball);
+        } else {
+            builder.info(
+                &format!("skipping llvm-bitcode-linker stage{} ({})", self.compiler.stage, self.target),
+            );
+        }
+    };
 );
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1edf65d28b76e..8d1ff2fcb245f 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -746,9 +746,11 @@ impl Step for LlvmBitcodeLinker {
             .join(exe(bin_name, self.compiler.host));
 
         if self.compiler.stage > 0 {
-            let bindir = builder.sysroot(self.compiler).join("bin");
-            t!(fs::create_dir_all(&bindir));
-            let bin_destination = bindir.join(exe(bin_name, self.compiler.host));
+            let bindir_self_contained = builder
+                .sysroot(self.compiler)
+                .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple));
+            t!(fs::create_dir_all(&bindir_self_contained));
+            let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host));
             builder.copy_link(&tool_out, &bin_destination);
             bin_destination
         } else {
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 224f5350e40a7..f31bc46d25fcb 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -853,6 +853,7 @@ impl<'a> Builder<'a> {
                 dist::Clippy,
                 dist::Miri,
                 dist::LlvmTools,
+                dist::LlvmBitcodeLinker,
                 dist::RustDev,
                 dist::Bootstrap,
                 dist::Extended,
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 4f99079a57f36..89fcac2a84b0a 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -20,6 +20,7 @@ pub(crate) enum OverlayKind {
     RLS,
     RustAnalyzer,
     RustcCodegenCranelift,
+    LlvmBitcodeLinker,
 }
 
 impl OverlayKind {
@@ -64,6 +65,12 @@ impl OverlayKind {
                 "compiler/rustc_codegen_cranelift/LICENSE-APACHE",
                 "compiler/rustc_codegen_cranelift/LICENSE-MIT",
             ],
+            OverlayKind::LlvmBitcodeLinker => &[
+                "COPYRIGHT",
+                "LICENSE-APACHE",
+                "LICENSE-MIT",
+                "src/tools/llvm-bitcode-linker/README.md",
+            ],
         }
     }
 
@@ -87,6 +94,7 @@ impl OverlayKind {
                 .rust_analyzer_info
                 .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
             OverlayKind::RustcCodegenCranelift => builder.rust_version(),
+            OverlayKind::LlvmBitcodeLinker => builder.rust_version(),
         }
     }
 }
diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-options.md b/src/doc/unstable-book/src/compiler-flags/codegen-options.md
index 31dfcdb199ab9..cc51554706d07 100644
--- a/src/doc/unstable-book/src/compiler-flags/codegen-options.md
+++ b/src/doc/unstable-book/src/compiler-flags/codegen-options.md
@@ -10,6 +10,10 @@ In addition to the stable set of linker flavors, the following unstable values a
 - `ptx`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker)
   for Nvidia NVPTX GPGPU support.
 - `bpf`: use [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
+- `llbc`: for linking in llvm bitcode. Install the preview rustup components`llvm-bitcode-linker`
+  and `llvm-tools` to use as a self-contained linker by passing
+  `-Zunstable-options -Clink-self-contained=+linker` together with `-Clinker-flavor=llbc`.
+  Can currently only be used for Nvidia NVPTX targets (`nvptx64-nvidia-cuda`).
 
 Additionally, a set of more precise linker flavors also exists, for example allowing targets to
 declare that they use the LLD linker by default. The following values are currently unstable, and
diff --git a/src/tools/llvm-bitcode-linker/src/linker.rs b/src/tools/llvm-bitcode-linker/src/linker.rs
index aa6b6443e4d90..40572f22342be 100644
--- a/src/tools/llvm-bitcode-linker/src/linker.rs
+++ b/src/tools/llvm-bitcode-linker/src/linker.rs
@@ -62,7 +62,7 @@ impl Session {
             .arg("-o")
             .arg(&self.link_path)
             .output()
-            .unwrap();
+            .context("An error occured when calling llvm-link. Make sure the llvm-tools component is installed.")?;
 
         if !llvm_link_output.status.success() {
             tracing::error!(
@@ -108,7 +108,9 @@ impl Session {
             opt_cmd.arg("--strip-debug");
         }
 
-        let opt_output = opt_cmd.output().unwrap();
+        let opt_output = opt_cmd.output().context(
+            "An error occured when calling opt. Make sure the llvm-tools component is installed.",
+        )?;
 
         if !opt_output.status.success() {
             tracing::error!(
@@ -133,8 +135,11 @@ impl Session {
             lcc_command.arg("--mcpu").arg(mcpu);
         }
 
-        let lcc_output =
-            lcc_command.arg(&self.opt_path).arg("-o").arg(&self.out_path).output().unwrap();
+        let lcc_output = lcc_command
+            .arg(&self.opt_path)
+            .arg("-o").arg(&self.out_path)
+            .output()
+            .context("An error occured when calling llc. Make sure the llvm-tools component is installed.")?;
 
         if !lcc_output.status.success() {
             tracing::error!(

From 435db9b9bd404c1bc632fbb6ade8b4ce92c2828c Mon Sep 17 00:00:00 2001
From: Maybe Waffle <waffle.lapkin@gmail.com>
Date: Mon, 15 Apr 2024 13:33:08 +0000
Subject: [PATCH 22/22] Use RPITIT  for `Successors` and `Predecessors` traits

Now with RPITIT instead of GAT!
---
 compiler/rustc_borrowck/src/constraints/graph.rs     |  4 +---
 compiler/rustc_data_structures/src/graph/mod.rs      | 12 ++----------
 .../rustc_data_structures/src/graph/reference.rs     |  8 ++------
 compiler/rustc_data_structures/src/graph/scc/mod.rs  |  4 +---
 compiler/rustc_data_structures/src/graph/tests.rs    | 10 ++--------
 .../rustc_data_structures/src/graph/vec_graph/mod.rs |  4 +---
 compiler/rustc_middle/src/mir/basic_blocks.rs        | 10 +++-------
 compiler/rustc_mir_transform/src/coverage/graph.rs   |  8 ++------
 8 files changed, 14 insertions(+), 46 deletions(-)

diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 2dfaeb3ae7605..540b466560c5d 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -223,9 +223,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph
 }
 
 impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> {
-    type Successors<'g> = Successors<'s, 'tcx, D> where Self: 'g;
-
-    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.outgoing_regions(node)
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 61bee2ee0bba5..3ae3023a91b34 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -25,19 +25,11 @@ pub trait StartNode: DirectedGraph {
 }
 
 pub trait Successors: DirectedGraph {
-    type Successors<'g>: Iterator<Item = Self::Node>
-    where
-        Self: 'g;
-
-    fn successors(&self, node: Self::Node) -> Self::Successors<'_>;
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>;
 }
 
 pub trait Predecessors: DirectedGraph {
-    type Predecessors<'g>: Iterator<Item = Self::Node>
-    where
-        Self: 'g;
-
-    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_>;
+    fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>;
 }
 
 /// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`].
diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs
index 16b019374be7f..7a487552f5385 100644
--- a/compiler/rustc_data_structures/src/graph/reference.rs
+++ b/compiler/rustc_data_structures/src/graph/reference.rs
@@ -15,17 +15,13 @@ impl<'graph, G: StartNode> StartNode for &'graph G {
 }
 
 impl<'graph, G: Successors> Successors for &'graph G {
-    type Successors<'g> = G::Successors<'g> where 'graph: 'g;
-
-    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         (**self).successors(node)
     }
 }
 
 impl<'graph, G: Predecessors> Predecessors for &'graph G {
-    type Predecessors<'g> = G::Predecessors<'g> where 'graph: 'g;
-
-    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
+    fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         (**self).predecessors(node)
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 1cd0edfe57fd4..5021e5e8fc090 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -104,9 +104,7 @@ impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
 }
 
 impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
-    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, S>>;
-
-    fn successors(&self, node: S) -> Self::Successors<'_> {
+    fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> {
         self.successors(node).iter().cloned()
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs
index 118b6bd3eb687..85c2703cc2538 100644
--- a/compiler/rustc_data_structures/src/graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/tests.rs
@@ -1,7 +1,5 @@
 use crate::fx::FxHashMap;
 use std::cmp::max;
-use std::iter;
-use std::slice;
 
 use super::*;
 
@@ -49,17 +47,13 @@ impl StartNode for TestGraph {
 }
 
 impl Predecessors for TestGraph {
-    type Predecessors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
-
-    fn predecessors(&self, node: usize) -> Self::Predecessors<'_> {
+    fn predecessors(&self, node: usize) -> impl Iterator<Item = Self::Node> {
         self.predecessors[&node].iter().cloned()
     }
 }
 
 impl Successors for TestGraph {
-    type Successors<'g> = iter::Cloned<slice::Iter<'g, usize>>;
-
-    fn successors(&self, node: usize) -> Self::Successors<'_> {
+    fn successors(&self, node: usize) -> impl Iterator<Item = Self::Node> {
         self.successors[&node].iter().cloned()
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 3f9d8ec0acabb..26c86469fad84 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -93,9 +93,7 @@ impl<N: Idx> NumEdges for VecGraph<N> {
 }
 
 impl<N: Idx + Ord> Successors for VecGraph<N> {
-    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, N>>;
-
-    fn successors(&self, node: N) -> Self::Successors<'_> {
+    fn successors(&self, node: N) -> impl Iterator<Item = Self::Node> {
         self.successors(node).iter().cloned()
     }
 }
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 36e067c130641..1086d647721b7 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -1,5 +1,5 @@
 use crate::mir::traversal::Postorder;
-use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK};
+use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph;
@@ -156,19 +156,15 @@ impl<'tcx> graph::StartNode for BasicBlocks<'tcx> {
 }
 
 impl<'tcx> graph::Successors for BasicBlocks<'tcx> {
-    type Successors<'b> = Successors<'b> where 'tcx: 'b;
-
     #[inline]
-    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.basic_blocks[node].terminator().successors()
     }
 }
 
 impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> {
-    type Predecessors<'b> = std::iter::Copied<std::slice::Iter<'b, BasicBlock>> where 'tcx: 'b;
-
     #[inline]
-    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
+    fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.predecessors()[node].iter().copied()
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index c187466403f83..1895735ab3523 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -209,19 +209,15 @@ impl graph::StartNode for CoverageGraph {
 }
 
 impl graph::Successors for CoverageGraph {
-    type Successors<'g> = std::iter::Cloned<std::slice::Iter<'g, BasicCoverageBlock>>;
-
     #[inline]
-    fn successors(&self, node: Self::Node) -> Self::Successors<'_> {
+    fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.successors[node].iter().cloned()
     }
 }
 
 impl graph::Predecessors for CoverageGraph {
-    type Predecessors<'g> = std::iter::Copied<std::slice::Iter<'g, BasicCoverageBlock>>;
-
     #[inline]
-    fn predecessors(&self, node: Self::Node) -> Self::Predecessors<'_> {
+    fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.predecessors[node].iter().copied()
     }
 }