about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast/src/token.rs3
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs120
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs15
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs7
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs72
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs5
-rw-r--r--compiler/rustc_error_messages/locales/en-US/middle.ftl9
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl559
-rw-r--r--compiler/rustc_error_messages/locales/en-US/query_system.ftl2
-rw-r--r--compiler/rustc_error_messages/src/lib.rs31
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs57
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs50
-rw-r--r--compiler/rustc_errors/src/emitter.rs4
-rw-r--r--compiler/rustc_errors/src/json.rs4
-rw-r--r--compiler/rustc_errors/src/lib.rs13
-rw-r--r--compiler/rustc_errors/src/translation.rs34
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs126
-rw-r--r--compiler/rustc_expand/src/tokenstream/tests.rs18
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs33
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs9
-rw-r--r--compiler/rustc_interface/src/tests.rs27
-rw-r--r--compiler/rustc_lint/src/errors.rs15
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs27
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs150
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs95
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs108
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs56
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/thir.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs5
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs21
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/query.rs2
-rw-r--r--compiler/rustc_middle/src/values.rs14
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs3
-rw-r--r--compiler/rustc_parse/src/parser/item.rs17
-rw-r--r--compiler/rustc_passes/src/check_attr.rs151
-rw-r--r--compiler/rustc_passes/src/check_const.rs13
-rw-r--r--compiler/rustc_passes/src/dead.rs16
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs15
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs37
-rw-r--r--compiler/rustc_passes/src/entry.rs145
-rw-r--r--compiler/rustc_passes/src/errors.rs785
-rw-r--r--compiler/rustc_passes/src/lang_items.rs207
-rw-r--r--compiler/rustc_passes/src/layout_test.rs71
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/lib_features.rs34
-rw-r--r--compiler/rustc_passes/src/loops.rs161
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs84
-rw-r--r--compiler/rustc_passes/src/stability.rs130
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs29
-rw-r--r--compiler/rustc_query_system/src/error.rs12
-rw-r--r--compiler/rustc_query_system/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs68
-rw-r--r--compiler/rustc_session/src/options.rs106
-rw-r--r--compiler/rustc_session/src/parse.rs13
-rw-r--r--compiler/rustc_session/src/session.rs11
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs3
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs81
-rw-r--r--library/core/src/num/int_macros.rs51
-rw-r--r--library/core/src/num/uint_macros.rs49
-rw-r--r--library/core/tests/num/int_log.rs30
-rw-r--r--library/proc_macro/src/bridge/client.rs4
-rw-r--r--library/std/src/io/readbuf.rs9
-rw-r--r--library/std/src/panicking.rs27
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/doc.rs1
-rw-r--r--src/doc/index.md6
-rw-r--r--src/doc/style-guide/book.toml8
-rw-r--r--src/doc/style-guide/src/README.md190
-rw-r--r--src/doc/style-guide/src/SUMMARY.md11
-rw-r--r--src/doc/style-guide/src/advice.md34
-rw-r--r--src/doc/style-guide/src/cargo.md78
-rw-r--r--src/doc/style-guide/src/expressions.md850
-rw-r--r--src/doc/style-guide/src/items.md565
-rw-r--r--src/doc/style-guide/src/principles.md51
-rw-r--r--src/doc/style-guide/src/statements.md150
-rw-r--r--src/doc/style-guide/src/types.md58
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css57
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css2
-rw-r--r--src/librustdoc/html/static/js/main.js8
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs7
-rw-r--r--src/test/rustdoc-gui/sidebar-links-color.goml126
-rw-r--r--src/test/rustdoc-gui/sidebar-macro-reexport.goml2
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs3
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr17
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs4
-rw-r--r--src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr17
-rw-r--r--src/test/rustdoc-ui/z-help.stdout44
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.rs12
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.stderr8
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs71
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr42
-rw-r--r--src/test/ui/associated-types/issue-85103.rs2
-rw-r--r--src/test/ui/associated-types/issue-85103.stderr2
-rw-r--r--src/test/ui/consts/issue-102117.rs30
-rw-r--r--src/test/ui/consts/issue-102117.stderr37
-rw-r--r--src/test/ui/issues/issue-72554.rs1
-rw-r--r--src/test/ui/issues/issue-72554.stderr20
-rw-r--r--src/test/ui/parser/bad-let-as-field.rs6
-rw-r--r--src/test/ui/parser/bad-let-as-field.stderr15
-rw-r--r--src/test/ui/parser/removed-syntax-field-let-2.rs12
-rw-r--r--src/test/ui/parser/removed-syntax-field-let-2.stderr33
-rw-r--r--src/test/ui/parser/removed-syntax-field-let.stderr10
-rw-r--r--src/test/ui/process/process-panic-after-fork.rs43
-rw-r--r--src/test/ui/variance/variance-regions-unused-indirect.rs1
-rw-r--r--src/test/ui/variance/variance-regions-unused-indirect.stderr30
m---------src/tools/cargo0
-rw-r--r--src/tools/tidy/src/alphabetical.rs113
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--triagebot.toml5
124 files changed, 5241 insertions, 1673 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 340302766d2..60b7f2e4c22 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3039,7 +3039,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(AssocItem, 104);
     static_assert_size!(AssocItemKind, 32);
     static_assert_size!(Attribute, 32);
@@ -3060,11 +3060,12 @@ mod size_asserts {
     static_assert_size!(Local, 72);
     static_assert_size!(Param, 40);
     static_assert_size!(Pat, 120);
-    static_assert_size!(PatKind, 96);
     static_assert_size!(Path, 40);
     static_assert_size!(PathSegment, 24);
+    static_assert_size!(PatKind, 96);
     static_assert_size!(Stmt, 32);
     static_assert_size!(StmtKind, 16);
     static_assert_size!(Ty, 96);
     static_assert_size!(TyKind, 72);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 16224d71e45..83b10d906e2 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -889,10 +889,11 @@ where
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(Lit, 12);
     static_assert_size!(LitKind, 2);
     static_assert_size!(Nonterminal, 16);
     static_assert_size!(Token, 24);
     static_assert_size!(TokenKind, 16);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 4d2049cbc41..015f5c1ee8a 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -245,12 +245,12 @@ impl AttrTokenStream {
                                 // properly implemented - we always synthesize fake tokens,
                                 // so we never reach this code.
 
-                                let mut builder = TokenStreamBuilder::new();
+                                let mut stream = TokenStream::default();
                                 for inner_attr in inner_attrs {
-                                    builder.push(inner_attr.tokens());
+                                    stream.push_stream(inner_attr.tokens());
                                 }
-                                builder.push(delim_tokens.clone());
-                                *tree = TokenTree::Delimited(*span, *delim, builder.build());
+                                stream.push_stream(delim_tokens.clone());
+                                *tree = TokenTree::Delimited(*span, *delim, stream);
                                 found = true;
                                 break;
                             }
@@ -505,76 +505,49 @@ impl TokenStream {
 
         self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
     }
-}
 
-// 99.5%+ of the time we have 1 or 2 elements in this vector.
-#[derive(Clone)]
-pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
-
-impl TokenStreamBuilder {
-    pub fn new() -> TokenStreamBuilder {
-        TokenStreamBuilder(SmallVec::new())
-    }
-
-    pub fn push(&mut self, stream: TokenStream) {
-        self.0.push(stream);
-    }
-
-    pub fn build(self) -> TokenStream {
-        let mut streams = self.0;
-        match streams.len() {
-            0 => TokenStream::default(),
-            1 => streams.pop().unwrap(),
-            _ => {
-                // We will extend the first stream in `streams` with the
-                // elements from the subsequent streams. This requires using
-                // `make_mut()` on the first stream, and in practice this
-                // doesn't cause cloning 99.9% of the time.
-                //
-                // One very common use case is when `streams` has two elements,
-                // where the first stream has any number of elements within
-                // (often 1, but sometimes many more) and the second stream has
-                // a single element within.
-
-                // Determine how much the first stream will be extended.
-                // Needed to avoid quadratic blow up from on-the-fly
-                // reallocations (#57735).
-                let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
-
-                // Get the first stream, which will become the result stream.
-                // If it's `None`, create an empty stream.
-                let mut iter = streams.into_iter();
-                let mut res_stream_lrc = iter.next().unwrap().0;
-
-                // Append the subsequent elements to the result stream, after
-                // reserving space for them.
-                let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
-                res_vec_mut.reserve(num_appends);
-                for stream in iter {
-                    let stream_iter = stream.0.iter().cloned();
-
-                    // If (a) `res_mut_vec` is not empty and the last tree
-                    // within it is a token tree marked with `Joint`, and (b)
-                    // `stream` is not empty and the first tree within it is a
-                    // token tree, and (c) the two tokens can be glued
-                    // together...
-                    if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last()
-                        && let Some(TokenTree::Token(tok, spacing)) = stream.0.first()
-                        && let Some(glued_tok) = last_tok.glue(&tok)
-                    {
-                        // ...then overwrite the last token tree in
-                        // `res_vec_mut` with the glued token, and skip the
-                        // first token tree from `stream`.
-                        *res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
-                        res_vec_mut.extend(stream_iter.skip(1));
-                    } else {
-                        // Append all of `stream`.
-                        res_vec_mut.extend(stream_iter);
-                    }
-                }
+    // If `vec` is not empty, try to glue `tt` onto its last token. The return
+    // value indicates if gluing took place.
+    fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
+        if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
+            && let TokenTree::Token(tok, spacing) = tt
+            && let Some(glued_tok) = last_tok.glue(&tok)
+        {
+            // ...then overwrite the last token tree in `vec` with the
+            // glued token, and skip the first token tree from `stream`.
+            *vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
+            true
+        } else {
+            false
+        }
+    }
 
-                TokenStream(res_stream_lrc)
-            }
+    // Push `tt` onto the end of the stream, possibly gluing it to the last
+    // token. Uses `make_mut` to maximize efficiency.
+    pub fn push_tree(&mut self, tt: TokenTree) {
+        let vec_mut = Lrc::make_mut(&mut self.0);
+
+        if Self::try_glue_to_last(vec_mut, &tt) {
+            // nothing else to do
+        } else {
+            vec_mut.push(tt);
+        }
+    }
+
+    // Push `stream` onto the end of the stream, possibly gluing the first
+    // token tree to the last token. (No other token trees will be glued.)
+    // Uses `make_mut` to maximize efficiency.
+    pub fn push_stream(&mut self, stream: TokenStream) {
+        let vec_mut = Lrc::make_mut(&mut self.0);
+
+        let stream_iter = stream.0.iter().cloned();
+
+        if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
+            // Now skip the first token tree from `stream`.
+            vec_mut.extend(stream_iter.skip(1));
+        } else {
+            // Append all of `stream`.
+            vec_mut.extend(stream_iter);
         }
     }
 }
@@ -673,10 +646,11 @@ impl DelimSpan {
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(AttrTokenStream, 8);
     static_assert_size!(AttrTokenTree, 32);
     static_assert_size!(LazyAttrTokenStream, 8);
     static_assert_size!(TokenStream, 8);
     static_assert_size!(TokenTree, 32);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 63ff64b00be..c6c85ffa84d 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -1,4 +1,7 @@
-use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay};
+use rustc_errors::{
+    fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay,
+    SubdiagnosticMessage,
+};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
@@ -19,7 +22,10 @@ pub struct UseAngleBrackets {
 }
 
 impl AddToDiagnostic for UseAngleBrackets {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         diag.multipart_suggestion(
             fluent::ast_lowering::use_angle_brackets,
             vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
@@ -69,7 +75,10 @@ pub enum AssocTyParenthesesSub {
 }
 
 impl AddToDiagnostic for AssocTyParenthesesSub {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self {
             Self::Empty { parentheses_span } => diag.multipart_suggestion(
                 fluent::ast_lowering::remove_parentheses,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 035f0ce1cbc..ba2ed24fc08 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,6 +1,6 @@
 //! Errors emitted by ast_passes.
 
-use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic};
+use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -17,7 +17,10 @@ pub struct ForbiddenLet {
 }
 
 impl AddToDiagnostic for ForbiddenLetReason {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self {
             Self::GenericForbidden => {}
             Self::NotSupportedOr(span) => {
@@ -228,7 +231,10 @@ pub struct ExternBlockSuggestion {
 }
 
 impl AddToDiagnostic for ExternBlockSuggestion {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         let start_suggestion = if let Some(abi) = self.abi {
             format!("extern \"{}\" {{", abi)
         } else {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6c4b2b3724e..dc0f0e7cd3c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -584,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         // modify their locations.
         let all_facts = &mut None;
         let mut constraints = Default::default();
+        let mut type_tests = Default::default();
         let mut closure_bounds = Default::default();
         let mut liveness_constraints =
             LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
@@ -595,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 &mut this.cx.borrowck_context.constraints.outlives_constraints,
                 &mut constraints,
             );
+            mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
             mem::swap(
                 &mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
                 &mut closure_bounds,
@@ -619,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         swap_constraints(self);
 
         let locations = location.to_locations();
+
+        // Use location of promoted const in collected constraints
+        for type_test in type_tests.iter() {
+            let mut type_test = type_test.clone();
+            type_test.locations = locations;
+            self.cx.borrowck_context.constraints.type_tests.push(type_test)
+        }
         for constraint in constraints.outlives().iter() {
             let mut constraint = constraint.clone();
             constraint.locations = locations;
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 1f577e9f352..a292bfce31e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -15,7 +15,10 @@ use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
-use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{
+    translation::{to_fluent_args, Translate},
+    DiagnosticId, FatalError, Handler, Level,
+};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
@@ -1740,7 +1743,7 @@ impl Translate for SharedEmitter {
 
 impl Emitter for SharedEmitter {
     fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
-        let fluent_args = self.to_fluent_args(diag.args());
+        let fluent_args = to_fluent_args(diag.args());
         drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
             msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
             code: diag.code.clone(),
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index f1674d04f8d..cdcebb61c2e 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -25,12 +25,10 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
 /// `Constness::NotConst`.
 fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
-    let def_id = def_id.expect_local();
-    let node = tcx.hir().get_by_def_id(def_id);
-
-    match node {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    match tcx.hir().get(hir_id) {
         hir::Node::Ctor(_) => hir::Constness::Const,
-        hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
+
         hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
             // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
             // foreign items cannot be evaluated at compile-time.
@@ -41,20 +39,62 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
             };
             if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
         }
-        _ => {
-            if let Some(fn_kind) = node.fn_kind() {
-                if fn_kind.constness() == hir::Constness::Const {
-                    return hir::Constness::Const;
-                }
 
-                // If the function itself is not annotated with `const`, it may still be a `const fn`
-                // if it resides in a const trait impl.
-                let is_const = is_parent_const_impl_raw(tcx, def_id);
-                if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
-            } else {
-                hir::Constness::NotConst
+        hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+            if tcx.is_const_default_method(def_id) =>
+        {
+            hir::Constness::Const
+        }
+
+        hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
+        | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
+        | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
+        | hir::Node::AnonConst(_)
+        | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
+        | hir::Node::ImplItem(hir::ImplItem {
+            kind:
+                hir::ImplItemKind::Fn(
+                    hir::FnSig {
+                        header: hir::FnHeader { constness: hir::Constness::Const, .. },
+                        ..
+                    },
+                    ..,
+                ),
+            ..
+        }) => hir::Constness::Const,
+
+        hir::Node::ImplItem(hir::ImplItem {
+            kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
+            ..
+        }) => {
+            let parent_hir_id = tcx.hir().get_parent_node(hir_id);
+            match tcx.hir().get(parent_hir_id) {
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+                    ..
+                }) => *constness,
+                _ => span_bug!(
+                    tcx.def_span(parent_hir_id.owner),
+                    "impl item's parent node is not an impl",
+                ),
             }
         }
+
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
+            ..
+        })
+        | hir::Node::TraitItem(hir::TraitItem {
+            kind:
+                hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
+            ..
+        })
+        | hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+            ..
+        }) => *constness,
+
+        _ => hir::Constness::NotConst,
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 510adde6296..719588a936c 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -788,9 +788,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(Immediate, 48);
     static_assert_size!(ImmTy<'_>, 64);
     static_assert_size!(Operand, 56);
     static_assert_size!(OpTy<'_>, 80);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index eeeb7d6d3e5..b0625b5f412 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -892,10 +892,11 @@ where
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(MemPlaceMeta, 24);
+    // tidy-alphabetical-start
     static_assert_size!(MemPlace, 40);
+    static_assert_size!(MemPlaceMeta, 24);
     static_assert_size!(MPlaceTy<'_>, 64);
     static_assert_size!(Place, 40);
     static_assert_size!(PlaceTy<'_>, 64);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl
index ca3c91ce24a..b9e4499d47f 100644
--- a/compiler/rustc_error_messages/locales/en-US/middle.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl
@@ -18,3 +18,12 @@ middle_limit_invalid =
 
 middle_const_eval_non_int =
     constant evaluation of enum discriminant resulted in non-integer
+
+middle_unknown_layout =
+    the type `{$ty}` has an unknown layout
+
+middle_values_too_big =
+    values of the type `{$ty}` are too big for the current architecture
+
+middle_cannot_be_normalized =
+    unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 995ad4fe258..1f1c9c29d66 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -10,88 +10,119 @@ passes_outer_crate_level_attr =
 passes_inner_crate_level_attr =
     crate-level attribute should be in the root module
 
-passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs
+passes_ignored_attr_with_macro =
+    `#[{$sym}]` is ignored on struct fields, match arms and macro defs
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "80564")}
 
-passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms
+passes_ignored_attr =
+    `#[{$sym}]` is ignored on struct fields and match arms
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "80564")}
 
-passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes
+passes_inline_ignored_function_prototype =
+    `#[inline]` is ignored on function prototypes
 
-passes_inline_ignored_constants = `#[inline]` is ignored on constants
+passes_inline_ignored_constants =
+    `#[inline]` is ignored on constants
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "65833")}
 
-passes_inline_not_fn_or_closure = attribute should be applied to function or closure
+passes_inline_not_fn_or_closure =
+    attribute should be applied to function or closure
     .label = not a function or closure
 
-passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes
+passes_no_coverage_ignored_function_prototype =
+    `#[no_coverage]` is ignored on function prototypes
 
 passes_no_coverage_propagate =
     `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
 
-passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions
+passes_no_coverage_fn_defn =
+    `#[no_coverage]` may only be applied to function definitions
 
-passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code
+passes_no_coverage_not_coverable =
+    `#[no_coverage]` must be applied to coverable code
     .label = not coverable code
 
-passes_should_be_applied_to_fn = attribute should be applied to a function definition
+passes_should_be_applied_to_fn =
+    attribute should be applied to a function definition
     .label = not a function definition
 
-passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]`
+passes_naked_tracked_caller =
+    cannot use `#[track_caller]` with `#[naked]`
 
-passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum
+passes_should_be_applied_to_struct_enum =
+    attribute should be applied to a struct or enum
     .label = not a struct or enum
 
-passes_should_be_applied_to_trait = attribute should be applied to a trait
+passes_should_be_applied_to_trait =
+    attribute should be applied to a trait
     .label = not a trait
 
-passes_target_feature_on_statement = {passes_should_be_applied_to_fn}
+passes_target_feature_on_statement =
+    {passes_should_be_applied_to_fn}
     .warn = {-passes_previously_accepted}
     .label = {passes_should_be_applied_to_fn.label}
 
-passes_should_be_applied_to_static = attribute should be applied to a static
+passes_should_be_applied_to_static =
+    attribute should be applied to a static
     .label = not a static
 
-passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
+passes_doc_expect_str =
+    doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
 
-passes_doc_alias_empty = {$attr_str} attribute cannot have empty value
+passes_doc_alias_empty =
+    {$attr_str} attribute cannot have empty value
 
-passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str}
+passes_doc_alias_bad_char =
+    {$char_} character isn't allowed in {$attr_str}
 
-passes_doc_alias_start_end = {$attr_str} cannot start or end with ' '
+passes_doc_alias_start_end =
+    {$attr_str} cannot start or end with ' '
 
-passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location}
+passes_doc_alias_bad_location =
+    {$attr_str} isn't allowed on {$location}
 
-passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name
+passes_doc_alias_not_an_alias =
+    {$attr_str} is the same as the item's name
 
 passes_doc_alias_duplicated = doc alias is duplicated
     .label = first defined here
 
-passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals
+passes_doc_alias_not_string_literal =
+    `#[doc(alias("a"))]` expects string literals
 
 passes_doc_alias_malformed =
     doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
 
-passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules
+passes_doc_keyword_empty_mod =
+    `#[doc(keyword = "...")]` should be used on empty modules
 
-passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules
+passes_doc_keyword_not_mod =
+    `#[doc(keyword = "...")]` should be used on modules
 
-passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier
+passes_doc_keyword_invalid_ident =
+    `{$doc_keyword}` is not a valid identifier
 
 passes_doc_fake_variadic_not_valid =
     `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
 
-passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks
+passes_doc_keyword_only_impl =
+    `#[doc(keyword = "...")]` should be used on impl blocks
 
-passes_doc_inline_conflict_first = this attribute...
-passes_doc_inline_conflict_second = ...conflicts with this attribute
-passes_doc_inline_conflict = conflicting doc inlining attributes
+passes_doc_inline_conflict_first =
+    this attribute...
+
+passes_doc_inline_conflict_second =
+    {"."}..conflicts with this attribute
+
+passes_doc_inline_conflict =
+    conflicting doc inlining attributes
     .help = remove one of the conflicting attributes
 
-passes_doc_inline_only_use = this attribute can only be applied to a `use` item
+passes_doc_inline_only_use =
+    this attribute can only be applied to a `use` item
     .label = only applicable on `use` items
     .not_a_use_item_label = not a `use` item
     .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
@@ -99,30 +130,39 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item
 passes_doc_attr_not_crate_level =
     `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
 
-passes_attr_crate_level = this attribute can only be applied at the crate level
+passes_attr_crate_level =
+    this attribute can only be applied at the crate level
     .suggestion = to apply to the crate, use an inner attribute
     .help = to apply to the crate, use an inner attribute
     .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
 
-passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}`
+passes_doc_test_unknown =
+    unknown `doc(test)` attribute `{$path}`
 
-passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes
+passes_doc_test_takes_list =
+    `#[doc(test(...)]` takes a list of attributes
 
-passes_doc_primitive = `doc(primitive)` should never have been stable
+passes_doc_primitive =
+    `doc(primitive)` should never have been stable
 
-passes_doc_test_unknown_any = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_any =
+    unknown `doc` attribute `{$path}`
 
-passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_spotlight =
+    unknown `doc` attribute `{$path}`
     .note = `doc(spotlight)` was renamed to `doc(notable_trait)`
     .suggestion = use `notable_trait` instead
     .no_op_note = `doc(spotlight)` is now a no-op
 
-passes_doc_test_unknown_include = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_include =
+    unknown `doc` attribute `{$path}`
     .suggestion = use `doc = include_str!` instead
 
-passes_doc_invalid = invalid `doc` attribute
+passes_doc_invalid =
+    invalid `doc` attribute
 
-passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias
+passes_pass_by_value =
+    `pass_by_value` attribute should be applied to a struct, enum or type alias
     .label = is not a struct, enum or type alias
 
 passes_allow_incoherent_impl =
@@ -137,42 +177,54 @@ passes_must_use_async =
     `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
     .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
 
-passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target}
+passes_must_use_no_effect =
+    `#[must_use]` has no effect when applied to {$article} {$target}
 
-passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait
+passes_must_not_suspend =
+    `must_not_suspend` attribute should be applied to a struct, enum, or trait
     .label = is not a struct, enum, or trait
 
-passes_cold = {passes_should_be_applied_to_fn}
+passes_cold =
+    {passes_should_be_applied_to_fn}
     .warn = {-passes_previously_accepted}
     .label = {passes_should_be_applied_to_fn.label}
 
-passes_link = attribute should be applied to an `extern` block with non-Rust ABI
+passes_link =
+    attribute should be applied to an `extern` block with non-Rust ABI
     .warn = {-passes_previously_accepted}
     .label = not an `extern` block
 
-passes_link_name = attribute should be applied to a foreign function or static
+passes_link_name =
+    attribute should be applied to a foreign function or static
     .warn = {-passes_previously_accepted}
     .label = not a foreign function or static
     .help = try `#[link(name = "{$value}")]` instead
 
-passes_no_link = attribute should be applied to an `extern crate` item
+passes_no_link =
+    attribute should be applied to an `extern crate` item
     .label = not an `extern crate` item
 
-passes_export_name = attribute should be applied to a free function, impl method or static
+passes_export_name =
+    attribute should be applied to a free function, impl method or static
     .label = not a free function, impl method or static
 
-passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct
+passes_rustc_layout_scalar_valid_range_not_struct =
+    attribute should be applied to a struct
     .label = not a struct
 
-passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument
+passes_rustc_layout_scalar_valid_range_arg =
+    expected exactly one integer literal argument
 
-passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics
+passes_rustc_legacy_const_generics_only =
+    #[rustc_legacy_const_generics] functions must only have const generics
     .label = non-const generic parameter
 
-passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter
+passes_rustc_legacy_const_generics_index =
+    #[rustc_legacy_const_generics] must have one index for each generic parameter
     .label = generic parameters
 
-passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments
+passes_rustc_legacy_const_generics_index_exceed =
+    index exceeds number of arguments
     .label = there {$arg_count ->
         [one] is
         *[other] are
@@ -181,93 +233,438 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume
         *[other] arguments
     }
 
-passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers
+passes_rustc_legacy_const_generics_index_negative =
+    arguments should be non-negative integers
 
-passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled
+passes_rustc_dirty_clean =
+    attribute requires -Z query-dep-graph to be enabled
 
-passes_link_section = attribute should be applied to a function or static
+passes_link_section =
+    attribute should be applied to a function or static
     .warn = {-passes_previously_accepted}
     .label = not a function or static
 
-passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+passes_no_mangle_foreign =
+    `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
     .warn = {-passes_previously_accepted}
     .label = foreign {$foreign_item_kind}
     .note = symbol names in extern blocks are not mangled
     .suggestion = remove this attribute
 
-passes_no_mangle = attribute should be applied to a free function, impl method or static
+passes_no_mangle =
+    attribute should be applied to a free function, impl method or static
     .warn = {-passes_previously_accepted}
     .label = not a free function, impl method or static
 
-passes_repr_ident = meta item in `repr` must be an identifier
+passes_repr_ident =
+    meta item in `repr` must be an identifier
 
-passes_repr_conflicting = conflicting representation hints
+passes_repr_conflicting =
+    conflicting representation hints
 
-passes_used_static = attribute must be applied to a `static` variable
+passes_used_static =
+    attribute must be applied to a `static` variable
 
-passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together
+passes_used_compiler_linker =
+    `used(compiler)` and `used(linker)` can't be used together
 
-passes_allow_internal_unstable = attribute should be applied to a macro
+passes_allow_internal_unstable =
+    attribute should be applied to a macro
     .label = not a macro
 
-passes_debug_visualizer_placement = attribute should be applied to a module
+passes_debug_visualizer_placement =
+    attribute should be applied to a module
 
-passes_debug_visualizer_invalid = invalid argument
+passes_debug_visualizer_invalid =
+    invalid argument
     .note_1 = expected: `natvis_file = "..."`
     .note_2 = OR
     .note_3 = expected: `gdb_script_file = "..."`
 
-passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn`
+passes_debug_visualizer_unreadable =
+    couldn't read {$file}: {$error}
+
+passes_rustc_allow_const_fn_unstable =
+    attribute should be applied to `const fn`
     .label = not a `const fn`
 
-passes_rustc_std_internal_symbol = attribute should be applied to functions or statics
+passes_rustc_std_internal_symbol =
+    attribute should be applied to functions or statics
     .label = not a function or static
 
-passes_const_trait = attribute should be applied to a trait
+passes_const_trait =
+    attribute should be applied to a trait
 
-passes_stability_promotable = attribute cannot be applied to an expression
+passes_stability_promotable =
+    attribute cannot be applied to an expression
 
-passes_deprecated = attribute is ignored here
+passes_deprecated =
+    attribute is ignored here
 
-passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules
+passes_macro_use =
+    `#[{$name}]` only has an effect on `extern crate` and modules
 
-passes_macro_export = `#[macro_export]` only has an effect on macro definitions
+passes_macro_export =
+    `#[macro_export]` only has an effect on macro definitions
 
-passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions
+passes_plugin_registrar =
+    `#[plugin_registrar]` only has an effect on functions
 
-passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect
+passes_unused_empty_lints_note =
+    attribute `{$name}` with an empty list has no effect
 
-passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect
+passes_unused_no_lints_note =
+    attribute `{$name}` without any lints has no effect
 
 passes_unused_default_method_body_const_note =
     `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
 
-passes_unused = unused attribute
+passes_unused =
+    unused attribute
     .suggestion = remove this attribute
 
-passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure
+passes_non_exported_macro_invalid_attrs =
+    attribute should be applied to function or closure
     .label = not a function or closure
 
-passes_unused_duplicate = unused attribute
+passes_unused_duplicate =
+    unused attribute
     .suggestion = remove this attribute
     .note = attribute also specified here
     .warn = {-passes_previously_accepted}
 
-passes_unused_multiple = multiple `{$name}` attributes
+passes_unused_multiple =
+    multiple `{$name}` attributes
     .suggestion = remove this attribute
     .note = attribute also specified here
 
-passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct
+passes_rustc_lint_opt_ty =
+    `#[rustc_lint_opt_ty]` should be applied to a struct
     .label = not a struct
 
-passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
+passes_rustc_lint_opt_deny_field_access =
+    `#[rustc_lint_opt_deny_field_access]` should be applied to a field
     .label = not a field
 
-passes_link_ordinal = attribute should be applied to a foreign function or static
+passes_link_ordinal =
+    attribute should be applied to a foreign function or static
     .label = not a foreign function or static
 
-passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions
+passes_collapse_debuginfo =
+    `collapse_debuginfo` attribute should be applied to macro definitions
     .label = not a macro definition
 
-passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
+passes_deprecated_annotation_has_no_effect =
+    this `#[deprecated]` annotation has no effect
     .suggestion = remove the unnecessary deprecation attribute
+
+passes_unknown_external_lang_item =
+    unknown external lang item: `{$lang_item}`
+
+passes_missing_panic_handler =
+    `#[panic_handler]` function required, but not found
+
+passes_alloc_func_required =
+    `#[alloc_error_handler]` function required, but not found
+
+passes_missing_alloc_error_handler =
+    use `#![feature(default_alloc_error_handler)]` for a default error handler
+
+passes_missing_lang_item =
+    language item required, but not found: `{$name}`
+    .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
+    .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
+
+passes_lang_item_on_incorrect_target =
+    `{$name}` language item must be applied to a {$expected_target}
+    .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
+
+passes_unknown_lang_item =
+    definition of an unknown language item: `{$name}`
+    .label = definition of unknown language item `{$name}`
+
+passes_invalid_attr_at_crate_level =
+    `{$name}` attribute cannot be used at crate level
+    .suggestion = perhaps you meant to use an outer attribute
+
+passes_duplicate_diagnostic_item =
+    duplicate diagnostic item found: `{$name}`.
+
+passes_duplicate_diagnostic_item_in_crate =
+    duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+
+passes_diagnostic_item_first_defined =
+    the diagnostic item is first defined here
+    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
+
+passes_abi =
+    abi: {$abi}
+
+passes_align =
+    align: {$align}
+
+passes_size =
+    size: {$size}
+
+passes_homogeneous_aggregate =
+    homogeneous_aggregate: {$homogeneous_aggregate}
+
+passes_layout_of =
+    layout_of({$normalized_ty}) = {$ty_layout}
+
+passes_unrecognized_field =
+    unrecognized field name `{$name}`
+
+passes_layout =
+    layout error: {$layout_error}
+
+passes_feature_stable_twice =
+    feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+
+passes_feature_previously_declared =
+    feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+
+passes_expr_not_allowed_in_context =
+    {$expr} is not allowed in a `{$context}`
+
+passes_const_impl_const_trait =
+    const `impl`s must be for traits marked with `#[const_trait]`
+    .note = this trait must be annotated with `#[const_trait]`
+
+passes_break_non_loop =
+    `break` with value from a `{$kind}` loop
+    .label = can only break with a value inside `loop` or breakable block
+    .label2 = you can't `break` with a value in a `{$kind}` loop
+    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
+    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+
+passes_continue_labeled_block =
+    `continue` pointing to a labeled block
+    .label = labeled blocks cannot be `continue`'d
+    .block_label = labeled block the `continue` points to
+
+passes_break_inside_closure =
+    `{$name}` inside of a closure
+    .label = cannot `{$name}` inside of a closure
+    .closure_label = enclosing closure
+
+passes_break_inside_async_block =
+    `{$name}` inside of an `async` block
+    .label = cannot `{$name}` inside of an `async` block
+    .async_block_label = enclosing `async` block
+
+passes_outside_loop =
+    `{$name}` outside of a loop
+    .label = cannot `{$name}` outside of a loop
+
+passes_unlabeled_in_labeled_block =
+    unlabeled `{$cf_type}` inside of a labeled block
+    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
+
+passes_unlabeled_cf_in_while_condition =
+    `break` or `continue` with no label in the condition of a `while` loop
+    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+
+passes_cannot_inline_naked_function =
+    naked functions cannot be inlined
+
+passes_undefined_naked_function_abi =
+    Rust ABI is unsupported in naked functions
+
+passes_no_patterns =
+    patterns not allowed in naked function parameters
+
+passes_params_not_allowed =
+    referencing function parameters is not allowed in naked functions
+    .help = follow the calling convention in asm block to use parameters
+
+passes_naked_functions_asm_block =
+    naked functions must contain a single asm block
+    .label_multiple_asm = multiple asm blocks are unsupported in naked functions
+    .label_non_asm = non-asm is unsupported in naked functions
+
+passes_naked_functions_operands =
+    only `const` and `sym` operands are supported in naked functions
+
+passes_naked_functions_asm_options =
+    asm options unsupported in naked functions: {$unsupported_options}
+
+passes_naked_functions_must_use_noreturn =
+    asm in naked functions must use `noreturn` option
+    .suggestion = consider specifying that the asm block is responsible for returning from the function
+
+passes_attr_only_on_main =
+    `{$attr}` attribute can only be used on `fn main()`
+
+passes_attr_only_on_root_main =
+    `{$attr}` attribute can only be used on root `fn main()`
+
+passes_attr_only_in_functions =
+    `{$attr}` attribute can only be used on functions
+
+passes_multiple_rustc_main =
+    multiple functions with a `#[rustc_main]` attribute
+    .first = first `#[rustc_main]` function
+    .additional = additional `#[rustc_main]` function
+
+passes_multiple_start_functions =
+    multiple `start` functions
+    .label = multiple `start` functions
+    .previous = previous `#[start]` function here
+
+passes_extern_main =
+    the `main` function cannot be declared in an `extern` block
+
+passes_unix_sigpipe_values =
+    valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+
+passes_no_main_function =
+    `main` function not found in crate `{$crate_name}`
+    .here_is_main = here is a function named `main`
+    .one_or_more_possible_main = you have one or more functions named `main` not defined at the crate level
+    .consider_moving_main = consider moving the `main` function definitions
+    .main_must_be_defined_at_crate = the main function must be defined at the crate level{$has_filename ->
+        [true] {" "}(in `{$filename}`)
+        *[false] {""}
+    }
+    .consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
+    .consider_adding_main_at_crate = consider adding a `main` function at the crate level
+    .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
+    .non_function_main = non-function item at `crate::main` is found
+
+passes_duplicate_lang_item =
+    found duplicate lang item `{$lang_item_name}`
+    .first_defined_span = the lang item is first defined here
+    .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+    .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+    .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+    .second_definition_local = second definition in the local crate (`{$crate_name}`)
+    .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+    .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+
+passes_duplicate_lang_item_crate =
+    duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`.
+    .first_defined_span = the lang item is first defined here
+    .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+    .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+    .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+    .second_definition_local = second definition in the local crate (`{$crate_name}`)
+    .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+    .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+
+passes_duplicate_lang_item_crate_depends =
+    duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`.
+    .first_defined_span = the lang item is first defined here
+    .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+    .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+    .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+    .second_definition_local = second definition in the local crate (`{$crate_name}`)
+    .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+    .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+
+passes_incorrect_target =
+    `{$name}` language item must be applied to a {$kind} with {$at_least ->
+        [true] at least {$num}
+        *[false] {$num}
+    } generic {$num ->
+        [one] argument
+        *[other] arguments
+    }
+    .label = this {$kind} has {$actual_num} generic {$actual_num ->
+        [one] argument
+        *[other] arguments
+    }
+
+passes_useless_assignment =
+    useless assignment of {$is_field_assign ->
+        [true] field
+        *[false] variable
+    } of type `{$ty}` to itself
+
+passes_only_has_effect_on =
+    `#[{$attr_name}]` only has an effect on {$target_name ->
+        [function] functions
+        [module] modules
+        [implementation_block] implementation blocks
+        *[unspecified] (unspecified--this is a compiler bug)
+    }
+
+passes_object_lifetime_err =
+    {$repr}
+
+passes_unrecognized_repr_hint =
+    unrecognized representation hint
+    .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+passes_attr_application_enum =
+    attribute should be applied to an enum
+    .label = not an enum
+
+passes_attr_application_struct =
+    attribute should be applied to a struct
+    .label = not a struct
+
+passes_attr_application_struct_union =
+    attribute should be applied to a struct or union
+    .label = not a struct or union
+
+passes_attr_application_struct_enum_union =
+    attribute should be applied to a struct, enum, or union
+    .label = not a struct, enum, or union
+
+passes_attr_application_struct_enum_function_union =
+    attribute should be applied to a struct, enum, function, or union
+    .label = not a struct, enum, function, or union
+
+passes_transparent_incompatible =
+    transparent {$target} cannot have other repr hints
+
+passes_deprecated_attribute =
+    deprecated attribute must be paired with either stable or unstable attribute
+
+passes_useless_stability =
+    this stability annotation is useless
+    .label = useless stability annotation
+    .item = the stability attribute annotates this item
+
+passes_invalid_stability =
+    invalid stability version found
+    .label = invalid stability version
+    .item = the stability attribute annotates this item
+
+passes_cannot_stabilize_deprecated =
+    an API can't be stabilized after it is deprecated
+    .label = invalid version
+    .item = the stability attribute annotates this item
+
+passes_invalid_deprecation_version =
+    invalid deprecation version found
+    .label = invalid deprecation version
+    .item = the stability attribute annotates this item
+
+passes_missing_stability_attr =
+    {$descr} has missing stability attribute
+
+passes_missing_const_stab_attr =
+    {$descr} has missing const stability attribute
+
+passes_trait_impl_const_stable =
+    trait implementations cannot be const stable yet
+    .note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+
+passes_feature_only_on_nightly =
+    `#![feature]` may not be used on the {$release_channel} release channel
+
+passes_unknown_feature =
+    unknown feature `{$feature}`
+
+passes_implied_feature_not_exist =
+    feature `{$implied_by}` implying `{$feature}` does not exist
+
+passes_duplicate_feature_err =
+    the feature `{$feature}` has already been declared
+
+passes_missing_const_err =
+    attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    .help = make the function or method const
+    .label = attribute specified here
diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl
index b914ba52a73..870e824039c 100644
--- a/compiler/rustc_error_messages/locales/en-US/query_system.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl
@@ -12,6 +12,8 @@ query_system_cycle_usage = cycle used when {$usage}
 
 query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
 
+query_system_cycle_stack_middle = ...which requires {$desc}...
+
 query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
 
 query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a2d507328b3..a6024044ad8 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -35,6 +35,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
 
 // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
 fluent_messages! {
+    // tidy-alphabetical-start
     ast_lowering => "../locales/en-US/ast_lowering.ftl",
     ast_passes => "../locales/en-US/ast_passes.ftl",
     attr => "../locales/en-US/attr.ftl",
@@ -64,6 +65,7 @@ fluent_messages! {
     symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
     trait_selection => "../locales/en-US/trait_selection.ftl",
     ty_utils => "../locales/en-US/ty_utils.ftl",
+    // tidy-alphabetical-end
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
@@ -277,6 +279,18 @@ pub enum SubdiagnosticMessage {
     /// Non-translatable diagnostic message.
     // FIXME(davidtwco): can a `Cow<'static, str>` be used here?
     Str(String),
+    /// Translatable message which has already been translated eagerly.
+    ///
+    /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
+    /// be instantiated multiple times with different values. As translation normally happens
+    /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
+    /// the setting of diagnostic arguments in the derived code will overwrite previous variable
+    /// values and only the final value will be set when translation occurs - resulting in
+    /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
+    /// happening immediately after the subdiagnostic derive's logic has been run. This variant
+    /// stores messages which have been translated eagerly.
+    // FIXME(#100717): can a `Cow<'static, str>` be used here?
+    Eager(String),
     /// Identifier of a Fluent message. Instances of this variant are generated by the
     /// `Subdiagnostic` derive.
     FluentIdentifier(FluentId),
@@ -304,8 +318,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
 #[rustc_diagnostic_item = "DiagnosticMessage"]
 pub enum DiagnosticMessage {
     /// Non-translatable diagnostic message.
-    // FIXME(davidtwco): can a `Cow<'static, str>` be used here?
+    // FIXME(#100717): can a `Cow<'static, str>` be used here?
     Str(String),
+    /// Translatable message which has already been translated eagerly.
+    ///
+    /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
+    /// be instantiated multiple times with different values. As translation normally happens
+    /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
+    /// the setting of diagnostic arguments in the derived code will overwrite previous variable
+    /// values and only the final value will be set when translation occurs - resulting in
+    /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
+    /// happening immediately after the subdiagnostic derive's logic has been run. This variant
+    /// stores messages which have been translated eagerly.
+    // FIXME(#100717): can a `Cow<'static, str>` be used here?
+    Eager(String),
     /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
     /// message.
     ///
@@ -324,6 +350,7 @@ impl DiagnosticMessage {
     pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
         let attr = match sub {
             SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
+            SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
             SubdiagnosticMessage::FluentIdentifier(id) => {
                 return DiagnosticMessage::FluentIdentifier(id, None);
             }
@@ -332,6 +359,7 @@ impl DiagnosticMessage {
 
         match self {
             DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
+            DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
             DiagnosticMessage::FluentIdentifier(id, _) => {
                 DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
             }
@@ -367,6 +395,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
     fn into(self) -> SubdiagnosticMessage {
         match self {
             DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
+            DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
             DiagnosticMessage::FluentIdentifier(id, None) => {
                 SubdiagnosticMessage::FluentIdentifier(id)
             }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index b32fc3c719b..f14b8ee3254 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -7,7 +7,7 @@
 
 use crate::emitter::FileWithAnnotatedLines;
 use crate::snippet::Line;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
 use crate::{
     CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
     LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
@@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
 impl Emitter for AnnotateSnippetEmitterWriter {
     /// The entry point for the diagnostics generation
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
-        let fluent_args = self.to_fluent_args(diag.args());
+        let fluent_args = to_fluent_args(diag.args());
 
         let mut children = diag.children.clone();
         let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 31e410aaaf0..3e0840caaa6 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -27,7 +27,11 @@ pub struct SuggestionsDisabled;
 /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
 /// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
 /// diagnostic emission.
-pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>);
+pub type DiagnosticArg<'iter, 'source> =
+    (&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>);
+
+/// Name of a diagnostic argument.
+pub type DiagnosticArgName<'source> = Cow<'source, str>;
 
 /// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
 /// to a `FluentValue` by the emitter to be used in diagnostic translation.
@@ -199,9 +203,20 @@ impl IntoDiagnosticArg for ast::token::TokenKind {
 /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
 #[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
 #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
-pub trait AddToDiagnostic {
+pub trait AddToDiagnostic
+where
+    Self: Sized,
+{
     /// Add a subdiagnostic to an existing diagnostic.
-    fn add_to_diagnostic(self, diag: &mut Diagnostic);
+    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+        self.add_to_diagnostic_with(diag, |_, m| m);
+    }
+
+    /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
+    /// (to optionally perform eager translation).
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage;
 }
 
 /// Trait implemented by lint types. This should not be implemented manually. Instead, use
@@ -229,7 +244,7 @@ pub struct Diagnostic {
     pub span: MultiSpan,
     pub children: Vec<SubDiagnostic>,
     pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
-    args: Vec<DiagnosticArg<'static>>,
+    args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
 
     /// This is not used for highlighting or rendering any error message.  Rather, it can be used
     /// as a sort key to sort a buffer of diagnostics.  By default, it is the primary span of
@@ -321,7 +336,7 @@ impl Diagnostic {
             span: MultiSpan::new(),
             children: vec![],
             suggestions: Ok(vec![]),
-            args: vec![],
+            args: Default::default(),
             sort_span: DUMMY_SP,
             is_lint: false,
         }
@@ -917,13 +932,30 @@ impl Diagnostic {
         self
     }
 
-    /// Add a subdiagnostic from a type that implements `Subdiagnostic` - see
-    /// [rustc_macros::Subdiagnostic].
+    /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
+    /// [rustc_macros::Subdiagnostic]).
     pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
         subdiagnostic.add_to_diagnostic(self);
         self
     }
 
+    /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
+    /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
+    /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
+    /// interpolated variables).
+    pub fn eager_subdiagnostic(
+        &mut self,
+        handler: &crate::Handler,
+        subdiagnostic: impl AddToDiagnostic,
+    ) -> &mut Self {
+        subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
+            let args = diag.args();
+            let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
+            handler.eagerly_translate(msg, args)
+        });
+        self
+    }
+
     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
         self.span = sp.into();
         if let Some(span) = self.span.primary_span() {
@@ -956,8 +988,11 @@ impl Diagnostic {
         self
     }
 
-    pub fn args(&self) -> &[DiagnosticArg<'static>] {
-        &self.args
+    // Exact iteration order of diagnostic arguments shouldn't make a difference to output because
+    // they're only used in interpolation.
+    #[allow(rustc::potential_query_instability)]
+    pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
+        self.args.iter()
     }
 
     pub fn set_arg(
@@ -965,7 +1000,7 @@ impl Diagnostic {
         name: impl Into<Cow<'static, str>>,
         arg: impl IntoDiagnosticArg,
     ) -> &mut Self {
-        self.args.push((name.into(), arg.into_diagnostic_arg()));
+        self.args.insert(name.into(), arg.into_diagnostic_arg());
         self
     }
 
@@ -976,7 +1011,7 @@ impl Diagnostic {
     /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
     /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
     /// passes the user's string along).
-    fn subdiagnostic_message_to_diagnostic_message(
+    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
         &self,
         attr: impl Into<SubdiagnosticMessage>,
     ) -> DiagnosticMessage {
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index bbe6435be59..9b41234dcfb 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -255,6 +255,56 @@ impl EmissionGuarantee for () {
     }
 }
 
+/// Marker type which enables implementation of `create_note` and `emit_note` functions for
+/// note-without-error struct diagnostics.
+#[derive(Copy, Clone)]
+pub struct Noted;
+
+impl<'a> DiagnosticBuilder<'a, Noted> {
+    /// Convenience function for internal use, clients should use one of the
+    /// `struct_*` methods on [`Handler`].
+    pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
+        let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
+        Self::new_diagnostic_note(handler, diagnostic)
+    }
+
+    /// Creates a new `DiagnosticBuilder` with an already constructed
+    /// diagnostic.
+    pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+        debug!("Created new diagnostic");
+        Self {
+            inner: DiagnosticBuilderInner {
+                state: DiagnosticBuilderState::Emittable(handler),
+                diagnostic: Box::new(diagnostic),
+            },
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl EmissionGuarantee for Noted {
+    fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+        match db.inner.state {
+            // First `.emit()` call, the `&Handler` is still available.
+            DiagnosticBuilderState::Emittable(handler) => {
+                db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+                handler.emit_diagnostic(&mut db.inner.diagnostic);
+            }
+            // `.emit()` was previously called, disallowed from repeating it.
+            DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+        }
+
+        Noted
+    }
+
+    fn make_diagnostic_builder(
+        handler: &Handler,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, Self> {
+        DiagnosticBuilder::new_note(handler, msg)
+    }
+}
+
 impl<'a> DiagnosticBuilder<'a, !> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 66fbb8f1213..cd6413bc3ec 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span};
 
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
 use crate::styled_buffer::StyledBuffer;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
 use crate::{
     CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
     LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
@@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
     }
 
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
-        let fluent_args = self.to_fluent_args(diag.args());
+        let fluent_args = to_fluent_args(diag.args());
 
         let mut children = diag.children.clone();
         let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1680c6accd7..4cc7be47fc2 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -13,7 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
 
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
 use crate::DiagnosticId;
 use crate::{
     CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
@@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
 
 impl Diagnostic {
     fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
-        let args = je.to_fluent_args(diag.args());
+        let args = to_fluent_args(diag.args());
         let sugg = diag.suggestions.iter().flatten().map(|sugg| {
             let translated_message = je.translate_message(&sugg.msg, &args);
             Diagnostic {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2f6686f8196..b16c54e0aac 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -374,7 +374,7 @@ pub use diagnostic::{
     AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
     DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
-pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
+pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
 use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
@@ -598,6 +598,17 @@ impl Handler {
         }
     }
 
+    /// Translate `message` eagerly with `args`.
+    pub fn eagerly_translate<'a>(
+        &self,
+        message: DiagnosticMessage,
+        args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
+    ) -> SubdiagnosticMessage {
+        let inner = self.inner.borrow();
+        let args = crate::translation::to_fluent_args(args);
+        SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string())
+    }
+
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc_middle.
     pub fn can_emit_warnings(&self) -> bool {
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index 4f407badb3f..a7737b467b7 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
 use rustc_error_messages::FluentArgs;
 use std::borrow::Cow;
 
+/// Convert diagnostic arguments (a rustc internal type that exists to implement
+/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
+///
+/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
+/// passed around as a reference thereafter.
+pub fn to_fluent_args<'iter, 'arg: 'iter>(
+    iter: impl Iterator<Item = DiagnosticArg<'iter, 'arg>>,
+) -> FluentArgs<'arg> {
+    let mut args = if let Some(size) = iter.size_hint().1 {
+        FluentArgs::with_capacity(size)
+    } else {
+        FluentArgs::new()
+    };
+
+    for (k, v) in iter {
+        args.set(k.clone(), v.clone());
+    }
+
+    args
+}
+
 pub trait Translate {
     /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
     /// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
@@ -15,15 +36,6 @@ pub trait Translate {
     /// unavailable for the requested locale.
     fn fallback_fluent_bundle(&self) -> &FluentBundle;
 
-    /// Convert diagnostic arguments (a rustc internal type that exists to implement
-    /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
-    ///
-    /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
-    /// passed around as a reference thereafter.
-    fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
-        FromIterator::from_iter(args.iter().cloned())
-    }
-
     /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
     fn translate_messages(
         &self,
@@ -43,7 +55,9 @@ pub trait Translate {
     ) -> Cow<'_, str> {
         trace!(?message, ?args);
         let (identifier, attr) = match message {
-            DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
+            DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
+                return Cow::Borrowed(&msg);
+            }
             DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
         };
 
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 17a348ec6ba..cc2858d3f73 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,5 +1,8 @@
 use crate::base::ExtCtxt;
-
+use pm::bridge::{
+    server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
+};
+use pm::{Delimiter, Level, LineColumn};
 use rustc_ast as ast;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
@@ -13,11 +16,7 @@ use rustc_session::parse::ParseSess;
 use rustc_span::def_id::CrateNum;
 use rustc_span::symbol::{self, sym, Symbol};
 use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
-
-use pm::bridge::{
-    server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
-};
-use pm::{Delimiter, Level, LineColumn};
+use smallvec::{smallvec, SmallVec};
 use std::ops::Bound;
 
 trait FromInternal<T> {
@@ -253,23 +252,57 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
     }
 }
 
-impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) {
-    fn to_internal(self) -> TokenStream {
+// We use a `SmallVec` because the output size is always one or two `TokenTree`s.
+impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
+    for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>)
+{
+    fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> {
         use rustc_ast::token::*;
 
         let (tree, rustc) = self;
-        let (ch, joint, span) = match tree {
-            TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
+        match tree {
+            TokenTree::Punct(Punct { ch, joint, span }) => {
+                let kind = match ch {
+                    b'=' => Eq,
+                    b'<' => Lt,
+                    b'>' => Gt,
+                    b'!' => Not,
+                    b'~' => Tilde,
+                    b'+' => BinOp(Plus),
+                    b'-' => BinOp(Minus),
+                    b'*' => BinOp(Star),
+                    b'/' => BinOp(Slash),
+                    b'%' => BinOp(Percent),
+                    b'^' => BinOp(Caret),
+                    b'&' => BinOp(And),
+                    b'|' => BinOp(Or),
+                    b'@' => At,
+                    b'.' => Dot,
+                    b',' => Comma,
+                    b';' => Semi,
+                    b':' => Colon,
+                    b'#' => Pound,
+                    b'$' => Dollar,
+                    b'?' => Question,
+                    b'\'' => SingleQuote,
+                    _ => unreachable!(),
+                };
+                smallvec![if joint {
+                    tokenstream::TokenTree::token_joint(kind, span)
+                } else {
+                    tokenstream::TokenTree::token_alone(kind, span)
+                }]
+            }
             TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
-                return tokenstream::TokenStream::delimited(
+                smallvec![tokenstream::TokenTree::Delimited(
                     tokenstream::DelimSpan { open, close },
                     delimiter.to_internal(),
                     stream.unwrap_or_default(),
-                );
+                )]
             }
             TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 rustc.sess().symbol_gallery.insert(sym, span);
-                return tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span);
+                smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)]
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Integer,
@@ -282,7 +315,7 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(integer, span);
-                return [a, b].into_iter().collect();
+                smallvec![a, b]
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Float,
@@ -295,46 +328,14 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
                 let float = TokenKind::lit(token::Float, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(float, span);
-                return [a, b].into_iter().collect();
+                smallvec![a, b]
             }
             TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
-                return tokenstream::TokenStream::token_alone(
+                smallvec![tokenstream::TokenTree::token_alone(
                     TokenKind::lit(kind.to_internal(), symbol, suffix),
                     span,
-                );
+                )]
             }
-        };
-
-        let kind = match ch {
-            b'=' => Eq,
-            b'<' => Lt,
-            b'>' => Gt,
-            b'!' => Not,
-            b'~' => Tilde,
-            b'+' => BinOp(Plus),
-            b'-' => BinOp(Minus),
-            b'*' => BinOp(Star),
-            b'/' => BinOp(Slash),
-            b'%' => BinOp(Percent),
-            b'^' => BinOp(Caret),
-            b'&' => BinOp(And),
-            b'|' => BinOp(Or),
-            b'@' => At,
-            b'.' => Dot,
-            b',' => Comma,
-            b';' => Semi,
-            b':' => Colon,
-            b'#' => Pound,
-            b'$' => Dollar,
-            b'?' => Question,
-            b'\'' => SingleQuote,
-            _ => unreachable!(),
-        };
-
-        if joint {
-            tokenstream::TokenStream::token_joint(kind, span)
-        } else {
-            tokenstream::TokenStream::token_alone(kind, span)
         }
     }
 }
@@ -549,7 +550,7 @@ impl server::TokenStream for Rustc<'_, '_> {
         &mut self,
         tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
     ) -> Self::TokenStream {
-        (tree, &mut *self).to_internal()
+        Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>())
     }
 
     fn concat_trees(
@@ -557,14 +558,14 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option<Self::TokenStream>,
         trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
     ) -> Self::TokenStream {
-        let mut builder = tokenstream::TokenStreamBuilder::new();
-        if let Some(base) = base {
-            builder.push(base);
-        }
+        let mut stream =
+            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
         for tree in trees {
-            builder.push((tree, &mut *self).to_internal());
+            for tt in (tree, &mut *self).to_internal() {
+                stream.push_tree(tt);
+            }
         }
-        builder.build()
+        stream
     }
 
     fn concat_streams(
@@ -572,14 +573,12 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option<Self::TokenStream>,
         streams: Vec<Self::TokenStream>,
     ) -> Self::TokenStream {
-        let mut builder = tokenstream::TokenStreamBuilder::new();
-        if let Some(base) = base {
-            builder.push(base);
+        let mut stream =
+            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
+        for s in streams {
+            stream.push_stream(s);
         }
-        for stream in streams {
-            builder.push(stream);
-        }
-        builder.build()
+        stream
     }
 
     fn into_trees(
@@ -705,6 +704,7 @@ impl server::Span for Rustc<'_, '_> {
     fn source_text(&mut self, span: Self::Span) -> Option<String> {
         self.sess().source_map().span_to_snippet(span).ok()
     }
+
     /// Saves the provided span into the metadata of
     /// *the crate we are currently compiling*, which must
     /// be a proc-macro crate. This id can be passed to
diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs
index eed69681011..91c4dd732e3 100644
--- a/compiler/rustc_expand/src/tokenstream/tests.rs
+++ b/compiler/rustc_expand/src/tokenstream/tests.rs
@@ -1,7 +1,7 @@
 use crate::tests::string_to_stream;
 
 use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_span::create_default_session_globals_then;
 use rustc_span::{BytePos, Span, Symbol};
 
@@ -19,10 +19,9 @@ fn test_concat() {
         let test_res = string_to_ts("foo::bar::baz");
         let test_fst = string_to_ts("foo::bar");
         let test_snd = string_to_ts("::baz");
-        let mut builder = TokenStreamBuilder::new();
-        builder.push(test_fst);
-        builder.push(test_snd);
-        let eq_res = builder.build();
+        let mut eq_res = TokenStream::default();
+        eq_res.push_stream(test_fst);
+        eq_res.push_stream(test_snd);
         assert_eq!(test_res.trees().count(), 5);
         assert_eq!(eq_res.trees().count(), 5);
         assert_eq!(test_res.eq_unspanned(&eq_res), true);
@@ -99,11 +98,10 @@ fn test_is_empty() {
 #[test]
 fn test_dotdotdot() {
     create_default_session_globals_then(|| {
-        let mut builder = TokenStreamBuilder::new();
-        builder.push(TokenStream::token_joint(token::Dot, sp(0, 1)));
-        builder.push(TokenStream::token_joint(token::Dot, sp(1, 2)));
-        builder.push(TokenStream::token_alone(token::Dot, sp(2, 3)));
-        let stream = builder.build();
+        let mut stream = TokenStream::default();
+        stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1)));
+        stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
+        stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
         assert!(stream.eq_unspanned(&string_to_ts("...")));
         assert_eq!(stream.trees().count(), 1);
     })
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 48c40eae662..5ea433e6b3d 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -412,8 +412,6 @@ declare_features! (
     (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
     /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
     (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
-    /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
-    (active, half_open_range_patterns, "1.41.0", Some(67264), None),
     /// Allows using `..=X` as a patterns in slices.
     (active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
     /// Allows `if let` guard in match arms.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 098f9d51549..bc149e48d89 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3514,7 +3514,7 @@ impl<'hir> Node<'hir> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(Block<'_>, 48);
     static_assert_size!(Body<'_>, 32);
     static_assert_size!(Expr<'_>, 64);
@@ -3533,9 +3533,9 @@ mod size_asserts {
     static_assert_size!(Local<'_>, 64);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
-    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(Path<'_>, 40);
     static_assert_size!(PathSegment<'_>, 48);
+    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(QPath<'_>, 24);
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
@@ -3544,4 +3544,5 @@ mod size_asserts {
     static_assert_size!(TraitItemKind<'_>, 48);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 77ab27266b2..f6f25603581 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -380,7 +380,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    let _ = tcx.representability(def_id);
 
     if def.repr().simd() {
         check_simd(tcx, span, def_id);
@@ -394,7 +393,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    let _ = tcx.representability(def_id);
     check_transparent(tcx, span, def);
     check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def);
@@ -1489,7 +1487,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
 
     detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
 
-    let _ = tcx.representability(def_id);
     check_transparent(tcx, sp, def);
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 0bd45bb1c91..0a8a1bec9b8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1041,6 +1041,8 @@ fn check_type_defn<'tcx, F>(
 ) where
     F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
 {
+    let _ = tcx.representability(item.def_id.def_id);
+
     enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
         let variants = lookup_fields(wfcx);
         let packed = tcx.adt_def(item.def_id).repr().packed();
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 85b877652c6..500900d3d4a 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,6 +1,7 @@
 use hir::GenericParamKind;
 use rustc_errors::{
-    fluent, AddToDiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
+    fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
+    MultiSpan, SubdiagnosticMessage,
 };
 use rustc_hir as hir;
 use rustc_hir::{FnRetTy, Ty};
@@ -229,7 +230,10 @@ pub enum RegionOriginNote<'a> {
 }
 
 impl AddToDiagnostic for RegionOriginNote<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         let mut label_or_note = |span, msg: DiagnosticMessage| {
             let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
             let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
@@ -290,7 +294,10 @@ pub enum LifetimeMismatchLabels {
 }
 
 impl AddToDiagnostic for LifetimeMismatchLabels {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self {
             LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
                 diag.span_label(param_span, fluent::infer::declared_different);
@@ -340,7 +347,10 @@ pub struct AddLifetimeParamsSuggestion<'a> {
 }
 
 impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         let mut mk_suggestion = || {
             let (
                 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
@@ -439,7 +449,10 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
 }
 
 impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
-    fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         self.unmet_requirements
             .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
         diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
@@ -451,7 +464,10 @@ pub struct ImplNote {
 }
 
 impl AddToDiagnostic for ImplNote {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self.impl_span {
             Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
             None => diag.note(fluent::infer::msl_impl_note),
@@ -466,7 +482,10 @@ pub enum TraitSubdiag {
 
 // FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
 impl AddToDiagnostic for TraitSubdiag {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self {
             TraitSubdiag::Note { span } => {
                 diag.span_note(span, "this has an implicit `'static` lifetime requirement");
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 7f54918f736..201a3c7100c 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,5 +1,7 @@
 use crate::infer::error_reporting::nice_region_error::find_anon_type;
-use rustc_errors::{self, fluent, AddToDiagnostic, IntoDiagnosticArg};
+use rustc_errors::{
+    self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
+};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::kw, Span};
 
@@ -159,7 +161,10 @@ impl RegionExplanation<'_> {
 }
 
 impl AddToDiagnostic for RegionExplanation<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         if let Some(span) = self.desc.span {
             diag.span_note(span, fluent::infer::region_explanation);
         } else {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 98eeaad976f..d64cdcdbaa9 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -540,7 +540,7 @@ fn test_codegen_options_tracking_hash() {
     }
 
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
-    // This list is in alphabetical order.
+    // tidy-alphabetical-start
     untracked!(ar, String::from("abc"));
     untracked!(codegen_units, Some(42));
     untracked!(default_linker_libraries, true);
@@ -556,6 +556,7 @@ fn test_codegen_options_tracking_hash() {
     untracked!(rpath, true);
     untracked!(save_temps, true);
     untracked!(strip, Strip::Debuginfo);
+    // tidy-alphabetical-end
 
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
@@ -567,7 +568,7 @@ fn test_codegen_options_tracking_hash() {
     }
 
     // Make sure that changing a [TRACKED] option changes the hash.
-    // This list is in alphabetical order.
+    // tidy-alphabetical-start
     tracked!(code_model, Some(CodeModel::Large));
     tracked!(control_flow_guard, CFGuard::Checks);
     tracked!(debug_assertions, Some(true));
@@ -577,8 +578,8 @@ fn test_codegen_options_tracking_hash() {
     tracked!(force_unwind_tables, Some(true));
     tracked!(inline_threshold, Some(0xf007ba11));
     tracked!(instrument_coverage, Some(InstrumentCoverage::All));
-    tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
     tracked!(link_dead_code, Some(true));
+    tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
     tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
     tracked!(lto, LtoCli::Fat);
     tracked!(metadata, vec![String::from("A"), String::from("B")]);
@@ -599,6 +600,7 @@ fn test_codegen_options_tracking_hash() {
     tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(target_cpu, Some(String::from("abc")));
     tracked!(target_feature, String::from("all the features, all of them"));
+    // tidy-alphabetical-end
 }
 
 #[test]
@@ -619,12 +621,13 @@ fn test_top_level_options_tracked_no_crate() {
     }
 
     // Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash.
-    // This list is in alphabetical order.
-    tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+    // tidy-alphabetical-start
     tracked!(
         real_rust_source_base_dir,
         Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
     );
+    tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+    // tidy-alphabetical-end
 }
 
 #[test]
@@ -641,7 +644,7 @@ fn test_unstable_options_tracking_hash() {
     }
 
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
-    // This list is in alphabetical order.
+    // tidy-alphabetical-start
     untracked!(assert_incr_state, Some(String::from("loaded")));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
@@ -678,12 +681,12 @@ fn test_unstable_options_tracking_hash() {
     untracked!(perf_stats, true);
     // `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
     untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
-    untracked!(profile_closures, true);
     untracked!(print_llvm_passes, true);
     untracked!(print_mono_items, Some(String::from("abc")));
     untracked!(print_type_sizes, true);
     untracked!(proc_macro_backtrace, true);
     untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
+    untracked!(profile_closures, true);
     untracked!(query_dep_graph, true);
     untracked!(save_analysis, true);
     untracked!(self_profile, SwitchWithOptPath::Enabled(None));
@@ -701,6 +704,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(unstable_options, true);
     untracked!(validate_mir, true);
     untracked!(verbose, true);
+    // tidy-alphabetical-end
 
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
@@ -712,7 +716,7 @@ fn test_unstable_options_tracking_hash() {
     }
 
     // Make sure that changing a [TRACKED] option changes the hash.
-    // This list is in alphabetical order.
+    // tidy-alphabetical-start
     tracked!(allow_features, Some(vec![String::from("lang_items")]));
     tracked!(always_encode_mir, true);
     tracked!(asm_comments, true);
@@ -733,10 +737,10 @@ fn test_unstable_options_tracking_hash() {
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
     tracked!(drop_tracking, true);
-    tracked!(export_executable_symbols, true);
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
     tracked!(emit_thin_lto, false);
+    tracked!(export_executable_symbols, true);
     tracked!(fewer_names, Some(true));
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
@@ -759,8 +763,8 @@ fn test_unstable_options_tracking_hash() {
     tracked!(mutable_noalias, Some(true));
     tracked!(no_generate_arange_section, true);
     tracked!(no_link, true);
-    tracked!(no_unique_section_names, true);
     tracked!(no_profiler_runtime, true);
+    tracked!(no_unique_section_names, true);
     tracked!(oom, OomStrategy::Panic);
     tracked!(osx_rpath_install_name, true);
     tracked!(packed_bundled_libs, true);
@@ -773,8 +777,8 @@ fn test_unstable_options_tracking_hash() {
     tracked!(print_fuel, Some("abc".to_string()));
     tracked!(profile, true);
     tracked!(profile_emit, Some(PathBuf::from("abc")));
-    tracked!(profiler_runtime, "abc".to_string());
     tracked!(profile_sample_use, Some(PathBuf::from("abc")));
+    tracked!(profiler_runtime, "abc".to_string());
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
@@ -803,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(verify_llvm_ir, true);
     tracked!(virtual_function_elimination, true);
     tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
+    // tidy-alphabetical-end
 
     macro_rules! tracked_no_crate_hash {
         ($name: ident, $non_default_value: expr) => {
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 880f3fbd00e..97d012fb611 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,4 +1,7 @@
-use rustc_errors::{fluent, AddToDiagnostic, ErrorGuaranteed, Handler, IntoDiagnostic};
+use rustc_errors::{
+    fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
+    SubdiagnosticMessage,
+};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
@@ -23,7 +26,10 @@ pub enum OverruledAttributeSub {
 }
 
 impl AddToDiagnostic for OverruledAttributeSub {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         match self {
             OverruledAttributeSub::DefaultSource { id } => {
                 diag.note(fluent::lint::default_source);
@@ -88,7 +94,10 @@ pub struct RequestedLevel {
 }
 
 impl AddToDiagnostic for RequestedLevel {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         diag.note(fluent::lint::requested_level);
         diag.set_arg(
             "level",
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 83040a652b1..8cf307df5a5 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -10,27 +10,31 @@ use synstructure::Structure;
 /// The central struct for constructing the `into_diagnostic` method from an annotated struct.
 pub(crate) struct DiagnosticDerive<'a> {
     structure: Structure<'a>,
-    handler: syn::Ident,
     builder: DiagnosticDeriveBuilder,
 }
 
 impl<'a> DiagnosticDerive<'a> {
     pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
         Self {
-            builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
-            handler,
+            builder: DiagnosticDeriveBuilder {
+                diag,
+                kind: DiagnosticDeriveKind::Diagnostic { handler },
+            },
             structure,
         }
     }
 
     pub(crate) fn into_tokens(self) -> TokenStream {
-        let DiagnosticDerive { mut structure, handler, mut builder } = self;
+        let DiagnosticDerive { mut structure, mut builder } = self;
 
         let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
             let preamble = builder.preamble(&variant);
             let body = builder.body(&variant);
 
             let diag = &builder.parent.diag;
+            let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
+                unreachable!()
+            };
             let init = match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
@@ -48,14 +52,17 @@ impl<'a> DiagnosticDerive<'a> {
                 }
             };
 
+            let formatting_init = &builder.formatting_init;
             quote! {
                 #init
+                #formatting_init
                 #preamble
                 #body
                 #diag
             }
         });
 
+        let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
         structure.gen_impl(quote! {
             gen impl<'__diagnostic_handler_sess, G>
                     rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
@@ -96,17 +103,18 @@ impl<'a> LintDiagnosticDerive<'a> {
             let body = builder.body(&variant);
 
             let diag = &builder.parent.diag;
-
+            let formatting_init = &builder.formatting_init;
             quote! {
                 #preamble
+                #formatting_init
                 #body
                 #diag
             }
         });
 
         let msg = builder.each_variant(&mut structure, |mut builder, variant| {
-            // HACK(wafflelapkin): initialize slug (???)
-            let _preamble = builder.preamble(&variant);
+            // Collect the slug by generating the preamble.
+            let _ = builder.preamble(&variant);
 
             match builder.slug.value_ref() {
                 None => {
@@ -125,7 +133,10 @@ impl<'a> LintDiagnosticDerive<'a> {
         let diag = &builder.diag;
         structure.gen_impl(quote! {
             gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
-                fn decorate_lint<'__b>(self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
+                fn decorate_lint<'__b>(
+                    self,
+                    #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
+                ) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
                 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 9e88dc7a913..dcbe89251cb 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -5,9 +5,9 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    bind_style_of_field, build_field_mapping, report_error_if_not_applied_to_span,
-    report_type_error, should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo,
-    FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
+    build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
+    should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
+    HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote};
@@ -17,9 +17,9 @@ use syn::{
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
 /// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
 pub(crate) enum DiagnosticDeriveKind {
-    Diagnostic,
+    Diagnostic { handler: syn::Ident },
     LintDiagnostic,
 }
 
@@ -40,6 +40,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
     /// The parent builder for the entire type.
     pub parent: &'parent DiagnosticDeriveBuilder,
 
+    /// Initialization of format strings for code suggestions.
+    pub formatting_init: TokenStream,
+
     /// Span of the struct or the enum variant.
     pub span: proc_macro::Span,
 
@@ -88,19 +91,7 @@ impl DiagnosticDeriveBuilder {
             }
         }
 
-        for variant in structure.variants_mut() {
-            // First, change the binding style of each field based on the code that will be
-            // generated for the field - e.g. `set_arg` calls needs by-move bindings, whereas
-            // `set_primary_span` only needs by-ref.
-            variant.bind_with(|bi| bind_style_of_field(bi.ast()).0);
-
-            // Then, perform a stable sort on bindings which generates code for by-ref bindings
-            // before code generated for by-move bindings. Any code generated for the by-ref
-            // bindings which creates a reference to the by-move fields will happen before the
-            // by-move bindings move those fields and make them inaccessible.
-            variant.bindings_mut().sort_by_cached_key(|bi| bind_style_of_field(bi.ast()));
-        }
-
+        structure.bind_with(|_| synstructure::BindStyle::Move);
         let variants = structure.each_variant(|variant| {
             let span = match structure.ast().data {
                 syn::Data::Struct(..) => span,
@@ -112,6 +103,7 @@ impl DiagnosticDeriveBuilder {
                 parent: &self,
                 span,
                 field_map: build_field_mapping(variant),
+                formatting_init: TokenStream::new(),
                 slug: None,
                 code: None,
             };
@@ -143,16 +135,14 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
 
     /// Generates calls to `span_label` and similar functions based on the attributes on fields or
     /// calls to `set_arg` when no attributes are present.
-    ///
-    /// Expects use of `Self::each_variant` which will have sorted bindings so that by-ref bindings
-    /// (which may create references to by-move bindings) have their code generated first -
-    /// necessary as code for suggestions uses formatting machinery and the value of other fields
-    /// (any given field can be referenced multiple times, so must be accessed through a borrow);
-    /// and when passing fields to `add_subdiagnostic` or `set_arg` for Fluent, fields must be
-    /// accessed by-move.
     pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
         let mut body = quote! {};
-        for binding in variant.bindings() {
+        // Generate `set_arg` calls first..
+        for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
+            body.extend(self.generate_field_code(binding));
+        }
+        // ..and then subdiagnostic additions.
+        for binding in variant.bindings().iter().filter(|bi| !should_generate_set_arg(bi.ast())) {
             body.extend(self.generate_field_attrs_code(binding));
         }
         body
@@ -274,24 +264,27 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
         }
     }
 
-    fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+    fn generate_field_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+        let diag = &self.parent.diag;
+
         let field = binding_info.ast();
         let field_binding = &binding_info.binding;
 
-        if should_generate_set_arg(&field) {
-            let diag = &self.parent.diag;
-            let ident = field.ident.as_ref().unwrap();
-            // strip `r#` prefix, if present
-            let ident = format_ident!("{}", ident);
-            return quote! {
-                #diag.set_arg(
-                    stringify!(#ident),
-                    #field_binding
-                );
-            };
+        let ident = field.ident.as_ref().unwrap();
+        let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
+
+        quote! {
+            #diag.set_arg(
+                stringify!(#ident),
+                #field_binding
+            );
         }
+    }
+
+    fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+        let field = binding_info.ast();
+        let field_binding = &binding_info.binding;
 
-        let needs_move = bind_style_of_field(&field).is_move();
         let inner_ty = FieldInnerTy::from_type(&field.ty);
 
         field
@@ -304,10 +297,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                 let (binding, needs_destructure) = if needs_clone {
                     // `primary_span` can accept a `Vec<Span>` so don't destructure that.
                     (quote! { #field_binding.clone() }, false)
-                } else if needs_move {
-                    (quote! { #field_binding }, true)
                 } else {
-                    (quote! { *#field_binding }, true)
+                    (quote! { #field_binding }, true)
                 };
 
                 let generated_code = self
@@ -340,18 +331,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
         let diag = &self.parent.diag;
         let meta = attr.parse_meta()?;
 
-        if let Meta::Path(_) = meta {
-            let ident = &attr.path.segments.last().unwrap().ident;
-            let name = ident.to_string();
-            let name = name.as_str();
-            match name {
-                "skip_arg" => {
-                    // Don't need to do anything - by virtue of the attribute existing, the
-                    // `set_arg` call will not be generated.
-                    return Ok(quote! {});
-                }
-                "primary_span" => match self.parent.kind {
-                    DiagnosticDeriveKind::Diagnostic => {
+        let ident = &attr.path.segments.last().unwrap().ident;
+        let name = ident.to_string();
+        match (&meta, name.as_str()) {
+            // Don't need to do anything - by virtue of the attribute existing, the
+            // `set_arg` call will not be generated.
+            (Meta::Path(_), "skip_arg") => return Ok(quote! {}),
+            (Meta::Path(_), "primary_span") => {
+                match self.parent.kind {
+                    DiagnosticDeriveKind::Diagnostic { .. } => {
                         report_error_if_not_applied_to_span(attr, &info)?;
 
                         return Ok(quote! {
@@ -363,10 +351,50 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                             diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
                         })
                     }
-                },
-                "subdiagnostic" => return Ok(quote! { #diag.subdiagnostic(#binding); }),
-                _ => {}
+                }
+            }
+            (Meta::Path(_), "subdiagnostic") => {
+                return Ok(quote! { #diag.subdiagnostic(#binding); });
+            }
+            (Meta::NameValue(_), "subdiagnostic") => {
+                throw_invalid_attr!(attr, &meta, |diag| {
+                    diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+                })
+            }
+            (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
+                if nested.len() != 1 {
+                    throw_invalid_attr!(attr, &meta, |diag| {
+                        diag.help(
+                            "`eager` is the only supported nested attribute for `subdiagnostic`",
+                        )
+                    })
+                }
+
+                let handler = match &self.parent.kind {
+                    DiagnosticDeriveKind::Diagnostic { handler } => handler,
+                    DiagnosticDeriveKind::LintDiagnostic => {
+                        throw_invalid_attr!(attr, &meta, |diag| {
+                            diag.help("eager subdiagnostics are not supported on lints")
+                        })
+                    }
+                };
+
+                let nested_attr = nested.first().expect("pop failed for single element list");
+                match nested_attr {
+                    NestedMeta::Meta(meta @ Meta::Path(_))
+                        if meta.path().segments.last().unwrap().ident.to_string().as_str()
+                            == "eager" =>
+                    {
+                        return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+                    }
+                    _ => {
+                        throw_invalid_nested_attr!(attr, nested_attr, |diag| {
+                            diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+                        })
+                    }
+                }
             }
+            _ => (),
         }
 
         let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
@@ -389,7 +417,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             SubdiagnosticKind::Suggestion {
                 suggestion_kind,
                 applicability: static_applicability,
-                code,
+                code_field,
+                code_init,
             } => {
                 let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
 
@@ -402,11 +431,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                     .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
                 let style = suggestion_kind.to_suggestion_style();
 
+                self.formatting_init.extend(code_init);
                 Ok(quote! {
                     #diag.span_suggestion_with_style(
                         #span_field,
                         rustc_errors::fluent::#slug,
-                        #code,
+                        #code_field,
                         #applicability,
                         #style
                     );
@@ -451,7 +481,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
             ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
                 let binding = &info.binding.binding;
-                Ok((quote!(*#binding), None))
+                Ok((quote!(#binding), None))
             }
             // If `ty` is `(Span, Applicability)` then return tokens accessing those.
             Type::Tuple(tup) => {
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 4166816b5e3..f98cc66e9e9 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -9,7 +9,7 @@ use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
 pub(crate) use fluent::fluent_messages;
 use proc_macro2::TokenStream;
 use quote::format_ident;
-use subdiagnostic::SubdiagnosticDerive;
+use subdiagnostic::SubdiagnosticDeriveBuilder;
 use synstructure::Structure;
 
 /// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
@@ -155,5 +155,5 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
 /// ```
 pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
-    SubdiagnosticDerive::new(s).into_tokens()
+    SubdiagnosticDeriveBuilder::new().into_tokens(s)
 }
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 9a2588513f0..3d4c3ab9fd7 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -5,7 +5,7 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, report_error_if_not_applied_to_applicability,
+    build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
     report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
     SpannedOption, SubdiagnosticKind,
 };
@@ -15,19 +15,19 @@ use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
 /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
-pub(crate) struct SubdiagnosticDerive<'a> {
-    structure: Structure<'a>,
+pub(crate) struct SubdiagnosticDeriveBuilder {
     diag: syn::Ident,
+    f: syn::Ident,
 }
 
-impl<'a> SubdiagnosticDerive<'a> {
-    pub(crate) fn new(structure: Structure<'a>) -> Self {
+impl SubdiagnosticDeriveBuilder {
+    pub(crate) fn new() -> Self {
         let diag = format_ident!("diag");
-        Self { structure, diag }
+        let f = format_ident!("f");
+        Self { diag, f }
     }
 
-    pub(crate) fn into_tokens(self) -> TokenStream {
-        let SubdiagnosticDerive { mut structure, diag } = self;
+    pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream {
         let implementation = {
             let ast = structure.ast();
             let span = ast.span().unwrap();
@@ -53,10 +53,11 @@ impl<'a> SubdiagnosticDerive<'a> {
 
             structure.bind_with(|_| synstructure::BindStyle::Move);
             let variants_ = structure.each_variant(|variant| {
-                let mut builder = SubdiagnosticDeriveBuilder {
-                    diag: &diag,
+                let mut builder = SubdiagnosticDeriveVariantBuilder {
+                    parent: &self,
                     variant,
                     span,
+                    formatting_init: TokenStream::new(),
                     fields: build_field_mapping(variant),
                     span_field: None,
                     applicability: None,
@@ -72,9 +73,17 @@ impl<'a> SubdiagnosticDerive<'a> {
             }
         };
 
+        let diag = &self.diag;
+        let f = &self.f;
         let ret = structure.gen_impl(quote! {
             gen impl rustc_errors::AddToDiagnostic for @Self {
-                fn add_to_diagnostic(self, #diag: &mut rustc_errors::Diagnostic) {
+                fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
+                where
+                    __F: Fn(
+                        &mut rustc_errors::Diagnostic,
+                        rustc_errors::SubdiagnosticMessage
+                    ) -> rustc_errors::SubdiagnosticMessage,
+                {
                     use rustc_errors::{Applicability, IntoDiagnosticArg};
                     #implementation
                 }
@@ -88,15 +97,18 @@ impl<'a> SubdiagnosticDerive<'a> {
 /// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
 /// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
 /// double mut borrow later on.
-struct SubdiagnosticDeriveBuilder<'a> {
+struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     /// The identifier to use for the generated `DiagnosticBuilder` instance.
-    diag: &'a syn::Ident,
+    parent: &'parent SubdiagnosticDeriveBuilder,
 
     /// Info for the current variant (or the type if not an enum).
     variant: &'a VariantInfo<'a>,
     /// Span for the entire type.
     span: proc_macro::Span,
 
+    /// Initialization of format strings for code suggestions.
+    formatting_init: TokenStream,
+
     /// Store a map of field name to its corresponding field. This is built on construction of the
     /// derive builder.
     fields: FieldMap,
@@ -112,7 +124,7 @@ struct SubdiagnosticDeriveBuilder<'a> {
     has_suggestion_parts: bool,
 }
 
-impl<'a> HasFieldMap for SubdiagnosticDeriveBuilder<'a> {
+impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
         self.fields.get(field)
     }
@@ -156,7 +168,7 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
     }
 }
 
-impl<'a> SubdiagnosticDeriveBuilder<'a> {
+impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
         let mut kind_slugs = vec![];
 
@@ -187,7 +199,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
         let ast = binding.ast();
         assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
 
-        let diag = &self.diag;
+        let diag = &self.parent.diag;
         let ident = ast.ident.as_ref().unwrap();
         // strip `r#` prefix, if present
         let ident = format_ident!("{}", ident);
@@ -222,7 +234,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                 };
 
                 let generated = self
-                    .generate_field_code_inner(kind_stats, attr, info)
+                    .generate_field_code_inner(kind_stats, attr, info, inner_ty.will_iterate())
                     .unwrap_or_else(|v| v.to_compile_error());
 
                 inner_ty.with(binding, generated)
@@ -235,13 +247,18 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
         kind_stats: KindsStatistics,
         attr: &Attribute,
         info: FieldInfo<'_>,
+        clone_suggestion_code: bool,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let meta = attr.parse_meta()?;
         match meta {
             Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
-            Meta::List(list @ MetaList { .. }) => {
-                self.generate_field_code_inner_list(kind_stats, attr, info, list)
-            }
+            Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
+                kind_stats,
+                attr,
+                info,
+                list,
+                clone_suggestion_code,
+            ),
             _ => throw_invalid_attr!(attr, &meta),
         }
     }
@@ -345,6 +362,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
         attr: &Attribute,
         info: FieldInfo<'_>,
         list: MetaList,
+        clone_suggestion_code: bool,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let span = attr.span().unwrap();
         let ident = &list.path.segments.last().unwrap().ident;
@@ -382,7 +400,8 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     match nested_name {
                         "code" => {
                             let formatted_str = self.build_format(&value.value(), value.span());
-                            code.set_once(formatted_str, span);
+                            let code_field = new_code_ident();
+                            code.set_once((code_field, formatted_str), span);
                         }
                         _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                             diag.help("`code` is the only valid nested attribute")
@@ -390,14 +409,20 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     }
                 }
 
-                let Some((code, _)) = code else {
+                let Some((code_field, formatted_str)) = code.value() else {
                     span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
                         .emit();
                     return Ok(quote! {});
                 };
                 let binding = info.binding;
 
-                Ok(quote! { suggestions.push((#binding, #code)); })
+                self.formatting_init.extend(quote! { let #code_field = #formatted_str; });
+                let code_field = if clone_suggestion_code {
+                    quote! { #code_field.clone() }
+                } else {
+                    quote! { #code_field }
+                };
+                Ok(quote! { suggestions.push((#binding, #code_field)); })
             }
             _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
                 let mut span_attrs = vec![];
@@ -442,13 +467,23 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
 
         let span_field = self.span_field.value_ref();
 
-        let diag = &self.diag;
+        let diag = &self.parent.diag;
+        let f = &self.parent.f;
         let mut calls = TokenStream::new();
         for (kind, slug) in kind_slugs {
+            let message = format_ident!("__message");
+            calls.extend(quote! { let #message = #f(#diag, rustc_errors::fluent::#slug.into()); });
+
             let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
-            let message = quote! { rustc_errors::fluent::#slug };
             let call = match kind {
-                SubdiagnosticKind::Suggestion { suggestion_kind, applicability, code } => {
+                SubdiagnosticKind::Suggestion {
+                    suggestion_kind,
+                    applicability,
+                    code_init,
+                    code_field,
+                } => {
+                    self.formatting_init.extend(code_init);
+
                     let applicability = applicability
                         .value()
                         .map(|a| quote! { #a })
@@ -457,8 +492,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
 
                     if let Some(span) = span_field {
                         let style = suggestion_kind.to_suggestion_style();
-
-                        quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
+                        quote! { #diag.#name(#span, #message, #code_field, #applicability, #style); }
                     } else {
                         span_err(self.span, "suggestion without `#[primary_span]` field").emit();
                         quote! { unreachable!(); }
@@ -499,6 +533,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     }
                 }
             };
+
             calls.extend(call);
         }
 
@@ -510,11 +545,13 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             .map(|binding| self.generate_field_set_arg(binding))
             .collect();
 
+        let formatting_init = &self.formatting_init;
         Ok(quote! {
             #init
+            #formatting_init
             #attr_args
-            #calls
             #plain_args
+            #calls
         })
     }
 }
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 162699c2868..4fd4adc5112 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -4,16 +4,29 @@ use crate::diagnostics::error::{
 use proc_macro::Span;
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, ToTokens};
-use std::cmp::Ordering;
+use std::cell::RefCell;
 use std::collections::{BTreeSet, HashMap};
 use std::fmt;
 use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
 use syn::{MetaList, MetaNameValue, NestedMeta, Path};
-use synstructure::{BindStyle, BindingInfo, VariantInfo};
+use synstructure::{BindingInfo, VariantInfo};
 
 use super::error::invalid_nested_attr;
 
+thread_local! {
+    pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
+}
+
+/// Returns an ident of the form `__code_N` where `N` is incremented once with every call.
+pub(crate) fn new_code_ident() -> syn::Ident {
+    CODE_IDENT_COUNT.with(|count| {
+        let ident = format_ident!("__code_{}", *count.borrow());
+        *count.borrow_mut() += 1;
+        ident
+    })
+}
+
 /// Checks whether the type name of `ty` matches `name`.
 ///
 /// Given some struct at `a::b::c::Foo`, this will return true for `c::Foo`, `b::c::Foo`, or
@@ -142,6 +155,15 @@ impl<'ty> FieldInnerTy<'ty> {
         unreachable!();
     }
 
+    /// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e.
+    /// that cloning might be required for values moved in the loop body).
+    pub(crate) fn will_iterate(&self) -> bool {
+        match self {
+            FieldInnerTy::Vec(..) => true,
+            FieldInnerTy::Option(..) | FieldInnerTy::None => false,
+        }
+    }
+
     /// Returns `Option` containing inner type if there is one.
     pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
         match self {
@@ -434,7 +456,12 @@ pub(super) enum SubdiagnosticKind {
     Suggestion {
         suggestion_kind: SuggestionKind,
         applicability: SpannedOption<Applicability>,
-        code: TokenStream,
+        /// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation
+        /// of formatting and diagnostic emission so that `set_arg` calls can happen in-between..
+        code_field: syn::Ident,
+        /// Initialization logic for `code_field`'s variable, e.g.
+        /// `let __formatted_code = /* whatever */;`
+        code_init: TokenStream,
     },
     /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
     MultipartSuggestion {
@@ -469,7 +496,8 @@ impl SubdiagnosticKind {
                     SubdiagnosticKind::Suggestion {
                         suggestion_kind,
                         applicability: None,
-                        code: TokenStream::new(),
+                        code_field: new_code_ident(),
+                        code_init: TokenStream::new(),
                     }
                 } else if let Some(suggestion_kind) =
                     name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
@@ -548,9 +576,10 @@ impl SubdiagnosticKind {
             };
 
             match (nested_name, &mut kind) {
-                ("code", SubdiagnosticKind::Suggestion { .. }) => {
+                ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
                     let formatted_str = fields.build_format(&value.value(), value.span());
-                    code.set_once(formatted_str, span);
+                    let code_init = quote! { let #code_field = #formatted_str; };
+                    code.set_once(code_init, span);
                 }
                 (
                     "applicability",
@@ -582,13 +611,13 @@ impl SubdiagnosticKind {
         }
 
         match kind {
-            SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
-                *code_field = if let Some((code, _)) = code {
-                    code
+            SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
+                *code_init = if let Some(init) = code.value() {
+                    init
                 } else {
                     span_err(span, "suggestion without `code = \"...\"`").emit();
-                    quote! { "" }
-                }
+                    quote! { let #code_field: String = unreachable!(); }
+                };
             }
             SubdiagnosticKind::Label
             | SubdiagnosticKind::Note
@@ -620,65 +649,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
     }
 }
 
-/// Wrapper around `synstructure::BindStyle` which implements `Ord`.
-#[derive(PartialEq, Eq)]
-pub(super) struct OrderedBindStyle(pub(super) BindStyle);
-
-impl OrderedBindStyle {
-    /// Is `BindStyle::Move` or `BindStyle::MoveMut`?
-    pub(super) fn is_move(&self) -> bool {
-        matches!(self.0, BindStyle::Move | BindStyle::MoveMut)
-    }
-}
-
-impl Ord for OrderedBindStyle {
-    fn cmp(&self, other: &Self) -> Ordering {
-        match (self.is_move(), other.is_move()) {
-            // If both `self` and `other` are the same, then ordering is equal.
-            (true, true) | (false, false) => Ordering::Equal,
-            // If `self` is not a move then it should be considered less than `other` (so that
-            // references are sorted first).
-            (false, _) => Ordering::Less,
-            // If `self` is a move then it must be greater than `other` (again, so that references
-            // are sorted first).
-            (true, _) => Ordering::Greater,
-        }
-    }
-}
-
-impl PartialOrd for OrderedBindStyle {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
 /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
 /// call (like `span_label`).
 pub(super) fn should_generate_set_arg(field: &Field) -> bool {
     field.attrs.is_empty()
 }
-
-/// Returns `true` if `field` needs to have code generated in the by-move branch of the
-/// generated derive rather than the by-ref branch.
-pub(super) fn bind_style_of_field(field: &Field) -> OrderedBindStyle {
-    let generates_set_arg = should_generate_set_arg(field);
-    let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
-    // FIXME(davidtwco): better support for one field needing to be in the by-move and
-    // by-ref branches.
-    let is_subdiagnostic = field
-        .attrs
-        .iter()
-        .map(|attr| attr.path.segments.last().unwrap().ident.to_string())
-        .any(|attr| attr == "subdiagnostic");
-
-    // `set_arg` calls take their argument by-move..
-    let needs_move = generates_set_arg
-        // If this is a `MultiSpan` field then it needs to be moved to be used by any
-        // attribute..
-        || is_multispan
-        // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
-        // unlikely to be `Copy`..
-        || is_subdiagnostic;
-
-    OrderedBindStyle(if needs_move { BindStyle::Move } else { BindStyle::Ref })
-}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3fc10197b91..68119598285 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1059,6 +1059,43 @@ fn should_encode_const(def_kind: DefKind) -> bool {
     }
 }
 
+fn should_encode_constness(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Trait
+        | DefKind::AssocTy
+        | DefKind::Fn
+        | DefKind::Const
+        | DefKind::Static(..)
+        | DefKind::Ctor(..)
+        | DefKind::AssocFn
+        | DefKind::AssocConst
+        | DefKind::AnonConst
+        | DefKind::InlineConst
+        | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
+        | DefKind::Impl
+        | DefKind::Closure
+        | DefKind::Generator
+        | DefKind::TyAlias => true,
+        DefKind::Variant
+        | DefKind::TraitAlias
+        | DefKind::ForeignTy
+        | DefKind::Field
+        | DefKind::TyParam
+        | DefKind::Mod
+        | DefKind::ForeignMod
+        | DefKind::ConstParam
+        | DefKind::Macro(..)
+        | DefKind::Use
+        | DefKind::LifetimeParam
+        | DefKind::GlobalAsm
+        | DefKind::ExternCrate => false,
+    }
+}
+
 fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     if tcx.def_kind(def_id) != DefKind::AssocFn {
         return false;
@@ -1165,6 +1202,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
+            if should_encode_constness(def_kind) {
+                self.tables.constness.set(def_id.index, tcx.constness(def_id));
+            }
         }
         let inherent_impls = tcx.crate_inherent_impls(());
         for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
@@ -1192,7 +1232,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
         record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -1220,7 +1259,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1284,7 +1322,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
         record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1320,7 +1357,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     }
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
-                self.tables.constness.set(def_id.index, hir::Constness::NotConst);
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1345,13 +1381,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
-                let constness = if self.tcx.is_const_fn_raw(def_id) {
-                    hir::Constness::Const
-                } else {
-                    hir::Constness::NotConst
-                };
-                self.tables.constness.set(def_id.index, constness);
             }
             ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
@@ -1474,7 +1503,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::Fn(ref sig, .., body) => {
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                self.tables.constness.set(def_id.index, sig.header.constness);
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
                 if macro_def.macro_rules {
@@ -1495,7 +1523,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                self.tables.constness.set(def_id.index, hir::Constness::Const);
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
@@ -1524,9 +1551,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                 });
             }
-            hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
+            hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
-                self.tables.constness.set(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index d3a98e43c53..d4258151ff3 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2946,11 +2946,12 @@ impl Location {
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(BasicBlockData<'_>, 144);
     static_assert_size!(LocalDecl<'_>, 56);
     static_assert_size!(Statement<'_>, 32);
     static_assert_size!(StatementKind<'_>, 16);
     static_assert_size!(Terminator<'_>, 112);
     static_assert_size!(TerminatorKind<'_>, 96);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 9a22a12b93b..85ef51f129b 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1245,10 +1245,11 @@ pub enum BinOp {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(AggregateKind<'_>, 40);
     static_assert_size!(Operand<'_>, 24);
     static_assert_size!(Place<'_>, 16);
     static_assert_size!(PlaceElem<'_>, 24);
     static_assert_size!(Rvalue<'_>, 40);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a175b1eb467..06eb10c9137 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -613,16 +613,8 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    // The cycle error here should be reported as an error by `check_representable`.
-    // We consider the type as Sized in the meanwhile to avoid
-    // further errors (done in impl Value for AdtSizedConstraint).
-    // Use `cycle_delay_bug` to delay the cycle error here to be emitted later
-    // in case we accidentally otherwise don't emit an error.
-    query adt_sized_constraint(
-        key: DefId
-    ) -> AdtSizedConstraint<'tcx> {
+    query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] {
         desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
-        cycle_delay_bug
     }
 
     query adt_dtorck_constraint(
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index f46f0ea4cab..ea7a507d7a4 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -848,7 +848,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(Block, 56);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
@@ -856,4 +856,5 @@ mod size_asserts {
     static_assert_size!(PatKind<'_>, 56);
     static_assert_size!(Stmt<'_>, 48);
     static_assert_size!(StmtKind<'_>, 40);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 26b6be7a1b8..b0a2412ab15 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -26,9 +26,6 @@ use super::{
     Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
 };
 
-#[derive(Copy, Clone, HashStable, Debug)]
-pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
-
 bitflags! {
     #[derive(HashStable, TyEncodable, TyDecodable)]
     pub struct AdtFlags: u32 {
@@ -563,7 +560,7 @@ impl<'tcx> AdtDef<'tcx> {
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer (e.g., issue #31299).
     pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
-        ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
+        ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 5f8729a8ddf..6045c1acdd0 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -191,10 +191,29 @@ pub enum LayoutError<'tcx> {
 
 impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
-        handler.struct_fatal(self.to_string())
+        let mut diag = handler.struct_fatal("");
+
+        match self {
+            LayoutError::Unknown(ty) => {
+                diag.set_arg("ty", ty);
+                diag.set_primary_message(rustc_errors::fluent::middle::unknown_layout);
+            }
+            LayoutError::SizeOverflow(ty) => {
+                diag.set_arg("ty", ty);
+                diag.set_primary_message(rustc_errors::fluent::middle::values_too_big);
+            }
+            LayoutError::NormalizationFailure(ty, e) => {
+                diag.set_arg("ty", ty);
+                diag.set_arg("failure_ty", e.get_type_for_failure());
+                diag.set_primary_message(rustc_errors::fluent::middle::cannot_be_normalized);
+            }
+        }
+        diag
     }
 }
 
+// FIXME: Once the other errors that embed this error have been converted to translateable
+// diagnostics, this Display impl should be removed.
 impl<'tcx> fmt::Display for LayoutError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 753d7bffe84..12d24d6751e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2668,8 +2668,9 @@ pub struct DestructuredConst<'tcx> {
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(PredicateS<'_>, 48);
     static_assert_size!(TyS<'_>, 40);
     static_assert_size!(WithStableHash<TyS<'_>>, 56);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index b6cda34c51f..ce1b69935f2 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::GeneratorDiagnosticData;
-use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_attr as attr;
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index bb89959b29d..f4b4c3fb05a 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -3,7 +3,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::Representability;
-use rustc_middle::ty::{self, AdtSizedConstraint, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
 use rustc_query_system::query::QueryInfo;
 use rustc_query_system::Value;
 use rustc_span::def_id::LocalDefId;
@@ -31,18 +31,6 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
     }
 }
 
-impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
-        // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
-        // FIXME: Represent the above fact in the trait system somehow.
-        unsafe {
-            std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
-                AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
-            )
-        }
-    }
-}
-
 impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
         let err = tcx.ty_error();
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 0dc05475ce9..81c051b8f35 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -459,7 +459,8 @@ fn make_token_stream(
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(AttrWrapper, 16);
     static_assert_size!(LazyAttrTokenStreamImpl, 144);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e82044a89c4..ebcbc75ba32 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1789,20 +1789,25 @@ impl<'a> Parser<'a> {
                 }
             } else {
                 let mut err = self.expected_ident_found();
-                if let Some((ident, _)) = self.token.ident() && ident.as_str() == "let" {
-                    self.bump(); // `let`
-                    let span = self.prev_token.span.until(self.token.span);
+                if self.eat_keyword_noexpect(kw::Let)
+                    && let removal_span = self.prev_token.span.until(self.token.span)
+                    && let Ok(ident) = self.parse_ident_common(false)
+                        // Cancel this error, we don't need it.
+                        .map_err(|err| err.cancel())
+                    && self.token.kind == TokenKind::Colon
+                {
                     err.span_suggestion(
-                        span,
-                        "remove the let, the `let` keyword is not allowed in struct field definitions",
+                        removal_span,
+                        "remove this `let` keyword",
                         String::new(),
                         Applicability::MachineApplicable,
                     );
                     err.note("the `let` keyword is not allowed in `struct` fields");
                     err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
                     err.emit();
-                    self.bump();
                     return Ok(ident);
+                } else {
+                    self.restore_snapshot(snapshot);
                 }
                 err
             };
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 5455d063c13..73fb89bbc38 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,10 +4,13 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::errors;
+use crate::errors::{
+    self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
+    OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
+};
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{fluent, Applicability, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
@@ -164,17 +167,17 @@ impl CheckAttrVisitor<'_> {
                 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
                 sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
                 sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
-                sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
+                sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
                 sym::macro_export => self.check_macro_export(hir_id, attr, target),
                 sym::ignore | sym::should_panic | sym::proc_macro_derive => {
-                    self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
+                    self.check_generic_attr(hir_id, attr, target, Target::Fn)
                 }
                 sym::automatically_derived => {
-                    self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
+                    self.check_generic_attr(hir_id, attr, target, Target::Impl)
                 }
                 sym::no_implicit_prelude => {
-                    self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
+                    self.check_generic_attr(hir_id, attr, target, Target::Mod)
                 }
                 sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
                 _ => {}
@@ -351,31 +354,17 @@ impl CheckAttrVisitor<'_> {
         hir_id: HirId,
         attr: &Attribute,
         target: Target,
-        allowed_targets: &[Target],
+        allowed_target: Target,
     ) {
-        if !allowed_targets.iter().any(|t| t == &target) {
-            let name = attr.name_or_empty();
-            let mut i = allowed_targets.iter();
-            // Pluralize
-            let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
-            let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
-                if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
-                    b.push_str(", and ");
-                } else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
-                    b.push_str(" and ");
-                } else {
-                    b.push_str(", ");
-                }
-                // Pluralize
-                b.push_str(&(allowed_target.to_string() + "s"));
-                b
-            });
-            self.tcx.struct_span_lint_hir(
+        if target != allowed_target {
+            self.tcx.emit_spanned_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
                 attr.span,
-                &format!("`#[{name}]` only has an effect on {}", supported_names),
-                |lint| lint,
+                OnlyHasEffectOn {
+                    attr_name: attr.name_or_empty(),
+                    target_name: allowed_target.name().replace(" ", "_"),
+                },
             );
         }
     }
@@ -432,7 +421,7 @@ impl CheckAttrVisitor<'_> {
                     ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
                     ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
                 };
-                tcx.sess.span_err(p.span, &repr);
+                tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
             }
         }
     }
@@ -1605,12 +1594,17 @@ impl CheckAttrVisitor<'_> {
                 continue;
             }
 
-            let (article, allowed_targets) = match hint.name_or_empty() {
+            match hint.name_or_empty() {
                 sym::C => {
                     is_c = true;
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
-                        _ => ("a", "struct, enum, or union"),
+                        _ => {
+                            self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+                                hint_span: hint.span(),
+                                span,
+                            });
+                        }
                     }
                 }
                 sym::align => {
@@ -1626,12 +1620,20 @@ impl CheckAttrVisitor<'_> {
 
                     match target {
                         Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
-                        _ => ("a", "struct, enum, function, or union"),
+                        _ => {
+                            self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion {
+                                hint_span: hint.span(),
+                                span,
+                            });
+                        }
                     }
                 }
                 sym::packed => {
                     if target != Target::Struct && target != Target::Union {
-                        ("a", "struct or union")
+                        self.tcx.sess.emit_err(AttrApplication::StructUnion {
+                            hint_span: hint.span(),
+                            span,
+                        });
                     } else {
                         continue;
                     }
@@ -1639,7 +1641,9 @@ impl CheckAttrVisitor<'_> {
                 sym::simd => {
                     is_simd = true;
                     if target != Target::Struct {
-                        ("a", "struct")
+                        self.tcx
+                            .sess
+                            .emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
                     } else {
                         continue;
                     }
@@ -1648,7 +1652,12 @@ impl CheckAttrVisitor<'_> {
                     is_transparent = true;
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
-                        _ => ("a", "struct, enum, or union"),
+                        _ => {
+                            self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+                                hint_span: hint.span(),
+                                span,
+                            });
+                        }
                     }
                 }
                 sym::i8
@@ -1665,35 +1674,18 @@ impl CheckAttrVisitor<'_> {
                 | sym::usize => {
                     int_reprs += 1;
                     if target != Target::Enum {
-                        ("an", "enum")
+                        self.tcx
+                            .sess
+                            .emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
                     } else {
                         continue;
                     }
                 }
                 _ => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        hint.span(),
-                        E0552,
-                        "unrecognized representation hint"
-                    )
-                    .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, \
-                          `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
-                    .emit();
-
+                    self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
                     continue;
                 }
             };
-
-            struct_span_err!(
-                self.tcx.sess,
-                hint.span(),
-                E0517,
-                "{}",
-                &format!("attribute should be applied to {article} {allowed_targets}")
-            )
-            .span_label(span, &format!("not {article} {allowed_targets}"))
-            .emit();
         }
 
         // Just point at all repr hints if there are any incompatibilities.
@@ -1703,14 +1695,9 @@ impl CheckAttrVisitor<'_> {
         // Error on repr(transparent, <anything else>).
         if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
-            struct_span_err!(
-                self.tcx.sess,
-                hint_spans,
-                E0692,
-                "transparent {} cannot have other repr hints",
-                target
-            )
-            .emit();
+            self.tcx
+                .sess
+                .emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
         }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
@@ -1862,14 +1849,12 @@ impl CheckAttrVisitor<'_> {
 
         match std::fs::File::open(&file) {
             Ok(_) => true,
-            Err(err) => {
-                self.tcx
-                    .sess
-                    .struct_span_err(
-                        meta_item.span,
-                        &format!("couldn't read {}: {}", file.display(), err),
-                    )
-                    .emit();
+            Err(error) => {
+                self.tcx.sess.emit_err(DebugVisualizerUnreadable {
+                    span: meta_item.span,
+                    file: &file,
+                    error,
+                });
                 false
             }
         }
@@ -2180,25 +2165,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         if attr.style == AttrStyle::Inner {
             for attr_to_check in ATTRS_TO_CHECK {
                 if attr.has_name(*attr_to_check) {
-                    let mut err = tcx.sess.struct_span_err(
-                        attr.span,
-                        &format!(
-                            "`{}` attribute cannot be used at crate level",
-                            attr_to_check.to_ident_string()
-                        ),
-                    );
-                    // Only emit an error with a suggestion if we can create a
-                    // string out of the attribute span
-                    if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
-                        let replacement = src.replace("#!", "#");
-                        err.span_suggestion_verbose(
-                            attr.span,
-                            "perhaps you meant to use an outer attribute",
-                            replacement,
-                            rustc_errors::Applicability::MachineApplicable,
-                        );
-                    }
-                    err.emit();
+                    tcx.sess.emit_err(InvalidAttrAtCrateLevel {
+                        span: attr.span,
+                        snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
+                        name: *attr_to_check,
+                    });
                 }
             }
         }
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index e502b9b54e3..aa726d6cd92 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -8,7 +8,6 @@
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
 use rustc_attr as attr;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
 
+use crate::errors::ExprNotAllowedInContext;
+
 /// An expression that is not *always* legal in a const context.
 #[derive(Clone, Copy)]
 enum NonConstExpr {
@@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> {
         let const_kind =
             const_kind.expect("`const_check_violated` may only be called inside a const context");
 
-        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
-
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
             required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
 
         match missing_gates.as_slice() {
             [] => {
-                struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit();
+                tcx.sess.emit_err(ExprNotAllowedInContext {
+                    span,
+                    expr: expr.name(),
+                    context: const_kind.keyword_name(),
+                });
             }
 
             [missing_primary, ref missing_secondary @ ..] => {
+                let msg =
+                    format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
                 let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
 
                 // If multiple feature gates would be required to enable this expression, include
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 08f704da62c..6a97ad3fe86 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -4,7 +4,7 @@
 
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, Applicability, DelayDm, MultiSpan};
+use rustc_errors::{pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -18,6 +18,8 @@ use rustc_session::lint;
 use rustc_span::symbol::{sym, Symbol};
 use std::mem;
 
+use crate::errors::UselessAssignment;
+
 // Any local node that may call something in its body block should be
 // explored. For example, if it's a live Node::Item that is a
 // function, then we should explore its block to check for codes that
@@ -180,19 +182,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 && !assign.span.from_expansion()
         {
                 let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
-                self.tcx.struct_span_lint_hir(
+                self.tcx.emit_spanned_lint(
                     lint::builtin::DEAD_CODE,
                     assign.hir_id,
                     assign.span,
-                    DelayDm(|| format!(
-                            "useless assignment of {} of type `{}` to itself",
-                            if is_field_assign { "field" } else { "variable" },
-                            self.typeck_results().expr_ty(lhs),
-                        )),
-                    |lint| {
-                        lint
-
-                    },
+                    UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
                 )
         }
     }
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index e08683fe23b..253b0a88e48 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
 
 use std::sync::Arc;
 
+use crate::errors::DebugVisualizerUnreadable;
+
 fn check_for_debugger_visualizer<'tcx>(
     tcx: TyCtxt<'tcx>,
     hir_id: HirId,
@@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>(
                     debugger_visualizers
                         .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
                 }
-                Err(err) => {
-                    tcx.sess
-                        .struct_span_err(
-                            meta_item.span,
-                            &format!("couldn't read {}: {}", file.display(), err),
-                        )
-                        .emit();
+                Err(error) => {
+                    tcx.sess.emit_err(DebugVisualizerUnreadable {
+                        span: meta_item.span,
+                        file: &file,
+                        error,
+                    });
                 }
             }
         }
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index e428d9293db..3f991cf6572 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -14,7 +14,9 @@ use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{kw::Empty, sym, Symbol};
+
+use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
 
 fn observe_item<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -33,25 +35,22 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
     items.id_to_name.insert(item_def_id, name);
     if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
         if original_def_id != item_def_id {
-            let mut err = match tcx.hir().span_if_local(item_def_id) {
-                Some(span) => tcx
-                    .sess
-                    .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")),
-                None => tcx.sess.struct_err(&format!(
-                    "duplicate diagnostic item in crate `{}`: `{}`.",
-                    tcx.crate_name(item_def_id.krate),
-                    name
-                )),
-            };
-            if let Some(span) = tcx.hir().span_if_local(original_def_id) {
-                err.span_note(span, "the diagnostic item is first defined here");
+            let orig_span = tcx.hir().span_if_local(original_def_id);
+            let orig_crate_name = if orig_span.is_some() {
+                None
             } else {
-                err.note(&format!(
-                    "the diagnostic item is first defined in crate `{}`.",
-                    tcx.crate_name(original_def_id.krate)
-                ));
-            }
-            err.emit();
+                Some(tcx.crate_name(original_def_id.krate))
+            };
+            match tcx.hir().span_if_local(item_def_id) {
+                Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
+                None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
+                    span: orig_span,
+                    orig_crate_name: orig_crate_name.unwrap_or(Empty),
+                    have_orig_crate_name: orig_crate_name.map(|_| ()),
+                    crate_name: tcx.crate_name(item_def_id.krate),
+                    name,
+                }),
+            };
         }
     }
 }
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index eec37d19a88..38a259ca884 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,5 +1,5 @@
 use rustc_ast::entry::EntryPointType;
-use rustc_errors::struct_span_err;
+use rustc_errors::error_code;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
@@ -8,7 +8,12 @@ use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{sigpipe, CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
+
+use crate::errors::{
+    AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
+    MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
+};
 
 struct EntryContext<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -71,14 +76,9 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
     }
 }
 
-fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) {
+fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
     let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-    if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
-        ctxt.tcx
-            .sess
-            .struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
-            .emit();
-    }
+    ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
 }
 
 fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
@@ -86,49 +86,47 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
 
     match entry_point_type(ctxt, id, at_root) {
         EntryPointType::None => {
-            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+                ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+            }
         }
         _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
-            err_if_attr_found(ctxt, id, sym::start, "can only be used on functions");
-            err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
+            for attr in [sym::start, sym::rustc_main] {
+                if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
+                    ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
+                }
+            }
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
-            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`");
+            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+                ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
+            }
             ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
         }
         EntryPointType::RustcMainAttr => {
             if ctxt.attr_main_fn.is_none() {
                 ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
             } else {
-                struct_span_err!(
-                    ctxt.tcx.sess,
-                    ctxt.tcx.def_span(id.def_id.to_def_id()),
-                    E0137,
-                    "multiple functions with a `#[rustc_main]` attribute"
-                )
-                .span_label(
-                    ctxt.tcx.def_span(id.def_id.to_def_id()),
-                    "additional `#[rustc_main]` function",
-                )
-                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
-                .emit();
+                ctxt.tcx.sess.emit_err(MultipleRustcMain {
+                    span: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    first: ctxt.attr_main_fn.unwrap().1,
+                    additional: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                });
             }
         }
         EntryPointType::Start => {
-            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+            if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+                ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+            }
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
             } else {
-                struct_span_err!(
-                    ctxt.tcx.sess,
-                    ctxt.tcx.def_span(id.def_id),
-                    E0138,
-                    "multiple `start` functions"
-                )
-                .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
-                .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
-                .emit();
+                ctxt.tcx.sess.emit_err(MultipleStartFunctions {
+                    span: ctxt.tcx.def_span(id.def_id),
+                    labeled: ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    previous: ctxt.start_fn.unwrap().1,
+                });
             }
         }
     }
@@ -144,12 +142,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
         if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
             // non-local main imports are handled below
             if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
-                tcx.sess
-                    .struct_span_err(
-                        tcx.def_span(def_id),
-                        "the `main` function cannot be declared in an `extern` block",
-                    )
-                    .emit();
+                tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
                 return None;
             }
 
@@ -182,12 +175,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
                 sigpipe::DEFAULT
             }
             _ => {
-                tcx.sess
-                    .struct_span_err(
-                        attr.span,
-                        "valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
-                    )
-                    .emit();
+                tcx.sess.emit_err(UnixSigpipeValues { span: attr.span });
                 sigpipe::DEFAULT
             }
         }
@@ -206,52 +194,29 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
     }
 
     // There is no main function.
-    let mut err = struct_span_err!(
-        tcx.sess,
-        DUMMY_SP,
-        E0601,
-        "`main` function not found in crate `{}`",
-        tcx.crate_name(LOCAL_CRATE)
-    );
-    let filename = &tcx.sess.local_crate_source_file;
-    let note = if !visitor.non_main_fns.is_empty() {
-        for &span in &visitor.non_main_fns {
-            err.span_note(span, "here is a function named `main`");
-        }
-        err.note("you have one or more functions named `main` not defined at the crate level");
-        err.help("consider moving the `main` function definitions");
-        // There were some functions named `main` though. Try to give the user a hint.
-        format!(
-            "the main function must be defined at the crate level{}",
-            filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default()
-        )
-    } else if let Some(filename) = filename {
-        format!("consider adding a `main` function to `{}`", filename.display())
-    } else {
-        String::from("consider adding a `main` function at the crate level")
-    };
+    let mut has_filename = true;
+    let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| {
+        has_filename = false;
+        Default::default()
+    });
+    let main_def_opt = tcx.resolutions(()).main_def;
+    let diagnostic_id = error_code!(E0601);
+    let add_teach_note = tcx.sess.teach(&diagnostic_id);
     // The file may be empty, which leads to the diagnostic machinery not emitting this
     // note. This is a relatively simple way to detect that case and emit a span-less
     // note instead.
-    if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() {
-        err.set_span(sp.shrink_to_hi());
-        err.span_label(sp.shrink_to_hi(), &note);
-    } else {
-        err.note(&note);
-    }
-
-    if let Some(main_def) = tcx.resolutions(()).main_def && main_def.opt_fn_def_id().is_none(){
-        // There is something at `crate::main`, but it is not a function definition.
-        err.span_label(main_def.span, "non-function item at `crate::main` is found");
-    }
-
-    if tcx.sess.teach(&err.get_code().unwrap()) {
-        err.note(
-            "If you don't know the basics of Rust, you can go look to the Rust Book \
-                  to get started: https://doc.rust-lang.org/book/",
-        );
-    }
-    err.emit();
+    let file_empty = !tcx.sess.source_map().lookup_line(sp.hi()).is_ok();
+
+    tcx.sess.emit_err(NoMainErr {
+        sp,
+        crate_name: tcx.crate_name(LOCAL_CRATE),
+        has_filename,
+        filename,
+        file_empty,
+        non_main_fns: visitor.non_main_fns.clone(),
+        main_def_opt,
+        add_teach_note,
+    });
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cc231af71a2..1cc81a9ab98 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,6 +1,16 @@
-use rustc_errors::{Applicability, MultiSpan};
+use std::{
+    io::Error,
+    path::{Path, PathBuf},
+};
+
+use rustc_ast::Label;
+use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
+use rustc_hir::{self as hir, ExprKind, Target};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_span::{Span, Symbol};
+use rustc_middle::ty::{MainDefinition, Ty};
+use rustc_span::{Span, Symbol, DUMMY_SP};
+
+use crate::lang_items::Duplicate;
 
 #[derive(LintDiagnostic)]
 #[diag(passes::outer_crate_level_attr)]
@@ -527,6 +537,15 @@ pub struct DebugVisualizerInvalid {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes::debug_visualizer_unreadable)]
+pub struct DebugVisualizerUnreadable<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub file: &'a Path,
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes::rustc_allow_const_fn_unstable)]
 pub struct RustcAllowConstFnUnstable {
     #[primary_span]
@@ -665,3 +684,765 @@ pub struct DeprecatedAnnotationHasNoEffect {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::unknown_external_lang_item, code = "E0264")]
+pub struct UnknownExternLangItem {
+    #[primary_span]
+    pub span: Span,
+    pub lang_item: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_panic_handler)]
+pub struct MissingPanicHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes::alloc_func_required)]
+pub struct AllocFuncRequired;
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_alloc_error_handler)]
+pub struct MissingAllocErrorHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_lang_item)]
+#[note]
+#[help]
+pub struct MissingLangItem {
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::lang_item_on_incorrect_target, code = "E0718")]
+pub struct LangItemOnIncorrectTarget {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub name: Symbol,
+    pub expected_target: Target,
+    pub actual_target: Target,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unknown_lang_item, code = "E0522")]
+pub struct UnknownLangItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+pub struct InvalidAttrAtCrateLevel {
+    pub span: Span,
+    pub snippet: Option<String>,
+    pub name: Symbol,
+}
+
+impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
+    fn into_diagnostic(
+        self,
+        handler: &'_ rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag =
+            handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level);
+        diag.set_span(self.span);
+        diag.set_arg("name", self.name);
+        // Only emit an error with a suggestion if we can create a string out
+        // of the attribute span
+        if let Some(src) = self.snippet {
+            let replacement = src.replace("#!", "#");
+            diag.span_suggestion_verbose(
+                self.span,
+                rustc_errors::fluent::passes::suggestion,
+                replacement,
+                rustc_errors::Applicability::MachineApplicable,
+            );
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::duplicate_diagnostic_item)]
+pub struct DuplicateDiagnosticItem {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::duplicate_diagnostic_item_in_crate)]
+pub struct DuplicateDiagnosticItemInCrate {
+    #[note(passes::diagnostic_item_first_defined)]
+    pub span: Option<Span>,
+    pub orig_crate_name: Symbol,
+    #[note]
+    pub have_orig_crate_name: Option<()>,
+    pub crate_name: Symbol,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::abi)]
+pub struct Abi {
+    #[primary_span]
+    pub span: Span,
+    pub abi: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::align)]
+pub struct Align {
+    #[primary_span]
+    pub span: Span,
+    pub align: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::size)]
+pub struct Size {
+    #[primary_span]
+    pub span: Span,
+    pub size: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::homogeneous_aggregate)]
+pub struct HomogeneousAggregate {
+    #[primary_span]
+    pub span: Span,
+    pub homogeneous_aggregate: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::layout_of)]
+pub struct LayoutOf {
+    #[primary_span]
+    pub span: Span,
+    pub normalized_ty: String,
+    pub ty_layout: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unrecognized_field)]
+pub struct UnrecognizedField {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::feature_stable_twice, code = "E0711")]
+pub struct FeatureStableTwice {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub since: Symbol,
+    pub prev_since: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::feature_previously_declared, code = "E0711")]
+pub struct FeaturePreviouslyDeclared<'a, 'b> {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub declared: &'a str,
+    pub prev_declared: &'b str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::expr_not_allowed_in_context, code = "E0744")]
+pub struct ExprNotAllowedInContext<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub expr: String,
+    pub context: &'a str,
+}
+
+pub struct BreakNonLoop<'a> {
+    pub span: Span,
+    pub head: Option<Span>,
+    pub kind: &'a str,
+    pub suggestion: String,
+    pub loop_label: Option<Label>,
+    pub break_label: Option<Label>,
+    pub break_expr_kind: &'a ExprKind<'a>,
+    pub break_expr_span: Span,
+}
+
+impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
+    fn into_diagnostic(
+        self,
+        handler: &rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
+            self.span,
+            rustc_errors::fluent::passes::break_non_loop,
+            error_code!(E0571),
+        );
+        diag.set_arg("kind", self.kind);
+        diag.span_label(self.span, rustc_errors::fluent::passes::label);
+        if let Some(head) = self.head {
+            diag.span_label(head, rustc_errors::fluent::passes::label2);
+        }
+        diag.span_suggestion(
+            self.span,
+            rustc_errors::fluent::passes::suggestion,
+            self.suggestion,
+            Applicability::MaybeIncorrect,
+        );
+        if let (Some(label), None) = (self.loop_label, self.break_label) {
+            match self.break_expr_kind {
+                ExprKind::Path(hir::QPath::Resolved(
+                    None,
+                    hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
+                )) if label.ident.to_string() == format!("'{}", segment.ident) => {
+                    // This error is redundant, we will have already emitted a
+                    // suggestion to use the label when `segment` wasn't found
+                    // (hence the `Res::Err` check).
+                    diag.delay_as_bug();
+                }
+                _ => {
+                    diag.span_suggestion(
+                        self.break_expr_span,
+                        rustc_errors::fluent::passes::break_expr_suggestion,
+                        label.ident,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::continue_labeled_block, code = "E0696")]
+pub struct ContinueLabeledBlock {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::block_label)]
+    pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::break_inside_closure, code = "E0267")]
+pub struct BreakInsideClosure<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::closure_label)]
+    pub closure_span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::break_inside_async_block, code = "E0267")]
+pub struct BreakInsideAsyncBlock<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::async_block_label)]
+    pub closure_span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::outside_loop, code = "E0268")]
+pub struct OutsideLoop<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unlabeled_in_labeled_block, code = "E0695")]
+pub struct UnlabeledInLabeledBlock<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unlabeled_cf_in_while_condition, code = "E0590")]
+pub struct UnlabeledCfInWhileCondition<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::cannot_inline_naked_function)]
+pub struct CannotInlineNakedFunction {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes::undefined_naked_function_abi)]
+pub struct UndefinedNakedFunctionAbi;
+
+#[derive(Diagnostic)]
+#[diag(passes::no_patterns)]
+pub struct NoPatterns {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::params_not_allowed)]
+#[help]
+pub struct ParamsNotAllowed {
+    #[primary_span]
+    pub span: Span,
+}
+
+pub struct NakedFunctionsAsmBlock {
+    pub span: Span,
+    pub multiple_asms: Vec<Span>,
+    pub non_asms: Vec<Span>,
+}
+
+impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
+    fn into_diagnostic(
+        self,
+        handler: &rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
+            self.span,
+            rustc_errors::fluent::passes::naked_functions_asm_block,
+            error_code!(E0787),
+        );
+        for span in self.multiple_asms.iter() {
+            diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
+        }
+        for span in self.non_asms.iter() {
+            diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::naked_functions_operands, code = "E0787")]
+pub struct NakedFunctionsOperands {
+    #[primary_span]
+    pub unsupported_operands: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::naked_functions_asm_options, code = "E0787")]
+pub struct NakedFunctionsAsmOptions {
+    #[primary_span]
+    pub span: Span,
+    pub unsupported_options: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
+pub struct NakedFunctionsMustUseNoreturn {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
+    pub last_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::attr_only_on_main)]
+pub struct AttrOnlyOnMain {
+    #[primary_span]
+    pub span: Span,
+    pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::attr_only_on_root_main)]
+pub struct AttrOnlyOnRootMain {
+    #[primary_span]
+    pub span: Span,
+    pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::attr_only_in_functions)]
+pub struct AttrOnlyInFunctions {
+    #[primary_span]
+    pub span: Span,
+    pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::multiple_rustc_main, code = "E0137")]
+pub struct MultipleRustcMain {
+    #[primary_span]
+    pub span: Span,
+    #[label(passes::first)]
+    pub first: Span,
+    #[label(passes::additional)]
+    pub additional: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::multiple_start_functions, code = "E0138")]
+pub struct MultipleStartFunctions {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub labeled: Span,
+    #[label(passes::previous)]
+    pub previous: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::extern_main)]
+pub struct ExternMain {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unix_sigpipe_values)]
+pub struct UnixSigpipeValues {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::no_main_function, code = "E0601")]
+pub struct NoMainFunction {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: String,
+}
+
+pub struct NoMainErr {
+    pub sp: Span,
+    pub crate_name: Symbol,
+    pub has_filename: bool,
+    pub filename: PathBuf,
+    pub file_empty: bool,
+    pub non_main_fns: Vec<Span>,
+    pub main_def_opt: Option<MainDefinition>,
+    pub add_teach_note: bool,
+}
+
+impl<'a> IntoDiagnostic<'a> for NoMainErr {
+    fn into_diagnostic(
+        self,
+        handler: &'a rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
+            DUMMY_SP,
+            rustc_errors::fluent::passes::no_main_function,
+            error_code!(E0601),
+        );
+        diag.set_arg("crate_name", self.crate_name);
+        diag.set_arg("filename", self.filename);
+        diag.set_arg("has_filename", self.has_filename);
+        let note = if !self.non_main_fns.is_empty() {
+            for &span in &self.non_main_fns {
+                diag.span_note(span, rustc_errors::fluent::passes::here_is_main);
+            }
+            diag.note(rustc_errors::fluent::passes::one_or_more_possible_main);
+            diag.help(rustc_errors::fluent::passes::consider_moving_main);
+            // There were some functions named `main` though. Try to give the user a hint.
+            rustc_errors::fluent::passes::main_must_be_defined_at_crate
+        } else if self.has_filename {
+            rustc_errors::fluent::passes::consider_adding_main_to_file
+        } else {
+            rustc_errors::fluent::passes::consider_adding_main_at_crate
+        };
+        if self.file_empty {
+            diag.note(note);
+        } else {
+            diag.set_span(self.sp.shrink_to_hi());
+            diag.span_label(self.sp.shrink_to_hi(), note);
+        }
+
+        if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
+            // There is something at `crate::main`, but it is not a function definition.
+            diag.span_label(main_def.span, rustc_errors::fluent::passes::non_function_main);
+        }
+
+        if self.add_teach_note {
+            diag.note(rustc_errors::fluent::passes::teach_note);
+        }
+        diag
+    }
+}
+
+pub struct DuplicateLangItem {
+    pub local_span: Option<Span>,
+    pub lang_item_name: Symbol,
+    pub crate_name: Symbol,
+    pub dependency_of: Symbol,
+    pub is_local: bool,
+    pub path: String,
+    pub first_defined_span: Option<Span>,
+    pub orig_crate_name: Symbol,
+    pub orig_dependency_of: Symbol,
+    pub orig_is_local: bool,
+    pub orig_path: String,
+    pub(crate) duplicate: Duplicate,
+}
+
+impl IntoDiagnostic<'_> for DuplicateLangItem {
+    fn into_diagnostic(
+        self,
+        handler: &rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_err_with_code(
+            match self.duplicate {
+                Duplicate::Plain => rustc_errors::fluent::passes::duplicate_lang_item,
+
+                Duplicate::Crate => rustc_errors::fluent::passes::duplicate_lang_item_crate,
+                Duplicate::CrateDepends => {
+                    rustc_errors::fluent::passes::duplicate_lang_item_crate_depends
+                }
+            },
+            error_code!(E0152),
+        );
+        diag.set_arg("lang_item_name", self.lang_item_name);
+        diag.set_arg("crate_name", self.crate_name);
+        diag.set_arg("dependency_of", self.dependency_of);
+        diag.set_arg("path", self.path);
+        diag.set_arg("orig_crate_name", self.orig_crate_name);
+        diag.set_arg("orig_dependency_of", self.orig_dependency_of);
+        diag.set_arg("orig_path", self.orig_path);
+        if let Some(span) = self.local_span {
+            diag.set_span(span);
+        }
+        if let Some(span) = self.first_defined_span {
+            diag.span_note(span, rustc_errors::fluent::passes::first_defined_span);
+        } else {
+            if self.orig_dependency_of.is_empty() {
+                diag.note(rustc_errors::fluent::passes::first_defined_crate);
+            } else {
+                diag.note(rustc_errors::fluent::passes::first_defined_crate_depends);
+            }
+
+            if self.orig_is_local {
+                diag.note(rustc_errors::fluent::passes::first_definition_local);
+            } else {
+                diag.note(rustc_errors::fluent::passes::first_definition_path);
+            }
+
+            if self.is_local {
+                diag.note(rustc_errors::fluent::passes::second_definition_local);
+            } else {
+                diag.note(rustc_errors::fluent::passes::second_definition_path);
+            }
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::incorrect_target, code = "E0718")]
+pub struct IncorrectTarget<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub generics_span: Span,
+    pub name: &'a str, // cannot be symbol because it renders e.g. `r#fn` instead of `fn`
+    pub kind: &'static str,
+    pub num: usize,
+    pub actual_num: usize,
+    pub at_least: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes::useless_assignment)]
+pub struct UselessAssignment<'a> {
+    pub is_field_assign: bool,
+    pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes::only_has_effect_on)]
+pub struct OnlyHasEffectOn {
+    pub attr_name: Symbol,
+    pub target_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::object_lifetime_err)]
+pub struct ObjectLifetimeErr {
+    #[primary_span]
+    pub span: Span,
+    pub repr: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unrecognized_repr_hint, code = "E0552")]
+#[help]
+pub struct UnrecognizedReprHint {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub enum AttrApplication {
+    #[diag(passes::attr_application_enum, code = "E0517")]
+    Enum {
+        #[primary_span]
+        hint_span: Span,
+        #[label]
+        span: Span,
+    },
+    #[diag(passes::attr_application_struct, code = "E0517")]
+    Struct {
+        #[primary_span]
+        hint_span: Span,
+        #[label]
+        span: Span,
+    },
+    #[diag(passes::attr_application_struct_union, code = "E0517")]
+    StructUnion {
+        #[primary_span]
+        hint_span: Span,
+        #[label]
+        span: Span,
+    },
+    #[diag(passes::attr_application_struct_enum_union, code = "E0517")]
+    StructEnumUnion {
+        #[primary_span]
+        hint_span: Span,
+        #[label]
+        span: Span,
+    },
+    #[diag(passes::attr_application_struct_enum_function_union, code = "E0517")]
+    StructEnumFunctionUnion {
+        #[primary_span]
+        hint_span: Span,
+        #[label]
+        span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::transparent_incompatible, code = "E0692")]
+pub struct TransparentIncompatible {
+    #[primary_span]
+    pub hint_spans: Vec<Span>,
+    pub target: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::deprecated_attribute, code = "E0549")]
+pub struct DeprecatedAttribute {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::useless_stability)]
+pub struct UselessStability {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::item)]
+    pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::invalid_stability)]
+pub struct InvalidStability {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::item)]
+    pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::cannot_stabilize_deprecated)]
+pub struct CannotStabilizeDeprecated {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::item)]
+    pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::invalid_deprecation_version)]
+pub struct InvalidDeprecationVersion {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(passes::item)]
+    pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_stability_attr)]
+pub struct MissingStabilityAttr<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub descr: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_const_stab_attr)]
+pub struct MissingConstStabAttr<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub descr: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::trait_impl_const_stable)]
+#[note]
+pub struct TraitImplConstStable {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::feature_only_on_nightly, code = "E0554")]
+pub struct FeatureOnlyOnNightly {
+    #[primary_span]
+    pub span: Span,
+    pub release_channel: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unknown_feature, code = "E0635")]
+pub struct UnknownFeature {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::implied_feature_not_exist)]
+pub struct ImpliedFeatureNotExist {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub implied_by: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::duplicate_feature_err, code = "E0636")]
+pub struct DuplicateFeatureErr {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+}
+#[derive(Diagnostic)]
+#[diag(passes::missing_const_err)]
+pub struct MissingConstErr {
+    #[primary_span]
+    #[help]
+    pub fn_sig_span: Span,
+    #[label]
+    pub const_span: Span,
+}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 79900a90aed..71b0735192a 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -8,9 +8,11 @@
 //! * Functions called by the compiler itself.
 
 use crate::check_attr::target_from_impl_item;
+use crate::errors::{
+    DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
+};
 use crate::weak_lang_items;
 
-use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -18,10 +20,16 @@ use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
 use rustc_hir::{HirId, LangItem, LanguageItems, Target};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ExternCrate;
-use rustc_span::Span;
+use rustc_span::{symbol::kw::Empty, Span};
 
 use rustc_middle::ty::query::Providers;
 
+pub(crate) enum Duplicate {
+    Plain,
+    Crate,
+    CrateDepends,
+}
+
 struct LanguageItemCollector<'tcx> {
     items: LanguageItems,
     tcx: TyCtxt<'tcx>,
@@ -34,42 +42,24 @@ impl<'tcx> LanguageItemCollector<'tcx> {
 
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
         let attrs = self.tcx.hir().attrs(hir_id);
-        if let Some((value, span)) = extract(&attrs) {
-            match ITEM_REFS.get(&value).cloned() {
+        if let Some((name, span)) = extract(&attrs) {
+            match ITEM_REFS.get(&name).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
                     self.collect_item_extended(item_index, hir_id, span);
                 }
                 // Known lang item with attribute on incorrect target.
                 Some((_, expected_target)) => {
-                    struct_span_err!(
-                        self.tcx.sess,
+                    self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
                         span,
-                        E0718,
-                        "`{}` language item must be applied to a {}",
-                        value,
+                        name,
                         expected_target,
-                    )
-                    .span_label(
-                        span,
-                        format!(
-                            "attribute should be applied to a {}, not a {}",
-                            expected_target, actual_target,
-                        ),
-                    )
-                    .emit();
+                        actual_target,
+                    });
                 }
                 // Unknown lang item.
                 _ => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0522,
-                        "definition of an unknown language item: `{}`",
-                        value
-                    )
-                    .span_label(span, format!("definition of unknown language item `{}`", value))
-                    .emit();
+                    self.tcx.sess.emit_err(UnknownLangItem { span, name });
                 }
             }
         }
@@ -79,74 +69,72 @@ impl<'tcx> LanguageItemCollector<'tcx> {
         // Check for duplicates.
         if let Some(original_def_id) = self.items.items[item_index] {
             if original_def_id != item_def_id {
-                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
-                let name = lang_item.name();
-                let mut err = match self.tcx.hir().span_if_local(item_def_id) {
-                    Some(span) => struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0152,
-                        "found duplicate lang item `{}`",
-                        name
-                    ),
-                    None => match self.tcx.extern_crate(item_def_id) {
-                        Some(ExternCrate { dependency_of, .. }) => {
-                            self.tcx.sess.struct_err(&format!(
-                                "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
-                                self.tcx.crate_name(item_def_id.krate),
-                                self.tcx.crate_name(*dependency_of),
-                                name
-                            ))
-                        }
-                        _ => self.tcx.sess.struct_err(&format!(
-                            "duplicate lang item in crate `{}`: `{}`.",
-                            self.tcx.crate_name(item_def_id.krate),
-                            name
-                        )),
-                    },
+                let local_span = self.tcx.hir().span_if_local(item_def_id);
+                let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
+                let crate_name = self.tcx.crate_name(item_def_id.krate);
+                let mut dependency_of = Empty;
+                let is_local = item_def_id.is_local();
+                let path = if is_local {
+                    String::new()
+                } else {
+                    self.tcx
+                        .crate_extern_paths(item_def_id.krate)
+                        .iter()
+                        .map(|p| p.display().to_string())
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                        .into()
                 };
-                if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
-                    err.span_note(span, "the lang item is first defined here");
+                let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
+                let mut orig_crate_name = Empty;
+                let mut orig_dependency_of = Empty;
+                let orig_is_local = original_def_id.is_local();
+                let orig_path = if orig_is_local {
+                    String::new()
                 } else {
-                    match self.tcx.extern_crate(original_def_id) {
-                        Some(ExternCrate { dependency_of, .. }) => {
-                            err.note(&format!(
-                                "the lang item is first defined in crate `{}` (which `{}` depends on)",
-                                self.tcx.crate_name(original_def_id.krate),
-                                self.tcx.crate_name(*dependency_of)
-                            ));
-                        }
-                        _ => {
-                            err.note(&format!(
-                                "the lang item is first defined in crate `{}`.",
-                                self.tcx.crate_name(original_def_id.krate)
-                            ));
-                        }
+                    self.tcx
+                        .crate_extern_paths(original_def_id.krate)
+                        .iter()
+                        .map(|p| p.display().to_string())
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                        .into()
+                };
+                if first_defined_span.is_none() {
+                    orig_crate_name = self.tcx.crate_name(original_def_id.krate);
+                    if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) =
+                        self.tcx.extern_crate(original_def_id)
+                    {
+                        orig_dependency_of = self.tcx.crate_name(*inner_dependency_of);
                     }
-                    let mut note_def = |which, def_id: DefId| {
-                        let crate_name = self.tcx.crate_name(def_id.krate);
-                        let note = if def_id.is_local() {
-                            format!("{} definition in the local crate (`{}`)", which, crate_name)
-                        } else {
-                            let paths: Vec<_> = self
-                                .tcx
-                                .crate_extern_paths(def_id.krate)
-                                .iter()
-                                .map(|p| p.display().to_string())
-                                .collect();
-                            format!(
-                                "{} definition in `{}` loaded from {}",
-                                which,
-                                crate_name,
-                                paths.join(", ")
-                            )
-                        };
-                        err.note(&note);
-                    };
-                    note_def("first", original_def_id);
-                    note_def("second", item_def_id);
                 }
-                err.emit();
+
+                let duplicate = if local_span.is_some() {
+                    Duplicate::Plain
+                } else {
+                    match self.tcx.extern_crate(item_def_id) {
+                        Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => {
+                            dependency_of = self.tcx.crate_name(*inner_dependency_of);
+                            Duplicate::CrateDepends
+                        }
+                        _ => Duplicate::Crate,
+                    }
+                };
+
+                self.tcx.sess.emit_err(DuplicateLangItem {
+                    local_span,
+                    lang_item_name,
+                    crate_name,
+                    dependency_of,
+                    is_local,
+                    path,
+                    first_defined_span,
+                    orig_crate_name,
+                    orig_dependency_of,
+                    orig_is_local,
+                    orig_path,
+                    duplicate,
+                });
             }
         }
 
@@ -179,41 +167,30 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                 None => (0, *item_span),
             };
 
+            let mut at_least = false;
             let required = match lang_item.required_generics() {
-                GenericRequirement::Exact(num) if num != actual_num => {
-                    Some((format!("{}", num), pluralize!(num)))
-                }
+                GenericRequirement::Exact(num) if num != actual_num => Some(num),
                 GenericRequirement::Minimum(num) if actual_num < num => {
-                    Some((format!("at least {}", num), pluralize!(num)))
-                }
+                    at_least = true;
+                    Some(num)}
+                ,
                 // If the number matches, or there is no requirement, handle it normally
                 _ => None,
             };
 
-            if let Some((range_str, pluralized)) = required {
+            if let Some(num) = required {
                 // We are issuing E0718 "incorrect target" here, because while the
                 // item kind of the target is correct, the target is still wrong
                 // because of the wrong number of generic arguments.
-                struct_span_err!(
-                    self.tcx.sess,
+                self.tcx.sess.emit_err(IncorrectTarget {
                     span,
-                    E0718,
-                    "`{}` language item must be applied to a {} with {} generic argument{}",
-                    name,
-                    kind.descr(),
-                    range_str,
-                    pluralized,
-                )
-                .span_label(
                     generics_span,
-                    format!(
-                        "this {} has {} generic argument{}",
-                        kind.descr(),
-                        actual_num,
-                        pluralize!(actual_num),
-                    ),
-                )
-                .emit();
+                    name: name.as_str(),
+                    kind: kind.descr(),
+                    num,
+                    actual_num,
+                    at_least,
+                });
 
                 // return early to not collect the lang item
                 return;
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 46c4a702fde..c1085094962 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -3,10 +3,13 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
 
+use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
+
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
@@ -35,62 +38,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri
             for meta_item in meta_items {
                 match meta_item.name_or_empty() {
                     sym::abi => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("abi: {:?}", ty_layout.abi),
-                        );
+                        tcx.sess.emit_err(Abi {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            abi: format!("{:?}", ty_layout.abi),
+                        });
                     }
 
                     sym::align => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("align: {:?}", ty_layout.align),
-                        );
+                        tcx.sess.emit_err(Align {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            align: format!("{:?}", ty_layout.align),
+                        });
                     }
 
                     sym::size => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("size: {:?}", ty_layout.size),
-                        );
+                        tcx.sess.emit_err(Size {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            size: format!("{:?}", ty_layout.size),
+                        });
                     }
 
                     sym::homogeneous_aggregate => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!(
-                                "homogeneous_aggregate: {:?}",
-                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+                        tcx.sess.emit_err(HomogeneousAggregate {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            homogeneous_aggregate: format!(
+                                "{:?}",
+                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
                             ),
-                        );
+                        });
                     }
 
                     sym::debug => {
-                        let normalized_ty = tcx.normalize_erasing_regions(
-                            param_env.with_reveal_all_normalized(tcx),
-                            ty,
-                        );
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+                        let normalized_ty = format!(
+                            "{:?}",
+                            tcx.normalize_erasing_regions(
+                                param_env.with_reveal_all_normalized(tcx),
+                                ty,
+                            )
                         );
+                        let ty_layout = format!("{:#?}", *ty_layout);
+                        tcx.sess.emit_err(LayoutOf {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            normalized_ty,
+                            ty_layout,
+                        });
                     }
 
                     name => {
-                        tcx.sess.span_err(
-                            meta_item.span(),
-                            &format!("unrecognized field name `{}`", name),
-                        );
+                        tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
                     }
                 }
             }
         }
 
         Err(layout_error) => {
-            tcx.sess.span_err(
-                tcx.def_span(item_def_id.to_def_id()),
-                &format!("layout error: {:?}", layout_error),
-            );
+            tcx.sess.emit_fatal(Spanned {
+                node: layout_error,
+                span: tcx.def_span(item_def_id.to_def_id()),
+            });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 6e621b7eb5e..15f60f626c8 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -5,6 +5,8 @@
 //! This API is completely unstable and subject to change.
 
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 04173c792a9..b5843c0ae48 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -6,7 +6,6 @@
 
 use rustc_ast::{Attribute, MetaItemKind};
 use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
-use rustc_errors::struct_span_err;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::LibFeatures;
@@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 
+use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
+
 fn new_lib_features() -> LibFeatures {
     LibFeatures { stable: Default::default(), unstable: Default::default() }
 }
@@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
             (Some(since), _, false) => {
                 if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
                     if *prev_since != since {
-                        self.span_feature_error(
+                        self.tcx.sess.emit_err(FeatureStableTwice {
                             span,
-                            &format!(
-                                "feature `{}` is declared stable since {}, \
-                                 but was previously declared stable since {}",
-                                feature, since, prev_since,
-                            ),
-                        );
+                            feature,
+                            since,
+                            prev_since: *prev_since,
+                        });
                         return;
                     }
                 }
@@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                 self.lib_features.unstable.insert(feature, span);
             }
             (Some(_), _, true) | (None, true, _) => {
-                self.span_feature_error(
+                let declared = if since.is_some() { "stable" } else { "unstable" };
+                let prev_declared = if since.is_none() { "stable" } else { "unstable" };
+                self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
                     span,
-                    &format!(
-                        "feature `{}` is declared {}, but was previously declared {}",
-                        feature,
-                        if since.is_some() { "stable" } else { "unstable" },
-                        if since.is_none() { "stable" } else { "unstable" },
-                    ),
-                );
+                    feature,
+                    declared,
+                    prev_declared,
+                });
             }
         }
     }
-
-    fn span_feature_error(&self, span: Span, msg: &str) {
-        struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit();
-    }
 }
 
 impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index cdda0e388dd..077194ec687 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,6 +1,5 @@
 use Context::*;
 
-use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -13,6 +12,11 @@ use rustc_session::Session;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::Span;
 
+use crate::errors::{
+    BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
+    UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
+};
+
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
@@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     Ok(loop_id) => Some(loop_id),
                     Err(hir::LoopIdError::OutsideLoopScope) => None,
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.emit_unlabled_cf_in_while_condition(e.span, "break");
+                        self.sess.emit_err(UnlabeledCfInWhileCondition {
+                            span: e.span,
+                            cf_type: "break",
+                        });
                         None
                     }
                     Err(hir::LoopIdError::UnresolvedLabel) => None,
@@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     match loop_kind {
                         None | Some(hir::LoopSource::Loop) => (),
                         Some(kind) => {
-                            let mut err = struct_span_err!(
-                                self.sess,
-                                e.span,
-                                E0571,
-                                "`break` with value from a `{}` loop",
-                                kind.name()
-                            );
-                            err.span_label(
-                                e.span,
-                                "can only break with a value inside `loop` or breakable block",
+                            let suggestion = format!(
+                                "break{}",
+                                break_label
+                                    .label
+                                    .map_or_else(String::new, |l| format!(" {}", l.ident))
                             );
-                            if let Some(head) = head {
-                                err.span_label(
-                                    head,
-                                    &format!(
-                                        "you can't `break` with a value in a `{}` loop",
-                                        kind.name()
-                                    ),
-                                );
-                            }
-                            err.span_suggestion(
-                                e.span,
-                                &format!(
-                                    "use `break` on its own without a value inside this `{}` loop",
-                                    kind.name(),
-                                ),
-                                format!(
-                                    "break{}",
-                                    break_label
-                                        .label
-                                        .map_or_else(String::new, |l| format!(" {}", l.ident))
-                                ),
-                                Applicability::MaybeIncorrect,
-                            );
-                            if let (Some(label), None) = (loop_label, break_label.label) {
-                                match break_expr.kind {
-                                    hir::ExprKind::Path(hir::QPath::Resolved(
-                                        None,
-                                        hir::Path {
-                                            segments: [segment],
-                                            res: hir::def::Res::Err,
-                                            ..
-                                        },
-                                    )) if label.ident.to_string()
-                                        == format!("'{}", segment.ident) =>
-                                    {
-                                        // This error is redundant, we will have already emitted a
-                                        // suggestion to use the label when `segment` wasn't found
-                                        // (hence the `Res::Err` check).
-                                        err.delay_as_bug();
-                                    }
-                                    _ => {
-                                        err.span_suggestion(
-                                            break_expr.span,
-                                            "alternatively, you might have meant to use the \
-                                             available loop label",
-                                            label.ident,
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                    }
-                                }
-                            }
-                            err.emit();
+                            self.sess.emit_err(BreakNonLoop {
+                                span: e.span,
+                                head,
+                                kind: kind.name(),
+                                suggestion,
+                                loop_label,
+                                break_label: break_label.label,
+                                break_expr_kind: &break_expr.kind,
+                                break_expr_span: break_expr.span,
+                            });
                         }
                     }
                 }
@@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 match destination.target_id {
                     Ok(loop_id) => {
                         if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
-                            struct_span_err!(
-                                self.sess,
-                                e.span,
-                                E0696,
-                                "`continue` pointing to a labeled block"
-                            )
-                            .span_label(e.span, "labeled blocks cannot be `continue`'d")
-                            .span_label(block.span, "labeled block the `continue` points to")
-                            .emit();
+                            self.sess.emit_err(ContinueLabeledBlock {
+                                span: e.span,
+                                block_span: block.span,
+                            });
                         }
                     }
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+                        self.sess.emit_err(UnlabeledCfInWhileCondition {
+                            span: e.span,
+                            cf_type: "continue",
+                        });
                     }
                     Err(_) => {}
                 }
@@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
     }
 
     fn require_break_cx(&self, name: &str, span: Span) {
-        let err_inside_of = |article, ty, closure_span| {
-            struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty)
-                .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty))
-                .span_label(closure_span, &format!("enclosing {}", ty))
-                .emit();
-        };
-
         match self.cx {
             LabeledBlock | Loop(_) => {}
-            Closure(closure_span) => err_inside_of("a", "closure", closure_span),
-            AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span),
+            Closure(closure_span) => {
+                self.sess.emit_err(BreakInsideClosure { span, closure_span, name });
+            }
+            AsyncClosure(closure_span) => {
+                self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
+            }
             Normal | AnonConst => {
-                struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name)
-                    .span_label(span, format!("cannot `{}` outside of a loop", name))
-                    .emit();
+                self.sess.emit_err(OutsideLoop { span, name });
             }
         }
     }
@@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         label: &Destination,
         cf_type: &str,
     ) -> bool {
-        if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock {
-            if label.label.is_none() {
-                struct_span_err!(
-                    self.sess,
-                    span,
-                    E0695,
-                    "unlabeled `{}` inside of a labeled block",
-                    cf_type
-                )
-                .span_label(
-                    span,
-                    format!(
-                        "`{}` statements that would diverge to or through \
-                                a labeled block need to bear a label",
-                        cf_type
-                    ),
-                )
-                .emit();
-                return true;
-            }
+        if !span.is_desugaring(DesugaringKind::QuestionMark)
+            && self.cx == LabeledBlock
+            && label.label.is_none()
+        {
+            self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type });
+            return true;
         }
         false
     }
-    fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
-        struct_span_err!(
-            self.sess,
-            span,
-            E0590,
-            "`break` or `continue` with no label in the condition of a `while` loop"
-        )
-        .span_label(span, format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
-        .emit();
-    }
 }
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 2690be66c21..acc54e7e110 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,7 +1,6 @@
 //! Checks validity of naked functions.
 
 use rustc_ast::InlineAsmOptions;
-use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
+use crate::errors::{
+    CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
+    NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
+    UndefinedNakedFunctionAbi,
+};
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_naked_functions, ..*providers };
 }
@@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
     for attr in attrs {
-        tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
+        tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
     }
 }
 
@@ -65,12 +70,11 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
     if abi == Abi::Rust {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let span = tcx.def_span(def_id);
-        tcx.struct_span_lint_hir(
+        tcx.emit_spanned_lint(
             UNDEFINED_NAKED_FUNCTION_ABI,
             hir_id,
             span,
-            "Rust ABI is unsupported in naked functions",
-            |lint| lint,
+            UndefinedNakedFunctionAbi,
         );
     }
 }
@@ -82,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
             hir::PatKind::Wild
             | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
             _ => {
-                tcx.sess
-                    .struct_span_err(
-                        param.pat.span,
-                        "patterns not allowed in naked function parameters",
-                    )
-                    .emit();
+                tcx.sess.emit_err(NoPatterns { span: param.pat.span });
             }
         }
     }
@@ -117,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
         )) = expr.kind
         {
             if self.params.contains(var_hir_id) {
-                self.tcx
-                    .sess
-                    .struct_span_err(
-                        expr.span,
-                        "referencing function parameters is not allowed in naked functions",
-                    )
-                    .help("follow the calling convention in asm block to use parameters")
-                    .emit();
+                self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
                 return;
             }
         }
@@ -139,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
     if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
         // Ok.
     } else {
-        let mut diag = struct_span_err!(
-            tcx.sess,
-            tcx.def_span(def_id),
-            E0787,
-            "naked functions must contain a single asm block"
-        );
-
         let mut must_show_error = false;
         let mut has_asm = false;
         let mut has_err = false;
+        let mut multiple_asms = vec![];
+        let mut non_asms = vec![];
         for &(kind, span) in &this.items {
             match kind {
                 ItemKind::Asm if has_asm => {
                     must_show_error = true;
-                    diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
+                    multiple_asms.push(span);
                 }
                 ItemKind::Asm => has_asm = true,
                 ItemKind::NonAsm => {
                     must_show_error = true;
-                    diag.span_label(span, "non-asm is unsupported in naked functions");
+                    non_asms.push(span);
                 }
                 ItemKind::Err => has_err = true,
             }
@@ -168,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
         // errors, then don't show an additional error. This allows for appending/prepending
         // `compile_error!("...")` statements and reduces error noise.
         if must_show_error || !has_err {
-            diag.emit();
-        } else {
-            diag.cancel();
+            tcx.sess.emit_err(NakedFunctionsAsmBlock {
+                span: tcx.def_span(def_id),
+                multiple_asms,
+                non_asms,
+            });
         }
     }
 }
@@ -251,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             })
             .collect();
         if !unsupported_operands.is_empty() {
-            struct_span_err!(
-                self.tcx.sess,
-                unsupported_operands,
-                E0787,
-                "only `const` and `sym` operands are supported in naked functions",
-            )
-            .emit();
+            self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
         }
 
         let unsupported_options: Vec<&'static str> = [
@@ -273,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         .collect();
 
         if !unsupported_options.is_empty() {
-            struct_span_err!(
-                self.tcx.sess,
+            self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
                 span,
-                E0787,
-                "asm options unsupported in naked functions: {}",
-                unsupported_options.join(", ")
-            )
-            .emit();
+                unsupported_options: unsupported_options.join(", "),
+            });
         }
 
         if !asm.options.contains(InlineAsmOptions::NORETURN) {
@@ -290,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
                 .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
                 .shrink_to_hi();
 
-            struct_span_err!(
-                self.tcx.sess,
-                span,
-                E0787,
-                "asm in naked functions must use `noreturn` option"
-            )
-            .span_suggestion(
-                last_span,
-                "consider specifying that the asm block is responsible \
-                for returning from the function",
-                ", options(noreturn)",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 34fa80228df..cfd6acd8d7c 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -1,13 +1,18 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use crate::errors;
+use crate::errors::{
+    self, CannotStabilizeDeprecated, DeprecatedAttribute, DuplicateFeatureErr,
+    FeatureOnlyOnNightly, ImpliedFeatureNotExist, InvalidDeprecationVersion, InvalidStability,
+    MissingConstErr, MissingConstStabAttr, MissingStabilityAttr, TraitImplConstStable,
+    UnknownFeature, UselessStability,
+};
 use rustc_attr::{
     self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
     UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -20,7 +25,6 @@ use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
 use rustc_middle::ty::{query::Providers, TyCtxt};
 use rustc_session::lint;
 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
-use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -179,7 +183,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 if !self.in_trait_impl
                     || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
                 {
-                    missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
+                    self.tcx
+                        .sess
+                        .emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span });
                 }
             }
         }
@@ -197,14 +203,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
 
         if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
             if stab.is_none() {
-                struct_span_err!(
-                    self.tcx.sess,
-                    *span,
-                    E0549,
-                    "deprecated attribute must be paired with \
-                    either stable or unstable attribute"
-                )
-                .emit();
+                self.tcx.sess.emit_err(DeprecatedAttribute { span: *span });
             }
         }
 
@@ -220,10 +219,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             if kind == AnnotationKind::Prohibited
                 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
             {
-                self.tcx.sess.struct_span_err(span,"this stability annotation is useless")
-                    .span_label(span, "useless stability annotation")
-                    .span_label(item_sp, "the stability attribute annotates this item")
-                    .emit();
+                self.tcx.sess.emit_err(UselessStability { span, item_sp });
             }
 
             debug!("annotate: found {:?}", stab);
@@ -239,19 +235,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 {
                     match stab_v.parse::<u64>() {
                         Err(_) => {
-                            self.tcx.sess.struct_span_err(span, "invalid stability version found")
-                                .span_label(span, "invalid stability version")
-                                .span_label(item_sp, "the stability attribute annotates this item")
-                                .emit();
+                            self.tcx.sess.emit_err(InvalidStability { span, item_sp });
                             break;
                         }
                         Ok(stab_vp) => match dep_v.parse::<u64>() {
                             Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
                                 Ordering::Less => {
-                                    self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated")
-                                        .span_label(span, "invalid version")
-                                        .span_label(item_sp, "the stability attribute annotates this item")
-                                        .emit();
+                                    self.tcx
+                                        .sess
+                                        .emit_err(CannotStabilizeDeprecated { span, item_sp });
                                     break;
                                 }
                                 Ordering::Equal => continue,
@@ -259,10 +251,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                             },
                             Err(_) => {
                                 if dep_v != "TBD" {
-                                    self.tcx.sess.struct_span_err(span, "invalid deprecation version found")
-                                        .span_label(span, "invalid deprecation version")
-                                        .span_label(item_sp, "the stability attribute annotates this item")
-                                        .emit();
+                                    self.tcx
+                                        .sess
+                                        .emit_err(InvalidDeprecationVersion { span, item_sp });
                                 }
                                 break;
                             }
@@ -271,7 +262,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 }
             }
 
-            if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
+            if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } =
+                stab
+            {
                 self.index.implications.insert(implied_by, feature);
             }
 
@@ -531,7 +524,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
         let stab = self.tcx.stability().local_stability(def_id);
         if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-            self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
+            self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
         }
     }
 
@@ -551,7 +544,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
 
         if is_const && is_stable && missing_const_stability_attribute && is_reachable {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-            self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
+            self.tcx.sess.emit_err(MissingConstStabAttr { span, descr });
         }
     }
 }
@@ -764,11 +757,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         && *constness == hir::Constness::Const
                         && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
                     {
-                        self.tcx
-                            .sess
-                            .struct_span_err(item.span, "trait implementations cannot be const stable yet")
-                            .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
-                            .emit();
+                        self.tcx.sess.emit_err(TraitImplConstStable { span: item.span });
                     }
                 }
 
@@ -929,7 +918,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         }
         if !lang_features.insert(feature) {
             // Warn if the user enables a lang feature multiple times.
-            duplicate_feature_err(tcx.sess, span, feature);
+            tcx.sess.emit_err(DuplicateFeatureErr { span, feature });
         }
     }
 
@@ -937,18 +926,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let mut remaining_lib_features = FxIndexMap::default();
     for (feature, span) in declared_lib_features {
         if !tcx.sess.opts.unstable_features.is_nightly_build() {
-            struct_span_err!(
-                tcx.sess,
-                *span,
-                E0554,
-                "`#![feature]` may not be used on the {} release channel",
-                env!("CFG_RELEASE_CHANNEL")
-            )
-            .emit();
+            tcx.sess.emit_err(FeatureOnlyOnNightly {
+                span: *span,
+                release_channel: env!("CFG_RELEASE_CHANNEL"),
+            });
         }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
-            duplicate_feature_err(tcx.sess, *span, *feature);
+            tcx.sess.emit_err(DuplicateFeatureErr { span: *span, feature: *feature });
         }
         remaining_lib_features.insert(feature, *span);
     }
@@ -1049,23 +1034,18 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     }
 
     for (feature, span) in remaining_lib_features {
-        struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
+        tcx.sess.emit_err(UnknownFeature { span, feature: *feature });
     }
 
     for (implied_by, feature) in remaining_implications {
         let local_defined_features = tcx.lib_features(());
-        let span = local_defined_features
+        let span = *local_defined_features
             .stable
             .get(&feature)
             .map(|(_, span)| span)
             .or_else(|| local_defined_features.unstable.get(&feature))
             .expect("feature that implied another does not exist");
-        tcx.sess
-            .struct_span_err(
-                *span,
-                format!("feature `{implied_by}` implying `{feature}` does not exist"),
-            )
-            .emit();
+        tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by });
     }
 
     // FIXME(#44232): the `used_features` table no longer exists, so we
@@ -1088,21 +1068,20 @@ fn unnecessary_partially_stable_feature_lint(
              by the feature `{implies}`"
         ),
         |lint| {
-            lint
-        .span_suggestion(
-            span,
-            &format!(
+            lint.span_suggestion(
+                span,
+                &format!(
                 "if you are using features which are still unstable, change to using `{implies}`"
             ),
-            implies,
-            Applicability::MaybeIncorrect,
-        )
-        .span_suggestion(
-            tcx.sess.source_map().span_extend_to_line(span),
-            "if you are using features which are now stable, remove this line",
-            "",
-            Applicability::MaybeIncorrect,
-        )
+                implies,
+                Applicability::MaybeIncorrect,
+            )
+            .span_suggestion(
+                tcx.sess.source_map().span_extend_to_line(span),
+                "if you are using features which are now stable, remove this line",
+                "",
+                Applicability::MaybeIncorrect,
+            )
         },
     );
 }
@@ -1120,20 +1099,3 @@ fn unnecessary_stable_feature_lint(
         lint
     });
 }
-
-fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
-    struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
-        .emit();
-}
-
-fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
-    const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
-         and `#[rustc_const_stable]` require \
-         the function or method to be `const`";
-
-    session
-        .struct_span_err(fn_sig_span, ERROR_MSG)
-        .span_help(fn_sig_span, "make the function or method const")
-        .span_label(const_span, "attribute specified here")
-        .emit();
-}
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index c48b4ecf87a..92024989a75 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -1,13 +1,17 @@
 //! Validity checking for weak lang items
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir::lang_items::{self, LangItem};
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
+use crate::errors::{
+    AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
+    UnknownExternLangItem,
+};
+
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
 pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) {
@@ -31,14 +35,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
                 }
             } else {
                 let span = tcx.def_span(id.def_id);
-                struct_span_err!(
-                    tcx.sess,
-                    span,
-                    E0264,
-                    "unknown external lang item: `{}`",
-                    lang_item
-                )
-                .emit();
+                tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
             }
         }
     }
@@ -71,20 +68,14 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
     for (name, &item) in WEAK_ITEMS_REFS.iter() {
         if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
             if item == LangItem::PanicImpl {
-                tcx.sess.err("`#[panic_handler]` function required, but not found");
+                tcx.sess.emit_err(MissingPanicHandler);
             } else if item == LangItem::Oom {
                 if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
-                    tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
+                    tcx.sess.emit_err(AllocFuncRequired);
+                    tcx.sess.emit_note(MissingAllocErrorHandler);
                 }
             } else {
-                tcx
-                    .sess
-                    .diagnostic()
-                    .struct_err(&format!("language item required, but not found: `{}`", name))
-                    .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name))
-                    .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name))
-                    .emit();
+                tcx.sess.emit_err(MissingLangItem { name: *name });
             }
         }
     }
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 8602a4cf5ae..1e74e0e2990 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -1,19 +1,15 @@
-use rustc_errors::AddToDiagnostic;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
+#[derive(Subdiagnostic)]
+#[note(query_system::cycle_stack_middle)]
 pub struct CycleStack {
+    #[primary_span]
     pub span: Span,
     pub desc: String,
 }
 
-impl AddToDiagnostic for CycleStack {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        diag.span_note(self.span, &format!("...which requires {}...", self.desc));
-    }
-}
-
 #[derive(Copy, Clone)]
 pub enum HandleCycleError {
     Error,
@@ -53,7 +49,7 @@ pub struct Cycle {
     #[primary_span]
     pub span: Span,
     pub stack_bottom: String,
-    #[subdiagnostic]
+    #[subdiagnostic(eager)]
     pub cycle_stack: Vec<CycleStack>,
     #[subdiagnostic]
     pub stack_count: StackCount,
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 8f6da73d1f2..f47760e9ae6 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -4,7 +4,7 @@
 #![feature(min_specialization)]
 #![feature(extern_types)]
 #![allow(rustc::potential_query_instability)]
-// #![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 83aae286402..c4644d4f076 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -139,8 +139,7 @@ impl<'a> Resolver<'a> {
                     &candidates,
                     if instead { Instead::Yes } else { Instead::No },
                     found_use,
-                    IsPattern::No,
-                    IsImport::No,
+                    DiagnosticMode::Normal,
                     path,
                 );
                 err.emit();
@@ -699,8 +698,7 @@ impl<'a> Resolver<'a> {
                         &import_suggestions,
                         Instead::No,
                         FoundUse::Yes,
-                        IsPattern::Yes,
-                        IsImport::No,
+                        DiagnosticMode::Pattern,
                         vec![],
                     );
                 }
@@ -1496,8 +1494,7 @@ impl<'a> Resolver<'a> {
             &import_suggestions,
             Instead::No,
             FoundUse::Yes,
-            IsPattern::No,
-            IsImport::No,
+            DiagnosticMode::Normal,
             vec![],
         );
 
@@ -2458,18 +2455,13 @@ enum FoundUse {
     No,
 }
 
-/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
-enum IsPattern {
+/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
+enum DiagnosticMode {
+    Normal,
     /// The binding is part of a pattern
-    Yes,
-    /// The binding is part of an expression
-    No,
-}
-
-/// Whether a binding is part of a use statement. Used for diagnostics.
-enum IsImport {
-    Yes,
-    No,
+    Pattern,
+    /// The binding is part of a use statement
+    Import,
 }
 
 pub(crate) fn import_candidates(
@@ -2488,8 +2480,7 @@ pub(crate) fn import_candidates(
         candidates,
         Instead::Yes,
         FoundUse::Yes,
-        IsPattern::No,
-        IsImport::Yes,
+        DiagnosticMode::Import,
         vec![],
     );
 }
@@ -2506,8 +2497,7 @@ fn show_candidates(
     candidates: &[ImportSuggestion],
     instead: Instead,
     found_use: FoundUse,
-    is_pattern: IsPattern,
-    is_import: IsImport,
+    mode: DiagnosticMode,
     path: Vec<Segment>,
 ) {
     if candidates.is_empty() {
@@ -2542,7 +2532,7 @@ fn show_candidates(
         };
 
         let instead = if let Instead::Yes = instead { " instead" } else { "" };
-        let mut msg = if let IsPattern::Yes = is_pattern {
+        let mut msg = if let DiagnosticMode::Pattern = mode {
             format!(
                 "if you meant to match on {}{}{}, use the full path in the pattern",
                 kind, instead, name
@@ -2555,19 +2545,24 @@ fn show_candidates(
             err.note(note);
         }
 
-        if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
-            err.span_suggestions(
-                span,
-                &msg,
-                accessible_path_strings.into_iter().map(|a| a.0),
-                Applicability::MaybeIncorrect,
-            );
-        } else if let Some(span) = use_placement_span {
+        if let Some(span) = use_placement_span {
+            let add_use = match mode {
+                DiagnosticMode::Pattern => {
+                    err.span_suggestions(
+                        span,
+                        &msg,
+                        accessible_path_strings.into_iter().map(|a| a.0),
+                        Applicability::MaybeIncorrect,
+                    );
+                    return;
+                }
+                DiagnosticMode::Import => "",
+                DiagnosticMode::Normal => "use ",
+            };
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
                 // from the directly following item.
                 let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
-                let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
                 candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
             }
 
@@ -2598,11 +2593,14 @@ fn show_candidates(
 
             err.note(&msg);
         }
-    } else if matches!(is_import, IsImport::No) {
+    } else if !matches!(mode, DiagnosticMode::Import) {
         assert!(!inaccessible_path_strings.is_empty());
 
-        let prefix =
-            if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
+        let prefix = if let DiagnosticMode::Pattern = mode {
+            "you might have meant to match on "
+        } else {
+            ""
+        };
         if inaccessible_path_strings.len() == 1 {
             let (name, descr, def_id, note) = &inaccessible_path_strings[0];
             let msg = format!(
@@ -2610,7 +2608,7 @@ fn show_candidates(
                 prefix,
                 descr,
                 name,
-                if let IsPattern::Yes = is_pattern { ", which" } else { "" }
+                if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
             );
 
             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 8d527c05122..102df3a4d7e 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1075,12 +1075,11 @@ mod parse {
 options! {
     CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
 
-    // This list is in alphabetical order.
-    //
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
     // - src/doc/rustc/src/codegen-options/index.md
 
+    // tidy-alphabetical-start
     ar: String = (String::new(), parse_string, [UNTRACKED],
         "this option is deprecated and does nothing"),
     #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
@@ -1195,9 +1194,8 @@ options! {
     target_feature: String = (String::new(), parse_target_feature, [TRACKED],
         "target specific attributes. (`rustc --print target-features` for details). \
         This feature is unsafe."),
+    // tidy-alphabetical-end
 
-    // This list is in alphabetical order.
-    //
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
     // - src/doc/rustc/src/codegen-options/index.md
@@ -1206,24 +1204,23 @@ options! {
 options! {
     UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
 
-    // This list is in alphabetical order.
-    //
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
     // - src/doc/unstable-book/src/compiler-flags
 
+    // tidy-alphabetical-start
     allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
         "only allow the listed language features to be enabled in code (space separated)"),
     always_encode_mir: bool = (false, parse_bool, [TRACKED],
         "encode MIR of all functions into the crate metadata (default: no)"),
-    assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
-        "make cfg(version) treat the current version as incomplete (default: no)"),
     #[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")]
     asm_comments: bool = (false, parse_bool, [TRACKED],
         "generate comments into the assembly (may change behavior) (default: no)"),
     assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "assert that the incremental cache is in given state: \
          either `loaded` or `not-loaded`."),
+    assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
+        "make cfg(version) treat the current version as incomplete (default: no)"),
     #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
@@ -1256,6 +1253,8 @@ options! {
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
         "print tasks that execute and the color their dep node gets (requires debug build) \
         (default: no)"),
+    diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
+        "set the current output width for diagnostic truncation"),
     dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
@@ -1337,16 +1336,16 @@ options! {
         "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
         "verify incr. comp. hashes of green query instances (default: no)"),
+    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "control whether `#[inline]` functions are in all CGUs"),
     inline_llvm: bool = (true, parse_bool, [TRACKED],
         "enable LLVM inlining (default: yes)"),
     inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable MIR inlining (default: no)"),
-    inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
-        "a default MIR inlining threshold (default: 50)"),
     inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
         "inlining threshold for functions with inline hint (default: 100)"),
-    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "control whether `#[inline]` functions are in all CGUs"),
+    inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
+        "a default MIR inlining threshold (default: 50)"),
     input_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather statistics about the input (default: no)"),
     #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
@@ -1363,6 +1362,8 @@ options! {
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
         "keep hygiene data after analysis (default: no)"),
+    layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
+        "seed layout randomization"),
     link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
         "link native libraries in the linker invocation (default: yes)"),
     link_only: bool = (false, parse_bool, [TRACKED],
@@ -1392,11 +1393,11 @@ options! {
         "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
         enabled, overriding all other checks. Passes that are not specified are enabled or \
         disabled by other flags as usual."),
-    mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
-        "use line numbers relative to the function in mir pretty printing"),
     #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
     mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
         "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
+    mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
+        "use line numbers relative to the function in mir pretty printing"),
     move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
         "the size at which the `large_assignments` lint starts to be emitted"),
     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1419,18 +1420,16 @@ options! {
         "compile without linking"),
     no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
-    no_unique_section_names: bool = (false, parse_bool, [TRACKED],
-        "do not use unique names for text and data sections when -Z function-sections is used"),
     no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
         "prevent automatic injection of the profiler_builtins crate"),
+    no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+        "do not use unique names for text and data sections when -Z function-sections is used"),
     normalize_docs: bool = (false, parse_bool, [TRACKED],
         "normalize associated items in rustdoc when generating documentation"),
     oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
         "panic strategy for out-of-memory handling"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
         "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
-    diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
-        "set the current output width for diagnostic truncation"),
     packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
         "change rlib format to store native libraries as archives"),
     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
@@ -1480,25 +1479,20 @@ options! {
     profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "file path to emit profiling data at runtime when using 'profile' \
         (default based on relative source path)"),
-    profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
-        "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
     profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
+    profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
+        "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing (default: no)"),
     randomize_layout: bool = (false, parse_bool, [TRACKED],
         "randomize the layout of types (default: no)"),
-    layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
-        "seed layout randomization"),
     relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "whether ELF relocations can be relaxed"),
     relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
         "choose which RELRO level to use"),
     remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "remap paths under the current working directory to this path prefix"),
-    simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
-        "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
-        to rust's source base directory. only meant for testing purposes"),
     report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
         "immediately print bugs registered with `delay_span_bug` (default: no)"),
     sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
@@ -1516,27 +1510,41 @@ options! {
     self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
         parse_switch_with_opt_path, [UNTRACKED],
         "run the self profiler and output the raw event data"),
-    /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
-    self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
-        "specify the events recorded by the self profiler;
-        for example: `-Z self-profile-events=default,query-keys`
-        all options: none, all, default, generic-activity, query-provider, query-cache-hit
-                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
     self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
         "counter used by the self profiler (default: `wall-time`), one of:
         `wall-time` (monotonic clock, i.e. `std::time::Instant`)
         `instructions:u` (retired instructions, userspace-only)
         `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
     ),
+    /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
+    self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
+        "specify the events recorded by the self profiler;
+        for example: `-Z self-profile-events=default,query-keys`
+        all options: none, all, default, generic-activity, query-provider, query-cache-hit
+                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "make the current crate share its generic instantiations"),
     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
         "show spans for compiler debugging (expr|pat|ty)"),
+    simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+        "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
+        to rust's source base directory. only meant for testing purposes"),
     span_debug: bool = (false, parse_bool, [UNTRACKED],
         "forward proc_macro::Span's `Debug` impl to `Span`"),
     /// o/w tests have closure@path
     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
         "exclude spans when debug-printing compiler state (default: no)"),
+    split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
+        "provide minimal debug info in the object/executable to facilitate online \
+         symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
+    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
+        "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+        (default: `split`)
+
+        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+                 file which is ignored by the linker
+        `single`: sections which do not require relocation are written into object file but ignored
+                  by the linker"),
     src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
     #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
@@ -1546,17 +1554,6 @@ options! {
         "control if mem::uninitialized and mem::zeroed panic on more UB"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
-    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
-        "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
-        (default: `split`)
-
-        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
-                 file which is ignored by the linker
-        `single`: sections which do not require relocation are written into object file but ignored
-                  by the linker"),
-    split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
-        "provide minimal debug info in the object/executable to facilitate online \
-         symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
     symbol_mangling_version: Option<SymbolManglingVersion> = (None,
         parse_symbol_mangling_version, [TRACKED],
         "which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
@@ -1565,17 +1562,6 @@ options! {
         "show extended diagnostic help (default: no)"),
     temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "the directory the intermediate files are written to"),
-    // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
-    // alongside query results and changes to translation options can affect diagnostics - so
-    // translation options should be tracked.
-    translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
-        "language identifier for diagnostic output"),
-    translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
-        "additional fluent translation to preferentially use (for testing translation)"),
-    translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
-        "emit directionality isolation markers in translated diagnostics"),
-    tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
-        "select processor to schedule for (`rustc --print target-cpus` for details)"),
     #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
@@ -1599,6 +1585,15 @@ options! {
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
         "for every macro invocation, print its name and arguments (default: no)"),
+    // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
+    // alongside query results and changes to translation options can affect diagnostics - so
+    // translation options should be tracked.
+    translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+        "additional fluent translation to preferentially use (for testing translation)"),
+    translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
+        "emit directionality isolation markers in translated diagnostics"),
+    translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
+        "language identifier for diagnostic output"),
     translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
         "translate remapped paths into local paths when possible (default: yes)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1607,6 +1602,8 @@ options! {
         "treat error number `val` that occurs as bug"),
     trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
         "in diagnostics, use heuristics to shorten paths referring to items"),
+    tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
+        "select processor to schedule for (`rustc --print target-cpus` for details)"),
     ui_testing: bool = (false, parse_bool, [UNTRACKED],
         "emit compiler diagnostics in a form suitable for UI testing (default: no)"),
     uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
@@ -1647,9 +1644,8 @@ options! {
         Requires `-Clto[=[fat,yes]]`"),
     wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
         "whether to build a wasi command or reactor"),
+    // tidy-alphabetical-end
 
-    // This list is in alphabetical order.
-    //
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
 }
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 2c3d8d5283b..a199947ebed 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey,
+    EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
@@ -354,6 +354,17 @@ impl ParseSess {
         self.create_warning(warning).emit()
     }
 
+    pub fn create_note<'a>(
+        &'a self,
+        note: impl IntoDiagnostic<'a, Noted>,
+    ) -> DiagnosticBuilder<'a, Noted> {
+        note.into_diagnostic(&self.span_diagnostic)
+    }
+
+    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+        self.create_note(note).emit()
+    }
+
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 5926cdc9dad..beb22ab3eb9 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan,
+    ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -489,6 +489,15 @@ impl Session {
     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
         self.parse_sess.emit_warning(warning)
     }
+    pub fn create_note<'a>(
+        &'a self,
+        note: impl IntoDiagnostic<'a, Noted>,
+    ) -> DiagnosticBuilder<'a, Noted> {
+        self.parse_sess.create_note(note)
+    }
+    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+        self.parse_sess.emit_note(note)
+    }
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index d2fb8c32ffd..9fe7da3f29e 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -740,7 +740,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
-    // These are in alphabetical order, which is easy to maintain.
+    // tidy-alphabetical-start
     static_assert_size!(ArgAbi<'_, usize>, 56);
     static_assert_size!(FnAbi<'_, usize>, 80);
+    // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 30efbf66175..196d70614e7 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -85,9 +85,13 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
 ///     - a type parameter or projection whose Sizedness can't be known
 ///     - a tuple of type parameters or projections, if there are multiple
 ///       such.
-///     - an Error, if a type contained itself. The representability
-///       check should catch this case.
-fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
+///     - an Error, if a type is infinitely sized
+fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
+    if let Some(def_id) = def_id.as_local() {
+        if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
+            return tcx.intern_type_list(&[tcx.ty_error()]);
+        }
+    }
     let def = tcx.adt_def(def_id);
 
     let result = tcx.mk_type_list(
@@ -99,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
 
     debug!("adt_sized_constraint: {:?} => {:?}", def, result);
 
-    ty::AdtSizedConstraint(result)
+    result
 }
 
 /// See `ParamEnv` struct definition for details.
@@ -133,77 +137,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     let local_did = def_id.as_local();
     let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
 
-    let constness = match hir_id {
-        Some(hir_id) => match tcx.hir().get(hir_id) {
-            hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
-                if tcx.is_const_default_method(def_id) =>
-            {
-                hir::Constness::Const
-            }
-
-            hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
-            | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
-            | hir::Node::TraitItem(hir::TraitItem {
-                kind: hir::TraitItemKind::Const(..), ..
-            })
-            | hir::Node::AnonConst(_)
-            | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
-            | hir::Node::ImplItem(hir::ImplItem {
-                kind:
-                    hir::ImplItemKind::Fn(
-                        hir::FnSig {
-                            header: hir::FnHeader { constness: hir::Constness::Const, .. },
-                            ..
-                        },
-                        ..,
-                    ),
-                ..
-            }) => hir::Constness::Const,
-
-            hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
-                ..
-            }) => {
-                let parent_hir_id = tcx.hir().get_parent_node(hir_id);
-                match tcx.hir().get(parent_hir_id) {
-                    hir::Node::Item(hir::Item {
-                        kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                        ..
-                    }) => *constness,
-                    _ => span_bug!(
-                        tcx.def_span(parent_hir_id.owner),
-                        "impl item's parent node is not an impl",
-                    ),
-                }
-            }
-
-            hir::Node::Item(hir::Item {
-                kind:
-                    hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
-                ..
-            })
-            | hir::Node::TraitItem(hir::TraitItem {
-                kind:
-                    hir::TraitItemKind::Fn(
-                        hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
-                        ..,
-                    ),
-                ..
-            })
-            | hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                ..
-            }) => *constness,
-
-            _ => hir::Constness::NotConst,
-        },
-        None => hir::Constness::NotConst,
-    };
-
     let unnormalized_env = ty::ParamEnv::new(
         tcx.intern_predicates(&predicates),
         traits::Reveal::UserFacing,
-        constness,
+        tcx.constness(def_id),
     );
 
     let body_id =
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index d6aeee299e3..ff3b7bc2c90 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2279,9 +2279,8 @@ macro_rules! int_impl {
         ///
         /// # Panics
         ///
-        /// When the number is negative, zero, or if the base is not at least 2; it
-        /// panics in debug mode and the return value is 0 in release
-        /// mode.
+        /// This function will panic if `self` is less than or equal to zero,
+        /// or if `base` is less then 2.
         ///
         /// # Examples
         ///
@@ -2294,27 +2293,16 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
-            match self.checked_ilog(base) {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            assert!(base >= 2, "base of integer logarithm must be at least 2");
+            self.checked_ilog(base).expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 2 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the return value
-        /// is 0 in release mode.
+        /// This function will panic if `self` is less than or equal to zero.
         ///
         /// # Examples
         ///
@@ -2327,27 +2315,15 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
-            match self.checked_ilog2() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 10 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the return value
-        /// is 0 in release mode.
+        /// This function will panic if `self` is less than or equal to zero.
         ///
         /// # Example
         ///
@@ -2360,19 +2336,8 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
-            match self.checked_ilog10() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the logarithm of the number with respect to an arbitrary base,
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 46b0ca23034..d921ff9ba10 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -692,8 +692,7 @@ macro_rules! uint_impl {
         ///
         /// # Panics
         ///
-        /// When the number is zero, or if the base is not at least 2;
-        /// it panics in debug mode and the return value is 0 in release mode.
+        /// This function will panic if `self` is zero, or if `base` is less then 2.
         ///
         /// # Examples
         ///
@@ -706,27 +705,16 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
-            match self.checked_ilog(base) {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            assert!(base >= 2, "base of integer logarithm must be at least 2");
+            self.checked_ilog(base).expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 2 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and
-        /// the return value is 0 in release mode.
+        /// This function will panic if `self` is zero.
         ///
         /// # Examples
         ///
@@ -739,27 +727,15 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
-            match self.checked_ilog2() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 10 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the
-        /// return value is 0 in release mode.
+        /// This function will panic if `self` is zero.
         ///
         /// # Example
         ///
@@ -772,19 +748,8 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
-            match self.checked_ilog10() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the logarithm of the number with respect to an arbitrary base,
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index be203fb5c04..a1edb1a5186 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -164,3 +164,33 @@ fn ilog10_u64() {
 fn ilog10_u128() {
     ilog10_loop! { u128, 38 }
 }
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog2_of_0_panic() {
+    let _ = 0u32.ilog2();
+}
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog10_of_0_panic() {
+    let _ = 0u32.ilog10();
+}
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog3_of_0_panic() {
+    let _ = 0u32.ilog(3);
+}
+
+#[test]
+#[should_panic(expected = "base of integer logarithm must be at least 2")]
+fn ilog0_of_1_panic() {
+    let _ = 1u32.ilog(0);
+}
+
+#[test]
+#[should_panic(expected = "base of integer logarithm must be at least 2")]
+fn ilog1_of_1_panic() {
+    let _ = 1u32.ilog(1);
+}
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 4461b21802a..506b2a773cc 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -223,10 +223,10 @@ pub(crate) use super::symbol::Symbol;
 
 macro_rules! define_client_side {
     ($($name:ident {
-        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
+        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
     }),* $(,)?) => {
         $(impl $name {
-            $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
+            $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
                 Bridge::with(|bridge| {
                     let mut buf = bridge.cached_buffer.take();
 
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
index b1a84095f13..4800eeda022 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/std/src/io/readbuf.rs
@@ -3,10 +3,10 @@
 #[cfg(test)]
 mod tests;
 
-use crate::cmp;
 use crate::fmt::{self, Debug, Formatter};
 use crate::io::{Result, Write};
 use crate::mem::{self, MaybeUninit};
+use crate::{cmp, ptr};
 
 /// A borrowed byte buffer which is incrementally filled and initialized.
 ///
@@ -250,8 +250,11 @@ impl<'a> BorrowedCursor<'a> {
     /// Initializes all bytes in the cursor.
     #[inline]
     pub fn ensure_init(&mut self) -> &mut Self {
-        for byte in self.uninit_mut() {
-            byte.write(0);
+        let uninit = self.uninit_mut();
+        // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
+        // since it is comes from a slice reference.
+        unsafe {
+            ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
         }
         self.buf.init = self.buf.capacity();
 
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 4b07b393a2f..d4976a469cc 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -308,6 +308,14 @@ pub mod panic_count {
     // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
     // records whether panic::always_abort() has been called.  This can only be
     // set, never cleared.
+    // panic::always_abort() is usually called to prevent memory allocations done by
+    // the panic handling in the child created by `libc::fork`.
+    // Memory allocations performed in  a child created with `libc::fork` are undefined
+    // behavior in most operating systems.
+    // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory
+    // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
+    // sufficient because a child process will always have exactly one thread only.
+    // See also #85261 for details.
     //
     // This could be viewed as a struct containing a single bit and an n-1-bit
     // value, but if we wrote it like that it would be more than a single word,
@@ -318,15 +326,26 @@ pub mod panic_count {
     // panicking thread consumes at least 2 bytes of address space.
     static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
 
+    // Return the state of the ALWAYS_ABORT_FLAG and number of panics.
+    //
+    // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread
+    // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls
+    // of the calling thread.
+    // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic
+    // calls. See above why LOCAL_PANIC_COUNT is not used.
     pub fn increase() -> (bool, usize) {
-        (
-            GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed) & ALWAYS_ABORT_FLAG != 0,
+        let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+        let must_abort = global_count & ALWAYS_ABORT_FLAG != 0;
+        let panics = if must_abort {
+            global_count & !ALWAYS_ABORT_FLAG
+        } else {
             LOCAL_PANIC_COUNT.with(|c| {
                 let next = c.get() + 1;
                 c.set(next);
                 next
-            }),
-        )
+            })
+        };
+        (must_abort, panics)
     }
 
     pub fn decrease() {
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 415774d7255..8b144f14635 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -704,6 +704,7 @@ impl<'a> Builder<'a> {
                 doc::Miri,
                 doc::EmbeddedBook,
                 doc::EditionGuide,
+                doc::StyleGuide,
             ),
             Kind::Dist => describe!(
                 dist::Docs,
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 819af658748..7bdd226cb69 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -82,6 +82,7 @@ book!(
     Reference, "src/doc/reference", "reference", submodule;
     RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
     RustdocBook, "src/doc/rustdoc", "rustdoc";
+    StyleGuide, "src/doc/style-guide", "style-guide";
 );
 
 fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
diff --git a/src/doc/index.md b/src/doc/index.md
index 744c7f709a6..bf08960f338 100644
--- a/src/doc/index.md
+++ b/src/doc/index.md
@@ -113,6 +113,12 @@ resources useful.
 [The Reference](reference/index.html) is not a formal spec, but is more detailed and
 comprehensive than the book.
 
+## The Style Guide
+
+[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
+code. Most developers use rustfmt to format their code, and rustfmt's default
+formatting matches this style guide.
+
 ## The Rustonomicon
 
 [The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml
new file mode 100644
index 00000000000..056aec8cdd4
--- /dev/null
+++ b/src/doc/style-guide/book.toml
@@ -0,0 +1,8 @@
+[book]
+title = "The Rust Style Guide"
+author = "The Rust Style Team"
+multilingual = false
+src = "src"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/"
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
new file mode 100644
index 00000000000..adb73a7eef6
--- /dev/null
+++ b/src/doc/style-guide/src/README.md
@@ -0,0 +1,190 @@
+# Rust Style Guide
+
+## Motivation - why use a formatting tool?
+
+Formatting code is a mostly mechanical task which takes both time and mental
+effort. By using an automatic formatting tool, a programmer is relieved of
+this task and can concentrate on more important things.
+
+Furthermore, by sticking to an established style guide (such as this one),
+programmers don't need to formulate ad hoc style rules, nor do they need to
+debate with other programmers what style rules should be used, saving time,
+communication overhead, and mental energy.
+
+Humans comprehend information through pattern matching. By ensuring that all
+Rust code has similar formatting, less mental effort is required to comprehend a
+new project, lowering the barrier to entry for new developers.
+
+Thus, there are productivity benefits to using a formatting tool (such as
+rustfmt), and even larger benefits by using a community-consistent formatting,
+typically by using a formatting tool's default settings.
+
+
+## Formatting conventions
+
+### Indentation and line width
+
+* Use spaces, not tabs.
+* Each level of indentation must be four spaces (that is, all indentation
+  outside of string literals and comments must be a multiple of four).
+* The maximum width for a line is 100 characters.
+* A tool should be configurable for all three of these variables.
+
+
+### Blank lines
+
+Separate items and statements by either zero or one blank lines (i.e., one or
+two newlines). E.g,
+
+```rust
+fn foo() {
+    let x = ...;
+
+    let y = ...;
+    let z = ...;
+}
+
+fn bar() {}
+fn baz() {}
+```
+
+Formatting tools should make the bounds on blank lines configurable: there
+should be separate minimum and maximum numbers of newlines between both
+statements and (top-level) items (i.e., four options). As described above, the
+defaults for both statements and items should be minimum: 1, maximum: 2.
+
+
+### [Module-level items](items.md)
+### [Statements](statements.md)
+### [Expressions](expressions.md)
+### [Types](types.md)
+
+
+### Comments
+
+The following guidelines for comments are recommendations only, a mechanical
+formatter might skip formatting of comments.
+
+Prefer line comments (`//`) to block comments (`/* ... */`).
+
+When using line comments there should be a single space after the opening sigil.
+
+When using single-line block comments there should be a single space after the
+opening sigil and before the closing sigil. Multi-line block comments should
+have a newline after the opening sigil and before the closing sigil.
+
+Prefer to put a comment on its own line. Where a comment follows code, there
+should be a single space before it. Where a block comment is inline, there
+should be surrounding whitespace as if it were an identifier or keyword. There
+should be no trailing whitespace after a comment or at the end of any line in a
+multi-line comment. Examples:
+
+```rust
+// A comment on an item.
+struct Foo { ... }
+
+fn foo() {} // A comment after an item.
+
+pub fn foo(/* a comment before an argument */ x: T) {...}
+```
+
+Comments should usually be complete sentences. Start with a capital letter, end
+with a period (`.`). An inline block comment may be treated as a note without
+punctuation.
+
+Source lines which are entirely a comment should be limited to 80 characters
+in length (including comment sigils, but excluding indentation) or the maximum
+width of the line (including comment sigils and indentation), whichever is
+smaller:
+
+```rust
+// This comment goes up to the ................................. 80 char margin.
+
+{
+    // This comment is .............................................. 80 chars wide.
+}
+
+{
+    {
+        {
+            {
+                {
+                    {
+                        // This comment is limited by the ......................... 100 char margin.
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+#### Doc comments
+
+Prefer line comments (`///`) to block comments (`/** ... */`).
+
+Prefer outer doc comments (`///` or `/** ... */`), only use inner doc comments
+(`//!` and `/*! ... */`) to write module-level or crate-level documentation.
+
+Doc comments should come before attributes.
+
+### Attributes
+
+Put each attribute on its own line, indented to the level of the item.
+In the case of inner attributes (`#!`), indent it to the level of the inside of
+the item. Prefer outer attributes, where possible.
+
+For attributes with argument lists, format like functions.
+
+```rust
+#[repr(C)]
+#[foo(foo, bar)]
+struct CRepr {
+    #![repr(C)]
+    x: f32,
+    y: f32,
+}
+```
+
+For attributes with an equal sign, there should be a single space before and
+after the `=`, e.g., `#[foo = 42]`.
+
+There must only be a single `derive` attribute. Note for tool authors: if
+combining multiple `derive` attributes into a single attribute, the ordering of
+the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)]
+struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`.
+
+### *small* items
+
+In many places in this guide we specify that a formatter may format an item
+differently if it is *small*, for example struct literals:
+
+```rust
+// Normal formatting
+Foo {
+    f1: an_expression,
+    f2: another_expression(),
+}
+
+// *small* formatting
+Foo { f1, f2 }
+```
+
+We leave it to individual tools to decide on exactly what *small* means. In
+particular, tools are free to use different definitions in different
+circumstances.
+
+Some suitable heuristics are the size of the item (in characters) or the
+complexity of an item (for example, that all components must be simple names,
+not more complex sub-expressions). For more discussion on suitable heuristics,
+see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47).
+
+Tools should give the user an option to ignore such heuristics and always use
+the normal formatting.
+
+
+## [Non-formatting conventions](advice.md)
+
+## [Cargo.toml conventions](cargo.md)
+
+## [Principles used for deciding these guidelines](principles.md)
diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md
new file mode 100644
index 00000000000..004692fa6a2
--- /dev/null
+++ b/src/doc/style-guide/src/SUMMARY.md
@@ -0,0 +1,11 @@
+# Summary
+
+[Introduction](README.md)
+
+- [Module-level items](items.md)
+- [Statements](statements.md)
+- [Expressions](expressions.md)
+- [Types](types.md)
+- [Non-formatting conventions](advice.md)
+- [`Cargo.toml` conventions](cargo.md)
+- [Principles used for deciding these guidelines](principles.md)
diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md
new file mode 100644
index 00000000000..ab4b92b0a24
--- /dev/null
+++ b/src/doc/style-guide/src/advice.md
@@ -0,0 +1,34 @@
+# Other style advice
+
+## Expressions
+
+Prefer to use Rust's expression oriented nature where possible;
+
+```rust
+// use
+let x = if y { 1 } else { 0 };
+// not
+let x;
+if y {
+    x = 1;
+} else {
+    x = 0;
+}
+```
+
+## Names
+
+ * Types shall be `UpperCamelCase`,
+ * Enum variants shall be `UpperCamelCase`,
+ * Struct fields shall be `snake_case`,
+ * Function and method names shall be `snake_case`,
+ * Local variables shall be `snake_case`,
+ * Macro names shall be `snake_case`,
+ * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`.
+ * When a name is forbidden because it is a reserved word (e.g., `crate`), use a
+   trailing underscore to make the name legal (e.g., `crate_`), or use raw
+   identifiers if possible.
+
+### Modules
+
+Avoid `#[path]` annotations where possible.
diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md
new file mode 100644
index 00000000000..f4993ba06a8
--- /dev/null
+++ b/src/doc/style-guide/src/cargo.md
@@ -0,0 +1,78 @@
+# Cargo.toml conventions
+
+## Formatting conventions
+
+Use the same line width and indentation as Rust code.
+
+Put a blank line between the last key-value pair in a section and the header of
+the next section. Do not place a blank line between section headers and the
+key-value pairs in that section, or between key-value pairs in a section.
+
+Sort key names alphabetically within each section, with the exception of the
+`[package]` section. Put the `[package]` section at the top of the file; put
+the `name` and `version` keys in that order at the top of that section,
+followed by the remaining keys other than `description` in alphabetical order,
+followed by the `description` at the end of that section.
+
+Don't use quotes around any standard key names; use bare keys. Only use quoted
+keys for non-standard keys whose names require them, and avoid introducing such
+key names when possible.  See the [TOML
+specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table)
+for details.
+
+Put a single space both before and after the `=` between a key and value. Do
+not indent any key names; start all key names at the start of a line.
+
+Use multi-line strings (rather than newline escape sequences) for any string
+values that include multiple lines, such as the crate description.
+
+For array values, such as a list of authors, put the entire list on the same
+line as the key, if it fits. Otherwise, use block indentation: put a newline
+after the opening square bracket, indent each item by one indentation level,
+put a comma after each item (including the last), and put the closing square
+bracket at the start of a line by itself after the last item.
+
+```rust
+authors = [
+    "A Uthor <a.uthor@example.org>",
+    "Another Author <author@example.net>",
+]
+```
+
+For table values, such as a crate dependency with a path, write the entire
+table using curly braces and commas on the same line as the key if it fits. If
+the entire table does not fit on the same line as the key, separate it out into
+a separate section with key-value pairs:
+
+```toml
+[dependencies]
+crate1 = { path = "crate1", version = "1.2.3" }
+
+[dependencies.extremely_long_crate_name_goes_here]
+path = "extremely_long_path_name_goes_right_here"
+version = "4.5.6"
+```
+
+## Metadata conventions
+
+The authors list should consist of strings that each contain an author name
+followed by an email address in angle brackets: `Full Name <email@address>`.
+It should not contain bare email addresses, or names without email addresses.
+(The authors list may also include a mailing list address without an associated
+name.)
+
+The license field must contain a valid [SPDX
+expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60),
+using valid [SPDX license names](https://spdx.org/licenses/). (As an exception,
+by widespread convention, the license field may use `/` in place of ` OR `; for
+example, `MIT/Apache-2.0`.)
+
+The homepage field, if present, must consist of a single URL, including the
+scheme (e.g. `https://example.org/`, not just `example.org`.)
+
+Within the description field, wrap text at 80 columns. Don't start the
+description field with the name of the crate (e.g. "cratename is a ..."); just
+describe the crate itself. If providing a multi-sentence description, the first
+sentence should go on a line by itself and summarize the crate, like the
+subject of an email or commit message; subsequent sentences can then describe
+the crate in more detail.
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
new file mode 100644
index 00000000000..c7d0446dded
--- /dev/null
+++ b/src/doc/style-guide/src/expressions.md
@@ -0,0 +1,850 @@
+## Expressions
+
+### Blocks
+
+A block expression should have a newline after the initial `{` and before the
+terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be
+on the same line as the opening brace, and separated with a single space. The
+contents of the block should be block indented:
+
+```rust
+fn block_as_stmt() {
+    a_call();
+
+    {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    }
+}
+
+fn block_as_expr() {
+    let foo = {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    };
+}
+
+fn unsafe_block_as_stmt() {
+    a_call();
+
+    unsafe {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    }
+}
+```
+
+If a block has an attribute, it should be on its own line:
+
+```rust
+fn block_as_stmt() {
+    #[an_attribute]
+    {
+        #![an_inner_attribute]
+
+        // a comment in a block
+        the_value
+    }
+}
+```
+
+Avoid writing comments on the same line as the braces.
+
+An empty block should be written as `{}`.
+
+A block may be written on a single line if:
+
+* it is either used in expression position (not statement position) or is an
+  unsafe block in statement position
+* contains a single-line expression and no statements
+* contains no comments
+
+A single line block should have spaces after the opening brace and before the
+closing brace.
+
+Examples:
+
+```rust
+fn main() {
+    // Single line
+    let _ = { a_call() };
+    let _ = unsafe { a_call() };
+
+    // Not allowed on one line
+    // Statement position.
+    {
+        a_call()
+    }
+
+    // Contains a statement
+    let _ = {
+        a_call();
+    };
+    unsafe {
+        a_call();
+    }
+
+    // Contains a comment
+    let _ = {
+        // A comment
+    };
+    let _ = {
+        // A comment
+        a_call()
+    };
+
+    // Multiple lines
+    let _ = {
+        a_call();
+        another_call()
+    };
+    let _ = {
+        a_call(
+            an_argument,
+            another_arg,
+        )
+    };
+}
+```
+
+
+### Closures
+
+Don't put any extra spaces before the first `|` (unless the closure is prefixed
+by `move`); put a space between the second `|` and the expression of the
+closure. Between the `|`s, you should use function definition syntax, however,
+elide types where possible.
+
+Use closures without the enclosing `{}`, if possible. Add the `{}` when you have
+a return type, when there are statements, there are comments in the body, or the
+body expression spans multiple lines and is a control-flow expression. If using
+braces, follow the rules above for blocks. Examples:
+
+```rust
+|arg1, arg2| expr
+
+move |arg1: i32, arg2: i32| -> i32 {
+    expr1;
+    expr2
+}
+
+|| Foo {
+    field1,
+    field2: 0,
+}
+
+|| {
+    if true {
+        blah
+    } else {
+        boo
+    }
+}
+
+|x| unsafe {
+    expr
+}
+```
+
+
+### Struct literals
+
+If a struct literal is *small* it may be formatted on a single line. If not,
+each field should be on it's own, block-indented line. There should be a
+trailing comma in the multi-line form only. There should be a space after the
+colon only.
+
+There should be a space before the opening brace. In the single-line form there
+should be spaces after the opening brace and before the closing brace.
+
+```rust
+Foo { field1, field2: 0 }
+let f = Foo {
+    field1,
+    field2: an_expr,
+};
+```
+
+Functional record update syntax is treated like a field, but it must never have
+a trailing comma. There should be no space after `..`.
+
+let f = Foo {
+    field1,
+    ..an_expr
+};
+
+
+### Tuple literals
+
+Use a single-line form where possible. There should not be spaces around the
+parentheses. Where a single-line form is not possible, each element of the tuple
+should be on its own block-indented line and there should be a trailing comma.
+
+```rust
+(a, b, c)
+
+let x = (
+    a_long_expr,
+    another_very_long_expr,
+);
+```
+
+
+### Tuple struct literals
+
+There should be no space between the identifier and the opening parenthesis.
+Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`.
+
+
+### Enum literals
+
+Follow the formatting rules for the various struct literals. Prefer using the
+name of the enum as a qualifying name, unless the enum is in the prelude. E.g.,
+
+```rust
+Foo::Bar(a, b)
+Foo::Baz {
+    field1,
+    field2: 1001,
+}
+Ok(an_expr)
+```
+
+
+### Array literals
+
+For simple array literals, avoid line breaking, no spaces around square
+brackets, contents of the array should be separated by commas and spaces. If
+using the repeating initialiser, there should be a space after the semicolon
+only. Apply the same rules if using the `vec!` or similar macros (always use
+square brackets here). Examples:
+
+```rust
+fn main() {
+    [1, 2, 3];
+    vec![a, b, c, d];
+    let a = [42; 10];
+}
+```
+
+If a line must be broken, prefer breaking only after the `;`, if possible.
+Otherwise, follow the rules below for function calls. In any case, the contents
+of the initialiser should be block indented and there should be line breaks
+after the opening bracket and before the closing bracket:
+
+```rust
+fn main() {
+    [
+        a_long_expression();
+        1234567890
+    ]
+    let x = [
+        an_expression,
+        another_expression,
+        a_third_expression,
+    ];
+}
+```
+
+
+### Array accesses, indexing, and slicing.
+
+No spaces around the square brackets, avoid breaking lines if possible, never
+break a line between the target expression and the opening bracket. If the
+indexing expression covers multiple lines, then it should be block indented and
+there should be newlines after the opening brackets and before the closing
+bracket. However, this should be avoided where possible.
+
+Examples:
+
+```rust
+fn main() {
+    foo[42];
+    &foo[..10];
+    bar[0..100];
+    foo[4 + 5 / bar];
+    a_long_target[
+        a_long_indexing_expression
+    ];
+}
+```
+
+### Unary operations
+
+Do not include a space between a unary op and its operand (i.e., `!x`, not
+`! x`). However, there must be a space after `&mut`. Avoid line-breaking
+between a unary operator and its operand.
+
+### Binary operations
+
+Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=`
+and other assignment operators such as `+=` or `*=`).
+
+For comparison operators, because for `T op U`, `&T op &U` is also implemented:
+if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general,
+within expressions, prefer dereferencing to taking references.
+
+Use parentheses liberally, do not necessarily elide them due to precedence.
+Tools should not automatically insert or remove parentheses. Do not use spaces
+to indicate precedence.
+
+If line-breaking, put the operator on a new line and block indent. Put each
+sub-expression on its own line. E.g.,
+
+```rust
+foo_bar
+    + bar
+    + baz
+    + qux
+    + whatever
+```
+
+Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
+than at other binary operators.
+
+### Control flow
+
+Do not include extraneous parentheses for `if` and `while` expressions.
+
+```rust
+if true {
+}
+```
+
+is better than
+
+```rust
+if (true) {
+}
+```
+
+Do include extraneous parentheses if it makes an arithmetic or logic expression
+easier to understand (`(x * 15) + (y * 20)` is fine)
+
+### Function calls
+
+Do not put a space between the function name, and the opening parenthesis.
+
+Do not put a space between an argument, and the comma which follows.
+
+Do put a space between an argument, and the comma which precedes it.
+
+Prefer not to break a line in the callee expression.
+
+#### Single-line calls
+
+Do not put a space between the function name and open paren, between the open
+paren and the first argument, or between the last argument and the close paren.
+
+Do not put a comma after the last argument.
+
+```rust
+foo(x, y, z)
+```
+
+#### Multi-line calls
+
+If the function call is not *small*, it would otherwise over-run the max width,
+or any argument or the callee is multi-line, then the call should be formatted
+across multiple lines. In this case, each argument should be on it's own block-
+indented line, there should be a newline after the opening parenthesis and
+before the closing parenthesis, and there should be a trailing comma. E.g.,
+
+```rust
+a_function_call(
+    arg1,
+    a_nested_call(a, b),
+)
+```
+
+
+### Method calls
+
+Follow the function rules for calling.
+
+Do not put any spaces around the `.`.
+
+```rust
+x.foo().bar().baz(x, y, z);
+```
+
+
+### Macro uses
+
+Macros which can be parsed like other constructs should be formatted like those
+constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
+function call (ignoring the `!`), therefore it should be formatted following the
+rules for function calls.
+
+#### Special case macros
+
+Macros which take a format string and where all other arguments are *small* may
+be formatted with arguments before and after the format string on a single line
+and the format string on its own line, rather than putting each argument on its
+own line. For example,
+
+```rust
+println!(
+    "Hello {} and {}",
+    name1, name2,
+);
+
+assert_eq!(
+    x, y,
+    "x and y were not equal, see {}",
+    reason,
+);
+```
+
+
+### Casts (`as`)
+
+Put spaces before and after `as`:
+
+```rust
+let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char;
+```
+
+
+### Chains of fields and method calls
+
+A chain is a sequence of field accesses and/or method calls. A chain may also
+include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`.
+
+Prefer formatting on one line if possible, and the chain is *small*. If
+formatting on multiple lines, each field access or method call in the chain
+should be on its own line with the line-break before the `.` and after any `?`.
+Each line should be block-indented. E.g.,
+
+```rust
+let foo = bar
+    .baz?
+    .qux();
+```
+
+If the length of the last line of the first element plus its indentation is
+less than or equal to the indentation of the second line (and there is space),
+then combine the first and second lines, e.g.,
+
+```rust
+x.baz?
+    .qux()
+
+let foo = x
+    .baz?
+    .qux();
+
+foo(
+    expr1,
+    expr2,
+).baz?
+    .qux();
+```
+
+#### Multi-line elements
+
+If any element in a chain is formatted across multiple lines, then that element
+and any later elements must be on their own line. Earlier elements may be kept
+on a single line. E.g.,
+
+```rust
+a.b.c()?.d
+    .foo(
+        an_expr,
+        another_expr,
+    )
+    .bar
+    .baz
+```
+
+Note there is block indent due to the chain and the function call in the above
+example.
+
+Prefer formatting the whole chain in multi-line style and each element on one
+line, rather than putting some elements on multiple lines and some on a single
+line, e.g.,
+
+```rust
+// Better
+self.pre_comment
+    .as_ref()
+    .map_or(false, |comment| comment.starts_with("//"))
+
+// Worse
+self.pre_comment.as_ref().map_or(
+    false,
+    |comment| comment.starts_with("//"),
+)
+```
+
+### Control flow expressions
+
+This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
+expressions.
+
+The keyword, any initial clauses, and the opening brace of the block should be
+on a single line. The usual rules for [block formatting](#blocks) should be
+applied to the block.
+
+If there is an `else` component, then the closing brace, `else`, any following
+clause, and the opening brace should all be on the same line. There should be a
+single space before and after the `else` keyword. For example:
+
+```rust
+if ... {
+    ...
+} else {
+    ...
+}
+
+if let ... {
+    ...
+} else if ... {
+    ...
+} else {
+    ...
+}
+```
+
+If the control line needs to be broken, then prefer to break before the `=` in
+`* let` expressions and before `in` in a `for` expression; the following line
+should be block indented. If the control line is broken for any reason, then the
+opening brace should be on its own line and not indented. Examples:
+
+```rust
+while let Some(foo)
+    = a_long_expression
+{
+    ...
+}
+
+for foo
+    in a_long_expression
+{
+    ...
+}
+
+if a_long_expression
+    && another_long_expression
+    || a_third_long_expression
+{
+    ...
+}
+```
+
+Where the initial clause is multi-lined and ends with one or more closing
+parentheses, square brackets, or braces, and there is nothing else on that line,
+and that line is not indented beyond the indent on the first line of the control
+flow expression, then the opening brace of the block should be put on the same
+line with a preceding space. For example:
+
+```rust
+if !self.config.file_lines().intersects(
+    &self.codemap.lookup_line_range(
+        stmt.span,
+    ),
+) {  // Opening brace on same line as initial clause.
+    ...
+}
+```
+
+
+#### Single line `if else`
+
+Formatters may place an `if else` or `if let else` on a single line if it occurs
+in expression context (i.e., is not a standalone statement), it contains a
+single `else` clause, and is *small*. For example:
+
+```rust
+let y = if x { 0 } else { 1 };
+
+// Examples that must be multi-line.
+let y = if something_very_long {
+    not_small
+} else {
+    also_not_small
+};
+
+if x {
+    0
+} else {
+    1
+}
+```
+
+
+### Match
+
+Prefer not to line-break inside the discriminant expression. There must always
+be a line break after the opening brace and before the closing brace. The match
+arms must be block indented once:
+
+```rust
+match foo {
+    // arms
+}
+
+let x = match foo.bar.baz() {
+    // arms
+};
+```
+
+Use a trailing comma for a match arm if and only if not using a block.
+
+Never start a match arm pattern with `|`, e.g.,
+
+```rust
+match foo {
+    // Don't do this.
+    | foo => bar,
+    // Or this.
+    | a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+}
+```
+
+Prefer
+
+
+```rust
+match foo {
+    foo => bar,
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+}
+```
+
+Avoid splitting the left-hand side (before the `=>`) of a match arm where
+possible. If the right-hand side of the match arm is kept on the same line,
+never use a block (unless the block is empty).
+
+If the right-hand side consists of multiple statements or has line comments or
+the start of the line cannot be fit on the same line as the left-hand side, use
+a block.
+
+The body of a block arm should be block indented once.
+
+Examples:
+
+```rust
+match foo {
+    foo => bar,
+    a_very_long_patten | another_pattern if an_expression() => {
+        no_room_for_this_expression()
+    }
+    foo => {
+        // A comment.
+        an_expression()
+    }
+    foo => {
+        let a = statement();
+        an_expression()
+    }
+    bar => {}
+    // Trailing comma on last item.
+    foo => bar,
+}
+```
+
+If the body is a single expression with no line comments and not a control flow
+expression, then it may be started on the same line as the right-hand side. If
+not, then it must be in a block. Example,
+
+```rust
+match foo {
+    // A combinable expression.
+    foo => a_function_call(another_call(
+        argument1,
+        argument2,
+    )),
+    // A non-combinable expression
+    bar => {
+        a_function_call(
+            another_call(
+                argument1,
+                argument2,
+            ),
+            another_argument,
+        )
+    }
+}
+```
+
+#### Line-breaking
+
+Where it is possible to use a block form on the right-hand side and avoid
+breaking the left-hand side, do that. E.g.
+
+```rust
+    // Assuming the following line does done fit in the max width
+    a_very_long_pattern | another_pattern => ALongStructName {
+        ...
+    },
+    // Prefer this
+    a_very_long_pattern | another_pattern => {
+        ALongStructName {
+            ...
+        }
+    }
+    // To splitting the pattern.
+```
+
+Never break after `=>` without using the block form of the body.
+
+If the left-hand side must be split and there is an `if` clause, break before
+the `if` and block indent. In this case, always use a block body and start the
+body on a new line:
+
+```rust
+    a_very_long_pattern | another_pattern
+        if expr =>
+    {
+        ...
+    }
+```
+
+If required to break the pattern, put each clause of the pattern on its own
+line with no additional indent, breaking before the `|`. If there is an `if`
+clause, then you must use the above form:
+
+```rust
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern
+        if expr =>
+    {
+        ...
+    }
+```
+
+If the pattern is multi-line, and the last line is less wide than the indent, do
+not put the `if` clause on a newline. E.g.,
+
+```rust
+    Token::Dimension {
+         value,
+         ref unit,
+         ..
+    } if num_context.is_ok(context.parsing_mode, value) => {
+        ...
+    }
+```
+
+If every clause in a pattern is *small*, but does not fit on one line, then the
+pattern may be formatted across multiple lines with as many clauses per line as
+possible. Again break before a `|`:
+
+```rust
+    foo | bar | baz
+    | qux => {
+        ...
+    }
+```
+
+We define a pattern clause to be *small* if it matches the following grammar:
+
+```
+[small, ntp]:
+    - single token
+    - `&[single-line, ntp]`
+
+[small]:
+    - `[small, ntp]`
+    - unary tuple constructor `([small, ntp])`
+    - `&[small]`
+```
+
+E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
+
+
+### Combinable expressions
+
+Where a function call has a single argument, and that argument is formatted
+across multiple-lines, the outer call may be formatted as if it were a single-
+line call. The same combining behaviour may be applied to any similar
+expressions which have multi-line, block-indented lists of sub-expressions
+delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
+
+```rust
+foo(bar(
+    an_expr,
+    another_expr,
+))
+
+let x = foo(Bar {
+    field: whatever,
+});
+
+foo(|param| {
+    action();
+    foo(param)
+})
+```
+
+Such behaviour should extend recursively, however, tools may choose to limit the
+depth of nesting.
+
+Only where the multi-line sub-expression is a closure with an explicit block,
+this combining behaviour may be used where there are other arguments, as long as
+all the arguments and the first line of the closure fit on the first line, the
+closure is the last argument, and there is only one closure argument:
+
+```rust
+foo(first_arg, x, |param| {
+    action();
+    foo(param)
+})
+```
+
+
+### Ranges
+
+Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`.
+
+When writing a range with both upper and lower bounds, if the line must be
+broken, break before the range operator and block indent the second line:
+
+```rust
+a_long_expression
+    ..another_long_expression
+```
+
+For the sake of indicating precedence, we recommend that if either bound is a
+compound expression, then use parentheses around it, e.g., `..(x + 1)`,
+`(x.f)..(x.f.len())`, or `0..(x - 10)`.
+
+
+### Hexadecimal literals
+
+Hexadecimal literals may use upper- or lower-case letters, but they must not be
+mixed within the same literal. Projects should use the same case for all
+literals, but we do not make a recommendation for either lower- or upper-case.
+Tools should have an option to convert mixed case literals to upper-case, and
+may have an option to convert all literals to either lower- or upper-case.
+
+
+## Patterns
+
+Patterns should be formatted like their corresponding expressions. See the
+section on `match` for additional formatting for patterns in match arms.
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
new file mode 100644
index 00000000000..2835975355f
--- /dev/null
+++ b/src/doc/style-guide/src/items.md
@@ -0,0 +1,565 @@
+## Items
+
+`extern crate` statements must be first in a file. They must be ordered
+alphabetically.
+
+`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
+must come before other items. We recommend that imports come before module
+declarations; if imports and modules are separated, then they should be ordered
+alphabetically. When sorting, `self` and `super` must come before any other
+names. Module declarations should not be moved if they are annotated with
+`#[macro_use]`, since that may be semantics changing.
+
+Tools should make the above ordering optional.
+
+
+### Function definitions
+
+In Rust, one finds functions by searching for `fn [function-name]`; It's
+important that you style your code so that it's very searchable in this way.
+
+The proper ordering and spacing is:
+
+```rust
+[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 {
+    ...
+}
+```
+
+Avoid comments within the signature itself.
+
+If the function signature does not fit on one line, then break after the opening
+parenthesis and before the closing parenthesis and put each argument on its own
+block-indented line. For example,
+
+```rust
+fn foo(
+    arg1: i32,
+    arg2: i32,
+) -> i32 {
+    ...
+}
+```
+
+Note the trailing comma on the last argument.
+
+
+### Tuples and tuple structs
+
+Write the type list as you would a parameter list to a function.
+
+Build a tuple or tuple struct as you would call a function.
+
+#### Single-line
+
+```rust
+struct Bar(Type1, Type2);
+
+let x = Bar(11, 22);
+let y = (11, 22, 33);
+```
+
+### Enums
+
+In the declaration, put each variant on its own line, block indented.
+
+Format each variant accordingly as either a struct, tuple struct, or identifier,
+which doesn't require special formatting (but without the `struct` keyword.
+
+```rust
+enum FooBar {
+    First(u32),
+    Second,
+    Error {
+        err: Box<Error>,
+        line: u32,
+    },
+}
+```
+
+If a struct variant is [*small*](index.html#small-items), it may be formatted on
+one line. In this case, do not use a trailing comma for the field list, but do
+put spaces around each brace:
+
+```rust
+enum FooBar {
+    Error { err: Box<Error>, line: u32 },
+}
+```
+
+In an enum with multiple struct variants, if any struct variant is written on
+multiple lines, then the multi-line formatting should be used for all struct
+variants. However, such a situation might be an indication that you should
+factor out the fields of the variant into their own struct.
+
+
+### Structs and Unions
+
+Struct names follow on the same line as the `struct` keyword, with the opening
+brace on the same line when it fits within the right margin. All struct fields
+are indented once and end with a trailing comma. The closing brace is not
+indented and appears on its own line.
+
+```rust
+struct Foo {
+    a: A,
+    b: B,
+}
+```
+
+If and only if the type of a field does not fit within the right margin, it is
+pulled down to its own line and indented again.
+
+```rust
+struct Foo {
+    a: A,
+    long_name:
+        LongType,
+}
+```
+
+Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g.,
+`struct Foo();` or `struct Foo {}`, these only exist to simplify code
+generation), but if you must use an empty struct, keep it on one line with no
+space between the braces: `struct Foo;` or `struct Foo {}`.
+
+The same guidelines are used for untagged union declarations.
+
+```rust
+union Foo {
+    a: A,
+    b: B,
+    long_name:
+        LongType,
+}
+```
+
+
+### Tuple structs
+
+Put the whole struct on one line if possible. Types in the parentheses should be
+separated by a comma and space with no trailing comma. No spaces around the
+parentheses or semi-colon:
+
+```rust
+pub struct Foo(String, u8);
+```
+
+Prefer unit structs to empty tuple structs (these only exist to simplify code
+generation), e.g., `struct Foo;` rather than `struct Foo();`.
+
+For more than a few fields, prefer a proper struct with named fields. Given
+this, a tuple struct should always fit on one line. If it does not, block format
+the fields with a field on each line and a trailing comma:
+
+```rust
+pub struct Foo(
+    String,
+    u8,
+);
+```
+
+
+### Traits
+
+Trait items should be block-indented. If there are no items, the trait may be
+formatted on a single line. Otherwise there should be line-breaks after the
+opening brace and before the closing brace:
+
+```rust
+trait Foo {}
+
+pub trait Bar {
+    ...
+}
+```
+
+If the trait has bounds, there should be a space after the colon but not before
+and before and after each `+`, e.g.,
+
+```rust
+trait Foo: Debug + Bar {}
+```
+
+Prefer not to line-break in the bounds if possible (consider using a `where`
+clause). Prefer to break between bounds than to break any individual bound. If
+you must break the bounds, put each bound (including the first) on its own
+block-indented line, break before the `+` and put the opening brace on its own
+line:
+
+```rust
+pub trait IndexRanges:
+    Index<Range<usize>, Output=Self>
+    + Index<RangeTo<usize>, Output=Self>
+    + Index<RangeFrom<usize>, Output=Self>
+    + Index<RangeFull, Output=Self>
+{
+    ...
+}
+```
+
+
+### Impls
+
+Impl items should be block indented. If there are no items, the impl may be
+formatted on a single line. Otherwise there should be line-breaks after the
+opening brace and before the closing brace:
+
+```rust
+impl Foo {}
+
+impl Bar for Foo {
+    ...
+}
+```
+
+Avoid line-breaking in the signature if possible. If a line break is required in
+a non-inherent impl, break immediately before `for`, block indent the concrete type
+and put the opening brace on its own line:
+
+```rust
+impl Bar
+    for Foo
+{
+    ...
+}
+```
+
+
+### Extern crate
+
+`extern crate foo;`
+
+Use spaces around keywords, no spaces around the semi-colon.
+
+
+### Modules
+
+```rust
+mod foo {
+}
+```
+
+```rust
+mod foo;
+```
+
+Use spaces around keywords and before the opening brace, no spaces around the
+semi-colon.
+
+### macro\_rules!
+
+Use `{}` for the full definition of the macro.
+
+```rust
+macro_rules! foo {
+}
+```
+
+
+### Generics
+
+Prefer to put a generics clause on one line. Break other parts of an item
+declaration rather than line-breaking a generics clause. If a generics clause is
+large enough to require line-breaking, you should prefer to use a `where` clause
+instead.
+
+Do not put spaces before or after `<` nor before `>`. Only put a space after `>`
+if it is followed by a word or opening brace, not an opening parenthesis. There
+should be a space after each comma and no trailing comma.
+
+```rust
+fn foo<T: Display, U: Debug>(x: Vec<T>, y: Vec<U>) ...
+
+impl<T: Display, U: Debug> SomeType<T, U> { ...
+```
+
+If the generics clause must be formatted across multiple lines, each parameter
+should have its own block-indented line, there should be newlines after the
+opening bracket and before the closing bracket, and the should be a trailing
+comma.
+
+```rust
+fn foo<
+    T: Display,
+    U: Debug,
+>(x: Vec<T>, y: Vec<U>) ...
+```
+
+If an associated type is bound in a generic type, then there should be spaces on
+either side of the `=`:
+
+```rust
+<T: Example<Item = u32>>
+```
+
+Prefer to use single-letter names for generic parameters.
+
+
+### `where` clauses
+
+These rules apply for `where` clauses on any item.
+
+A `where` clause may immediately follow a closing bracket of any kind.
+Otherwise, it must start a new line, with no indent. Each component of a `where`
+clause must be on its own line and be block indented. There should be a trailing
+comma, unless the clause is terminated with a semicolon. If the `where` clause
+is followed by a block (or assignment), the block should be started on a new
+line. Examples:
+
+```rust
+fn function<T, U>(args)
+where
+    T: Bound,
+    U: AnotherBound,
+{
+    body
+}
+
+fn foo<T>(
+    args
+) -> ReturnType
+where
+    T: Bound,
+{
+    body
+}
+
+fn foo<T, U>(
+    args,
+) where
+    T: Bound,
+    U: AnotherBound,
+{
+    body
+}
+
+fn foo<T, U>(
+    args
+) -> ReturnType
+where
+    T: Bound,
+    U: AnotherBound;  // Note, no trailing comma.
+
+// Note that where clauses on `type` aliases are not enforced and should not
+// be used.
+type Foo<T>
+where
+    T: Bound
+= Bar<T>;
+```
+
+If a `where` clause is very short, we recommend using an inline bound on the
+type parameter.
+
+
+If a component of a `where` clause is long, it may be broken before `+` and
+further block indented. Each bound should go on its own line. E.g.,
+
+```rust
+impl<T: ?Sized, Idx> IndexRanges<Idx> for T
+where
+    T: Index<Range<Idx>, Output = Self::Output>
+        + Index<RangeTo<Idx>, Output = Self::Output>
+        + Index<RangeFrom<Idx>, Output = Self::Output>
+        + Index<RangeInclusive<Idx>, Output = Self::Output>
+        + Index<RangeToInclusive<Idx>, Output = Self::Output> + Index<RangeFull>
+```
+
+#### Option - `where_single_line`
+
+`where_single_line` is `false` by default. If `true`, then a where clause with
+exactly one component may be formatted on a single line if the rest of the
+item's signature is also kept on one line. In this case, there is no need for a
+trailing comma and if followed by a block, no need for a newline before the
+block. E.g.,
+
+```rust
+// May be single-lined.
+fn foo<T>(args) -> ReturnType
+where T: Bound {
+    body
+}
+
+// Must be multi-lined.
+fn foo<T>(
+    args
+) -> ReturnType
+where
+    T: Bound,
+{
+    body
+}
+```
+
+
+### Type aliases
+
+Type aliases should generally be kept on one line. If necessary to break the
+line, do so after the `=`; the right-hand-side should be block indented:
+
+```rust
+pub type Foo = Bar<T>;
+
+// If multi-line is required
+type VeryLongType<T, U: SomeBound> =
+    AnEvenLongerType<T, U, Foo<T>>;
+```
+
+Where possible avoid `where` clauses and keep type constraints inline. Where
+that is not possible split the line before and after the `where` clause (and
+split the `where` clause as normal), e.g.,
+
+```rust
+type VeryLongType<T, U>
+where
+    T: U::AnAssociatedType,
+    U: SomeBound,
+= AnEvenLongerType<T, U, Foo<T>>;
+```
+
+
+### Associated types
+
+Associated types should follow the guidelines above for type aliases. Where an
+associated type has a bound, there should be a space after the colon but not
+before:
+
+```rust
+pub type Foo: Bar;
+```
+
+
+### extern items
+
+When writing extern items (such as `extern "C" fn`), always be explicit about
+the ABI. For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or
+`extern "C" { ... }`.
+
+
+### Imports (`use` statements)
+
+If an import can be formatted on one line, do so. There should be no spaces
+around braces.
+
+```rust
+use a::b::c;
+use a::b::d::*;
+use a::b::{foo, bar, baz};
+```
+
+
+#### Large list imports
+
+Prefer to use multiple imports rather than a multi-line import. However, tools
+should not split imports by default (they may offer this as an option).
+
+If an import does require multiple lines (either because a list of single names
+does not fit within the max width, or because of the rules for nested imports
+below), then break after the opening brace and before the closing brace, use a
+trailing comma, and block indent the names.
+
+
+```rust
+// Prefer
+foo::{long, list, of, imports};
+foo::{more, imports};
+
+// If necessary
+foo::{
+    long, list, of, imports, more,
+    imports,  // Note trailing comma
+};
+```
+
+
+#### Ordering of imports
+
+A *group* of imports is a set of imports on the same or sequential lines. One or
+more blank lines or other items (e.g., a function) separate groups of imports.
+
+Within a group of imports, imports must be sorted ascii-betically. Groups of
+imports must not be merged or re-ordered.
+
+
+E.g., input:
+
+```rust
+use d;
+use c;
+
+use b;
+use a;
+```
+
+output:
+
+```rust
+use c;
+use d;
+
+use a;
+use b;
+```
+
+Because of `macro_use`, attributes must also start a new group and prevent
+re-ordering.
+
+Note that tools which only have access to syntax (such as Rustfmt) cannot tell
+which imports are from an external crate or the std lib, etc.
+
+
+#### Ordering list import
+
+Names in a list import must be sorted ascii-betically, but with `self` and
+`super` first, and groups and glob imports last. This applies recursively. For
+example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
+`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
+
+
+#### Normalisation
+
+Tools must make the following normalisations:
+
+* `use a::self;` -> `use a;`
+* `use a::{};` -> (nothing)
+* `use a::{b};` -> `use a::b;`
+
+And must apply these recursively.
+
+Tools must not otherwise merge or un-merge import lists or adjust glob imports
+(without an explicit option).
+
+
+#### Nested imports
+
+If there are any nested imports in a list import, then use the multi-line form,
+even if the import fits on one line. Each nested import must be on its own line,
+but non-nested imports must be grouped on as few lines as possible.
+
+For example,
+
+```rust
+use a::b::{
+    x, y, z,
+    u::{...},
+    w::{...},
+};
+```
+
+
+#### Merging/un-merging imports
+
+An example:
+
+```rust
+// Un-merged
+use a::b;
+use a::c::d;
+
+// Merged
+use a::{b, c::d};
+```
+
+Tools must not merge or un-merge imports by default. They may offer merging or
+un-merging as an option.
diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md
new file mode 100644
index 00000000000..b02b3c0471f
--- /dev/null
+++ b/src/doc/style-guide/src/principles.md
@@ -0,0 +1,51 @@
+# Guiding principles and rationale
+
+When deciding on style guidelines, the style team tried to be guided by the
+following principles (in rough priority order):
+
+* readability
+    - scan-ability
+    - avoiding misleading formatting
+    - accessibility - readable and editable by users using the the widest
+      variety of hardware, including non-visual accessibility interfaces
+    - readability of code when quoted in rustc error messages
+
+* aesthetics
+    - sense of 'beauty'
+    - consistent with other languages/tools
+
+* specifics
+    - compatibility with version control practices - preserving diffs,
+      merge-friendliness, etc.
+    - preventing right-ward drift
+    - minimising vertical space
+
+* application
+    - ease of manual application
+    - ease of implementation (in Rustfmt, and in other tools/editors/code generators)
+    - internal consistency
+    - simplicity of formatting rules
+
+
+## Overarching guidelines
+
+Prefer block indent over visual indent. E.g.,
+
+```rust
+// Block indent
+a_function_call(
+    foo,
+    bar,
+);
+
+// Visual indent
+a_function_call(foo,
+                bar);
+```
+
+This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above
+example) and less rightward drift.
+
+Lists should have a trailing comma when followed by a newline, see the block
+indent example above. This choice makes moving code (e.g., by copy and paste)
+easier and makes smaller diffs.
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
new file mode 100644
index 00000000000..29b48bb1ee0
--- /dev/null
+++ b/src/doc/style-guide/src/statements.md
@@ -0,0 +1,150 @@
+### Let statements
+
+There should be spaces after the `:` and on both sides of the `=` (if they are
+present). No space before the semi-colon.
+
+```rust
+// A comment.
+let pattern: Type = expr;
+
+let pattern;
+let pattern: Type;
+let pattern = expr;
+```
+
+If possible the declaration should be formatted on a single line. If this is not
+possible, then try splitting after the `=`, if the declaration can fit on two
+lines. The expression should be block indented.
+
+```rust
+let pattern: Type =
+    expr;
+```
+
+If the first line does not fit on a single line, then split after the colon,
+using block indentation. If the type covers multiple lines, even after line-
+breaking after the `:`, then the first line may be placed on the same line as
+the `:`, subject to the [combining rules](https://github.com/rust-lang-nursery/fmt-rfcs/issues/61) (WIP).
+
+
+```rust
+let pattern:
+    Type =
+    expr;
+```
+
+e.g,
+
+```rust
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo<Bar> =
+    Foo { f, g };
+
+let (abcd,
+    defg):
+    Baz =
+{ ... }
+```
+
+If the expression covers multiple lines, if the first line of the expression
+fits in the remaining space, it stays on the same line as the `=`, the rest of the
+expression is not indented. If the first line does not fit, then it should start
+on the next lines, and should be block indented. If the expression is a block
+and the type or pattern cover multiple lines, then the opening brace should be
+on a new line and not indented (this provides separation for the interior of the
+block from the type), otherwise the opening brace follows the `=`.
+
+Examples:
+
+```rust
+let foo = Foo {
+    f: abcd,
+    g: qwer,
+};
+
+let foo =
+    ALongName {
+        f: abcd,
+        g: qwer,
+    };
+
+let foo: Type = {
+    an_expression();
+    ...
+};
+
+let foo:
+    ALongType =
+{
+    an_expression();
+    ...
+};
+
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo<Bar> = Foo {
+    f: blimblimblim,
+    g: blamblamblam,
+};
+
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo<Bar> = foo(
+    blimblimblim,
+    blamblamblam,
+);
+```
+
+
+### Macros in statement position
+
+A macro use in statement position should use parentheses or square brackets as
+delimiters and should be terminated with a semi-colon. There should be no spaces
+between the name, `!`, the delimiters, or the `;`.
+
+```rust
+// A comment.
+a_macro!(...);
+```
+
+
+### Expressions in statement position
+
+There should be no space between the expression and the semi-colon.
+
+```
+<expr>;
+```
+
+All expressions in statement position should be terminated with a semi-colon,
+unless they end with a block or are used as the value for a block.
+
+E.g.,
+
+```rust
+{
+    an_expression();
+    expr_as_value()
+}
+
+return foo();
+
+loop {
+    break;
+}
+```
+
+Use a semi-colon where an expression has void type, even if it could be
+propagated. E.g.,
+
+```rust
+fn foo() { ... }
+
+fn bar() {
+    foo();
+}
+```
diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md
new file mode 100644
index 00000000000..25861ddabb8
--- /dev/null
+++ b/src/doc/style-guide/src/types.md
@@ -0,0 +1,58 @@
+## Types and Bounds
+
+### Single line formatting
+
+* `[T]` no spaces
+* `[T; expr]`, e.g., `[u32; 42]`, `[Vec<Foo>; 10 * 2 + foo()]` (space after colon, no spaces around square brackets)
+* `*const T`, `*mut T` (no space after `*`, space before type)
+* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words)
+* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keyowrds and sigils, and after commas, no trailing commas, no spaces around brackets)
+* `!` should be treated like any other type name, `Name`
+* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple)
+* `<Baz<T> as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`)
+* `Foo::Bar<T, U, V>` (spaces after commas, no trailing comma, no spaces around angle brackets)
+* `T + T + T` (single spaces between types, and `+`).
+* `impl T + T + T` (single spaces between keyword, types, and `+`).
+
+Parentheses used in types should not be surrounded by whitespace, e.g., `(Foo)`
+
+
+### Line breaks
+
+Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer
+
+```rust
+Foo<
+    Bar,
+    Baz<Type1, Type2>,
+>
+```
+
+to
+
+```rust
+Foo<Bar, Baz<
+    Type1,
+    Type2,
+>>
+```
+
+`[T; expr]` may be broken after the `;` if necessary.
+
+Function types may be broken following the rules for function declarations.
+
+Generic types may be broken following the rules for generics.
+
+Types with `+` may be broken after any `+` using block indent and breaking before the `+`. When breaking such a type, all `+`s should be line broken, e.g.,
+
+```rust
+impl Clone
+    + Copy
+    + Debug
+
+Box<
+    Clone
+    + Copy
+    + Debug
+>
+```
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 661aed71298..894c7328b5f 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -218,55 +218,55 @@ pre.rust a,
 .sidebar h2 a,
 .sidebar h3 a,
 .mobile-topbar h2 a,
-h1.fqn a,
+h1 a,
 .search-results a,
 .module-item .stab,
 .import-item .stab,
 .result-name .primitive > i, .result-name .keyword > i,
-.content .method .where,
-.content .fn .where,
-.content .where.fmt-newline {
+.method .where,
+.fn .where,
+.where.fmt-newline {
 	color: var(--main-color);
 }
 
-.content span.enum, .content a.enum,
-.content span.struct, .content a.struct,
-.content span.union, .content a.union,
-.content span.primitive, .content a.primitive,
-.content span.type, .content a.type,
-.content span.foreigntype, .content a.foreigntype {
+span.enum, a.enum,
+span.struct, a.struct,
+span.union, a.union,
+span.primitive, a.primitive,
+span.type, a.type,
+span.foreigntype, a.foreigntype {
 	color: var(--type-link-color);
 }
 
-.content span.trait, .content a.trait,
-.content span.traitalias, .content a.traitalias {
+span.trait, a.trait,
+span.traitalias, a.traitalias {
 	color: var(--trait-link-color);
 }
 
-.content span.associatedtype, .content a.associatedtype,
-.content span.constant, .content a.constant,
-.content span.static, .content a.static {
+span.associatedtype, a.associatedtype,
+span.constant, a.constant,
+span.static, a.static {
 	color: var(--assoc-item-link-color);
 }
 
-.content span.fn, .content a.fn,
-.content .fnname,
-.content span.method, .content a.method,
-.content span.tymethod, .content a.tymethod {
+span.fn, a.fn,
+.fnname,
+span.method, a.method,
+span.tymethod, a.tymethod {
 	color: var(--function-link-color);
 }
 
-.content span.attr, .content a.attr,
-.content span.derive, .content a.derive,
-.content span.macro, .content a.macro {
+span.attr, a.attr,
+span.derive, a.derive,
+span.macro, a.macro {
 	color: var(--macro-link-color);
 }
 
-.content span.mod, .content a.mod, .block a.current.mod {
+span.mod, a.mod {
 	color: var(--mod-link-color);
 }
 
-.content span.keyword, .content a.keyword {
+span.keyword, a.keyword {
 	color: var(--keyword-link-color);
 }
 
@@ -563,8 +563,6 @@ h2.location a {
 .rustdoc .example-wrap {
 	display: flex;
 	position: relative;
-}
-.rustdoc .example-wrap {
 	margin-bottom: 10px;
 }
 /* For the last child of a div, the margin will be taken care of
@@ -685,9 +683,9 @@ pre, .rustdoc.source .example-wrap {
 }
 
 /* Shift "where ..." part of method or fn definition down a line */
-.content .method .where,
-.content .fn .where,
-.content .where.fmt-newline {
+.method .where,
+.fn .where,
+.where.fmt-newline {
 	display: block;
 	font-size: 0.875rem;
 }
@@ -718,7 +716,6 @@ nav.sub {
 .source nav.sub {
 	margin-left: 32px;
 }
-nav.sum { text-align: right; }
 nav.sub form { display: inline; }
 
 a {
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 0975d497cb2..fc7713b9885 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -56,7 +56,7 @@ input:focus + .slider {
 h1, h2, h3, h4 {
 	color: white;
 }
-h1.fqn  a {
+h1 a {
 	color: #fff;
 }
 h4 {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0180c0ead8d..dc5b8acdf53 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -451,7 +451,6 @@ function loadCss(cssFileName) {
                 const name = item[0];
                 const desc = item[1]; // can be null
 
-                let klass = shortty;
                 let path;
                 if (shortty === "mod") {
                     path = name + "/index.html";
@@ -459,13 +458,12 @@ function loadCss(cssFileName) {
                     path = shortty + "." + name + ".html";
                 }
                 const current_page = document.location.href.split("/").pop();
-                if (path === current_page) {
-                    klass += " current";
-                }
                 const link = document.createElement("a");
                 link.href = path;
                 link.title = desc;
-                link.className = klass;
+                if (path === current_page) {
+                    link.className = "current";
+                }
                 link.textContent = name;
                 const li = document.createElement("li");
                 li.appendChild(link);
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 14a38a760d2..2e651b53874 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,8 +1,9 @@
 //! Validates syntax inside Rust code blocks (\`\`\`rust).
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{
-    emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
-    LazyFallbackBundle,
+    emitter::Emitter,
+    translation::{to_fluent_args, Translate},
+    Applicability, Diagnostic, Handler, LazyFallbackBundle,
 };
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
@@ -193,7 +194,7 @@ impl Emitter for BufferEmitter {
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let mut buffer = self.buffer.borrow_mut();
 
-        let fluent_args = self.to_fluent_args(diag.args());
+        let fluent_args = to_fluent_args(diag.args());
         let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
 
         buffer.messages.push(format!("error from rustc: {}", translated_main_message));
diff --git a/src/test/rustdoc-gui/sidebar-links-color.goml b/src/test/rustdoc-gui/sidebar-links-color.goml
index 3f719c4c4dc..18a1a3fadea 100644
--- a/src/test/rustdoc-gui/sidebar-links-color.goml
+++ b/src/test/rustdoc-gui/sidebar-links-color.goml
@@ -13,72 +13,72 @@ reload:
 
 // Struct
 assert-css: (
-    ".sidebar a.struct:not(.current)",
+    ".sidebar .block.struct a:not(.current)",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.struct:not(.current)"
+move-cursor-to: ".sidebar .block.struct a:not(.current)"
 assert-css: (
-    ".sidebar a.struct:hover",
+    ".sidebar .block.struct a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Enum
 assert-css: (
-    ".sidebar a.enum",
+    ".sidebar .block.enum a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.enum"
+move-cursor-to: ".sidebar .block.enum a"
 assert-css: (
-    ".sidebar a.enum:hover",
+    ".sidebar .block.enum a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Union
 assert-css: (
-    ".sidebar a.union",
+    ".sidebar .block.union a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.union"
+move-cursor-to: ".sidebar .block.union a"
 assert-css: (
-    ".sidebar a.union:hover",
+    ".sidebar .block.union a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Trait
 assert-css: (
-    ".sidebar a.trait",
+    ".sidebar .block.trait a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.trait"
+move-cursor-to: ".sidebar .block.trait a"
 assert-css: (
-    ".sidebar a.trait:hover",
+    ".sidebar .block.trait a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Function
 assert-css: (
-    ".sidebar a.fn",
+    ".sidebar .block.fn a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.fn"
+move-cursor-to: ".sidebar .block.fn a"
 assert-css: (
-    ".sidebar a.fn:hover",
+    ".sidebar .block.fn a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Type definition
 assert-css: (
-    ".sidebar a.type",
+    ".sidebar .block.type a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.type"
+move-cursor-to: ".sidebar .block.type a"
 assert-css: (
-    ".sidebar a.type:hover",
+    ".sidebar .block.type a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // Keyword
 assert-css: (
-    ".sidebar a.keyword",
+    ".sidebar .block.keyword a",
     {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.keyword"
+move-cursor-to: ".sidebar .block.keyword a"
 assert-css: (
-    ".sidebar a.keyword:hover",
+    ".sidebar .block.keyword a:hover",
     {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 
@@ -88,72 +88,72 @@ reload:
 
 // Struct
 assert-css: (
-    ".sidebar a.struct:not(.current)",
+    ".sidebar .block.struct a:not(.current)",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.struct:not(.current)"
+move-cursor-to: ".sidebar .block.struct a:not(.current)"
 assert-css: (
-    ".sidebar a.struct:hover",
+    ".sidebar .block.struct a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Enum
 assert-css: (
-    ".sidebar a.enum",
+    ".sidebar .block.enum a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.enum"
+move-cursor-to: ".sidebar .block.enum a"
 assert-css: (
-    ".sidebar a.enum:hover",
+    ".sidebar .block.enum a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Union
 assert-css: (
-    ".sidebar a.union",
+    ".sidebar .block.union a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.union"
+move-cursor-to: ".sidebar .block.union a"
 assert-css: (
-    ".sidebar a.union:hover",
+    ".sidebar .block.union a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Trait
 assert-css: (
-    ".sidebar a.trait",
+    ".sidebar .block.trait a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.trait"
+move-cursor-to: ".sidebar .block.trait a"
 assert-css: (
-    ".sidebar a.trait:hover",
+    ".sidebar .block.trait a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Function
 assert-css: (
-    ".sidebar a.fn",
+    ".sidebar .block.fn a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.fn"
+move-cursor-to: ".sidebar .block.fn a"
 assert-css: (
-    ".sidebar a.fn:hover",
+    ".sidebar .block.fn a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Type definition
 assert-css: (
-    ".sidebar a.type",
+    ".sidebar .block.type a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.type"
+move-cursor-to: ".sidebar .block.type a"
 assert-css: (
-    ".sidebar a.type:hover",
+    ".sidebar .block.type a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 // Keyword
 assert-css: (
-    ".sidebar a.keyword",
+    ".sidebar .block.keyword a",
     {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.keyword"
+move-cursor-to: ".sidebar .block.keyword a"
 assert-css: (
-    ".sidebar a.keyword:hover",
+    ".sidebar .block.keyword a:hover",
     {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
 )
 
@@ -163,71 +163,71 @@ reload:
 
 // Struct
 assert-css: (
-    ".sidebar a.struct:not(.current)",
+    ".sidebar .block.struct a:not(.current)",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.struct:not(.current)"
+move-cursor-to: ".sidebar .block.struct a:not(.current)"
 assert-css: (
-    ".sidebar a.struct:hover",
+    ".sidebar .block.struct a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Enum
 assert-css: (
-    ".sidebar a.enum",
+    ".sidebar .block.enum a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.enum"
+move-cursor-to: ".sidebar .block.enum a"
 assert-css: (
-    ".sidebar a.enum:hover",
+    ".sidebar .block.enum a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Union
 assert-css: (
-    ".sidebar a.union",
+    ".sidebar .block.union a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.union"
+move-cursor-to: ".sidebar .block.union a"
 assert-css: (
-    ".sidebar a.union:hover",
+    ".sidebar .block.union a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Trait
 assert-css: (
-    ".sidebar a.trait",
+    ".sidebar .block.trait a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.trait"
+move-cursor-to: ".sidebar .block.trait a"
 assert-css: (
-    ".sidebar a.trait:hover",
+    ".sidebar .block.trait a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Function
 assert-css: (
-    ".sidebar a.fn",
+    ".sidebar .block.fn a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.fn"
+move-cursor-to: ".sidebar .block.fn a"
 assert-css: (
-    ".sidebar a.fn:hover",
+    ".sidebar .block.fn a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Type definition
 assert-css: (
-    ".sidebar a.type",
+    ".sidebar .block.type a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.type"
+move-cursor-to: ".sidebar .block.type a"
 assert-css: (
-    ".sidebar a.type:hover",
+    ".sidebar .block.type a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
 // Keyword
 assert-css: (
-    ".sidebar a.keyword",
+    ".sidebar .block.keyword a",
     {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
 )
-move-cursor-to: ".sidebar a.keyword"
+move-cursor-to: ".sidebar .block.keyword a"
 assert-css: (
-    ".sidebar a.keyword:hover",
+    ".sidebar .block.keyword a:hover",
     {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
 )
diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
index 01282f2ffeb..b5c1b6a4390 100644
--- a/src/test/rustdoc-gui/sidebar-macro-reexport.goml
+++ b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
@@ -1,5 +1,5 @@
 // This test ensures that the reexport of a macro doesn't make the original macro
 // displayed twice in the sidebar.
 goto: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html"
-wait-for: ".sidebar-elems .macro .macro"
+wait-for: ".sidebar-elems .block.macro a"
 assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
index 2319de55683..4b1e04234c8 100644
--- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
@@ -1,11 +1,12 @@
+// check-pass
 // normalize-stderr-test: "`.*`" -> "`DEF_ID`"
 // normalize-stdout-test: "`.*`" -> "`DEF_ID`"
 // edition:2018
 
 pub async fn f() -> impl std::fmt::Debug {
+    // rustdoc doesn't care that this is infinitely sized
     #[derive(Debug)]
     enum E {
-    //~^ ERROR recursive type `f::{closure#0}::E` has infinite size
         This(E),
         Unit,
     }
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
deleted file mode 100644
index e6ab67d59ce..00000000000
--- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0072]: recursive type `DEF_ID` has infinite size
-  --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
-   |
-LL |     enum E {
-   |     ^^^^^^
-LL |
-LL |         This(E),
-   |              - recursive without indirection
-   |
-help: insert some indirection (e.g., a `DEF_ID`) to break the cycle
-   |
-LL |         This(Box<E>),
-   |              ++++ +
-
-error: aborting due to previous error
-
-For more information about this error, try `DEF_ID`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
index b3a7ee56313..ac79582fb3f 100644
--- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
+++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs
@@ -1,6 +1,8 @@
+// check-pass
+
 fn f() -> impl Sized {
+    // rustdoc doesn't care that this is infinitely sized
     enum E {
-    //~^ ERROR recursive type `f::E` has infinite size
         V(E),
     }
     unimplemented!()
diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
deleted file mode 100644
index 165ff678372..00000000000
--- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0072]: recursive type `f::E` has infinite size
-  --> $DIR/infinite-recursive-type-impl-trait.rs:2:5
-   |
-LL |     enum E {
-   |     ^^^^^^
-LL |
-LL |         V(E),
-   |           - recursive without indirection
-   |
-help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
-   |
-LL |         V(Box<E>),
-   |           ++++ +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 65536cb3aa1..dbf3a8f00ee 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -1,8 +1,8 @@
     -Z                          allow-features=val -- only allow the listed language features to be enabled in code (space separated)
     -Z                       always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no)
-    -Z               assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
     -Z                            asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
     -Z                       assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
+    -Z               assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
     -Z                      binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
     -Z                             box-noalias=val -- emit noalias metadata for box (default: yes)
     -Z                       branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
@@ -17,6 +17,7 @@
     -Z                 deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes)
     -Z                  dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no)
     -Z                               dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no)
+    -Z                        diagnostic-width=val -- set the current output width for diagnostic truncation
     -Z                                 dlltool=val -- import library generation tool (windows-gnu only)
     -Z                 dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
     -Z                           drop-tracking=val -- enables drop tracking in generators (default: no)
@@ -54,11 +55,11 @@
     -Z                        incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
     -Z              incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
     -Z                  incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
+    -Z                      inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
     -Z                             inline-llvm=val -- enable LLVM inlining (default: yes)
     -Z                              inline-mir=val -- enable MIR inlining (default: no)
-    -Z                    inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
     -Z               inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
-    -Z                      inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
+    -Z                    inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
     -Z                             input-stats=val -- gather statistics about the input (default: no)
     -Z                     instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
@@ -67,6 +68,7 @@
         `=off` (default)
     -Z                       instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
     -Z                       keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
+    -Z                             layout-seed=val -- seed layout randomization
     -Z                   link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
     -Z                               link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
     -Z                            llvm-plugins=val -- a list LLVM plugins to enable (space separated)
@@ -78,8 +80,8 @@
     -Z                              meta-stats=val -- gather metadata statistics (default: no)
     -Z                          mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
     -Z                       mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual.
-    -Z        mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing
     -Z                           mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
+    -Z        mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing
     -Z                         move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
     -Z                         mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
     -Z                               nll-facts=val -- dump facts from NLL analysis into side files (default: no)
@@ -91,12 +93,11 @@
     -Z                           no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
     -Z                                 no-link=val -- compile without linking
     -Z                        no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
-    -Z                 no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
     -Z                     no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate
+    -Z                 no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
     -Z                          normalize-docs=val -- normalize associated items in rustdoc when generating documentation
     -Z                                     oom=val -- panic strategy for out-of-memory handling
     -Z                  osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no)
-    -Z                        diagnostic-width=val -- set the current output width for diagnostic truncation
     -Z                     packed-bundled-libs=val -- change rlib format to store native libraries as archives
     -Z                       panic-abort-tests=val -- support compiling tests with panic=abort (default: no)
     -Z                           panic-in-drop=val -- panic strategy for panics in drops
@@ -120,15 +121,13 @@
     -Z                                 profile=val -- insert profiling code (default: no)
     -Z                        profile-closures=val -- profile size of closures
     -Z                            profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path)
-    -Z                        profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
     -Z                      profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)
+    -Z                        profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
     -Z                         query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no)
     -Z                        randomize-layout=val -- randomize the layout of types (default: no)
-    -Z                             layout-seed=val -- seed layout randomization
     -Z                   relax-elf-relocations=val -- whether ELF relocations can be relaxed
     -Z                             relro-level=val -- choose which RELRO level to use
     -Z                        remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix
-    -Z         simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
     -Z                     report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
     -Z                               sanitizer=val -- use a sanitizer
     -Z          sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
@@ -136,22 +135,20 @@
     -Z                  saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes)
     -Z                           save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no)
     -Z                            self-profile=val -- run the self profiler and output the raw event data
-    -Z                     self-profile-events=val -- specify the events recorded by the self profiler;
-        for example: `-Z self-profile-events=default,query-keys`
-        all options: none, all, default, generic-activity, query-provider, query-cache-hit
-                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
     -Z                    self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of:
         `wall-time` (monotonic clock, i.e. `std::time::Instant`)
         `instructions:u` (retired instructions, userspace-only)
         `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
+    -Z                     self-profile-events=val -- specify the events recorded by the self profiler;
+        for example: `-Z self-profile-events=default,query-keys`
+        all options: none, all, default, generic-activity, query-provider, query-cache-hit
+                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
     -Z                          share-generics=val -- make the current crate share its generic instantiations
     -Z                               show-span=val -- show spans for compiler debugging (expr|pat|ty)
+    -Z         simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
     -Z                              span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span`
     -Z                       span-free-formats=val -- exclude spans when debug-printing compiler state (default: no)
-    -Z                      src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
-    -Z                         stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
-    -Z                      strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
-    -Z                                   strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
+    -Z                    split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
     -Z                        split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
         (default: `split`)
 
@@ -159,14 +156,13 @@
                  file which is ignored by the linker
         `single`: sections which do not require relocation are written into object file but ignored
                   by the linker
-    -Z                    split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
+    -Z                      src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
+    -Z                         stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
+    -Z                      strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
+    -Z                                   strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
     -Z                 symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
     -Z                                   teach=val -- show extended diagnostic help (default: no)
     -Z                               temps-dir=val -- the directory the intermediate files are written to
-    -Z                          translate-lang=val -- language identifier for diagnostic output
-    -Z                translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
-    -Z        translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
-    -Z                                tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
     -Z                                 thinlto=val -- enable ThinLTO when possible
     -Z                           thir-unsafeck=val -- use the THIR unsafety checker (default: no)
     -Z                                 threads=val -- use a thread pool with N threads
@@ -174,10 +170,14 @@
     -Z                             time-passes=val -- measure time of each rustc pass (default: no)
     -Z                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
+    -Z                translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
+    -Z        translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
+    -Z                          translate-lang=val -- language identifier for diagnostic output
     -Z   translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes)
     -Z                        trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)
     -Z                        treat-err-as-bug=val -- treat error number `val` that occurs as bug
     -Z                   trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items
+    -Z                                tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
     -Z                              ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no)
     -Z            uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16)
     -Z          unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no)
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
index 9a5100ce17f..462f5e78498 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
@@ -13,7 +13,7 @@ extern crate rustc_span;
 
 use rustc_errors::{
     AddToDiagnostic, IntoDiagnostic, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, Handler, fluent
+    ErrorGuaranteed, Handler, fluent, SubdiagnosticMessage,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
@@ -52,7 +52,10 @@ impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
 pub struct UntranslatableInAddToDiagnostic;
 
 impl AddToDiagnostic for UntranslatableInAddToDiagnostic {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         diag.note("untranslatable diagnostic");
         //~^ ERROR diagnostics should be created using translatable messages
     }
@@ -61,7 +64,10 @@ impl AddToDiagnostic for UntranslatableInAddToDiagnostic {
 pub struct TranslatableInAddToDiagnostic;
 
 impl AddToDiagnostic for TranslatableInAddToDiagnostic {
-    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
         diag.note(fluent::compiletest::note);
     }
 }
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
index f5f92ac1e7f..ac820a79db2 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:56:14
+  --> $DIR/diagnostics.rs:59:14
    |
 LL |         diag.note("untranslatable diagnostic");
    |              ^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:70:25
+  --> $DIR/diagnostics.rs:76:25
    |
 LL |     let _diag = handler.struct_err(fluent::compiletest::example);
    |                         ^^^^^^^^^^
@@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:73:25
+  --> $DIR/diagnostics.rs:79:25
    |
 LL |     let _diag = handler.struct_err("untranslatable diagnostic");
    |                         ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:73:25
+  --> $DIR/diagnostics.rs:79:25
    |
 LL |     let _diag = handler.struct_err("untranslatable diagnostic");
    |                         ^^^^^^^^^^
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 1dc71abc104..e873c36e0b3 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -678,3 +678,74 @@ enum ExampleEnum {
 struct RawIdentDiagnosticArg {
     pub r#type: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticBad {
+    #[subdiagnostic(bad)]
+//~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
+    note: Note,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticBadStr {
+    #[subdiagnostic = "bad"]
+//~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
+    note: Note,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticBadTwice {
+    #[subdiagnostic(bad, bad)]
+//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+    note: Note,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticBadLitStr {
+    #[subdiagnostic("bad")]
+//~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
+    note: Note,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticEagerLint {
+    #[subdiagnostic(eager)]
+//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+    note: Note,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticEagerCorrect {
+    #[subdiagnostic(eager)]
+    note: Note,
+}
+
+// Check that formatting of `correct` in suggestion doesn't move the binding for that field, making
+// the `set_arg` call a compile error; and that isn't worked around by moving the `set_arg` call
+// after the `span_suggestion` call - which breaks eager translation.
+
+#[derive(Subdiagnostic)]
+#[suggestion_short(
+    parser::use_instead,
+    applicability = "machine-applicable",
+    code = "{correct}"
+)]
+pub(crate) struct SubdiagnosticWithSuggestion {
+    #[primary_span]
+    span: Span,
+    invalid: String,
+    correct: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest::example)]
+struct SubdiagnosticEagerSuggestion {
+    #[subdiagnostic(eager)]
+    sub: SubdiagnosticWithSuggestion,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 167198b47f2..7a42d618707 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -533,6 +533,46 @@ LL | #[label]
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
+error: `#[subdiagnostic(bad)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:685:21
+   |
+LL |     #[subdiagnostic(bad)]
+   |                     ^^^
+   |
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+
+error: `#[subdiagnostic = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:693:5
+   |
+LL |     #[subdiagnostic = "bad"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:701:5
+   |
+LL |     #[subdiagnostic(bad, bad)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+
+error: `#[subdiagnostic("...")]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:709:21
+   |
+LL |     #[subdiagnostic("bad")]
+   |                     ^^^^^
+   |
+   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:717:5
+   |
+LL |     #[subdiagnostic(eager)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: eager subdiagnostics are not supported on lints
+
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:55:3
    |
@@ -607,7 +647,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 75 previous errors
+error: aborting due to 80 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-85103.rs b/src/test/ui/associated-types/issue-85103.rs
index c5e13856178..9c6a419e9f7 100644
--- a/src/test/ui/associated-types/issue-85103.rs
+++ b/src/test/ui/associated-types/issue-85103.rs
@@ -4,6 +4,6 @@ use std::borrow::Cow;
 
 #[rustc_layout(debug)]
 type Edges<'a, E> = Cow<'a, [E]>;
-//~^ ERROR layout error: NormalizationFailure
+//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
 
 fn main() {}
diff --git a/src/test/ui/associated-types/issue-85103.stderr b/src/test/ui/associated-types/issue-85103.stderr
index bddd1dce8e6..17f7148074c 100644
--- a/src/test/ui/associated-types/issue-85103.stderr
+++ b/src/test/ui/associated-types/issue-85103.stderr
@@ -1,4 +1,4 @@
-error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
+error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized
   --> $DIR/issue-85103.rs:6:1
    |
 LL | type Edges<'a, E> = Cow<'a, [E]>;
diff --git a/src/test/ui/consts/issue-102117.rs b/src/test/ui/consts/issue-102117.rs
new file mode 100644
index 00000000000..b77342c4135
--- /dev/null
+++ b/src/test/ui/consts/issue-102117.rs
@@ -0,0 +1,30 @@
+#![feature(inline_const, const_type_id)]
+
+use std::alloc::Layout;
+use std::any::TypeId;
+use std::mem::transmute;
+use std::ptr::drop_in_place;
+
+pub struct VTable {
+    layout: Layout,
+    type_id: TypeId,
+    drop_in_place: unsafe fn(*mut ()),
+}
+
+impl VTable {
+    pub fn new<T>() -> &'static Self {
+        const {
+          //~^ ERROR the parameter type `T` may not live long enough
+          //~| ERROR the parameter type `T` may not live long enough
+            &VTable {
+                layout: Layout::new::<T>(),
+                type_id: TypeId::of::<T>(),
+                drop_in_place: unsafe {
+                    transmute::<unsafe fn(*mut T), unsafe fn(*mut ())>(drop_in_place::<T>)
+                },
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-102117.stderr b/src/test/ui/consts/issue-102117.stderr
new file mode 100644
index 00000000000..eb4b329bd81
--- /dev/null
+++ b/src/test/ui/consts/issue-102117.stderr
@@ -0,0 +1,37 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-102117.rs:16:9
+   |
+LL | /         const {
+LL | |
+LL | |
+LL | |             &VTable {
+...  |
+LL | |             }
+LL | |         }
+   | |_________^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     pub fn new<T: 'static>() -> &'static Self {
+   |                 +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-102117.rs:16:9
+   |
+LL | /         const {
+LL | |
+LL | |
+LL | |             &VTable {
+...  |
+LL | |             }
+LL | |         }
+   | |_________^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     pub fn new<T: 'static>() -> &'static Self {
+   |                 +++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs
index 7287639c61d..54f7e9ac592 100644
--- a/src/test/ui/issues/issue-72554.rs
+++ b/src/test/ui/issues/issue-72554.rs
@@ -3,7 +3,6 @@ use std::collections::BTreeSet;
 #[derive(Hash)]
 pub enum ElemDerived {
     //~^ ERROR recursive type `ElemDerived` has infinite size
-    //~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
     A(ElemDerived)
 }
 
diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr
index bc85cd7b18d..d12be539f7c 100644
--- a/src/test/ui/issues/issue-72554.stderr
+++ b/src/test/ui/issues/issue-72554.stderr
@@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
    |
 LL | pub enum ElemDerived {
    | ^^^^^^^^^^^^^^^^^^^^
-...
+LL |
 LL |     A(ElemDerived)
    |       ----------- recursive without indirection
    |
@@ -12,20 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
 LL |     A(Box<ElemDerived>)
    |       ++++           +
 
-error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
-  --> $DIR/issue-72554.rs:4:1
-   |
-LL | pub enum ElemDerived {
-   | ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
-note: cycle used when computing drop-check constraints for `Elem`
-  --> $DIR/issue-72554.rs:11:1
-   |
-LL | pub enum Elem {
-   | ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0072, E0391.
-For more information about an error, try `rustc --explain E0072`.
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/parser/bad-let-as-field.rs b/src/test/ui/parser/bad-let-as-field.rs
new file mode 100644
index 00000000000..fec2bc25617
--- /dev/null
+++ b/src/test/ui/parser/bad-let-as-field.rs
@@ -0,0 +1,6 @@
+struct Foo {
+    let: i32,
+    //~^ ERROR expected identifier, found keyword
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/bad-let-as-field.stderr b/src/test/ui/parser/bad-let-as-field.stderr
new file mode 100644
index 00000000000..57def42b1ee
--- /dev/null
+++ b/src/test/ui/parser/bad-let-as-field.stderr
@@ -0,0 +1,15 @@
+error: expected identifier, found keyword `let`
+  --> $DIR/bad-let-as-field.rs:2:5
+   |
+LL | struct Foo {
+   |        --- while parsing this struct
+LL |     let: i32,
+   |     ^^^ expected identifier, found keyword
+   |
+help: escape `let` to use it as an identifier
+   |
+LL |     r#let: i32,
+   |     ++
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/removed-syntax-field-let-2.rs b/src/test/ui/parser/removed-syntax-field-let-2.rs
new file mode 100644
index 00000000000..7ff91b476ae
--- /dev/null
+++ b/src/test/ui/parser/removed-syntax-field-let-2.rs
@@ -0,0 +1,12 @@
+struct Foo {
+    let x: i32,
+    //~^ ERROR expected identifier, found keyword
+    let y: i32,
+    //~^ ERROR expected identifier, found keyword
+}
+
+fn main() {
+    let _ = Foo {
+        //~^ ERROR missing fields `x` and `y` in initializer of `Foo`
+    };
+}
diff --git a/src/test/ui/parser/removed-syntax-field-let-2.stderr b/src/test/ui/parser/removed-syntax-field-let-2.stderr
new file mode 100644
index 00000000000..fda0919b9b6
--- /dev/null
+++ b/src/test/ui/parser/removed-syntax-field-let-2.stderr
@@ -0,0 +1,33 @@
+error: expected identifier, found keyword `let`
+  --> $DIR/removed-syntax-field-let-2.rs:2:5
+   |
+LL |     let x: i32,
+   |     ^^^-
+   |     |
+   |     expected identifier, found keyword
+   |     help: remove this `let` keyword
+   |
+   = note: the `let` keyword is not allowed in `struct` fields
+   = note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
+
+error: expected identifier, found keyword `let`
+  --> $DIR/removed-syntax-field-let-2.rs:4:5
+   |
+LL |     let y: i32,
+   |     ^^^-
+   |     |
+   |     expected identifier, found keyword
+   |     help: remove this `let` keyword
+   |
+   = note: the `let` keyword is not allowed in `struct` fields
+   = note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
+
+error[E0063]: missing fields `x` and `y` in initializer of `Foo`
+  --> $DIR/removed-syntax-field-let-2.rs:9:13
+   |
+LL |     let _ = Foo {
+   |             ^^^ missing `x` and `y`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0063`.
diff --git a/src/test/ui/parser/removed-syntax-field-let.stderr b/src/test/ui/parser/removed-syntax-field-let.stderr
index bd1b23f7e3b..9bc18dabd6e 100644
--- a/src/test/ui/parser/removed-syntax-field-let.stderr
+++ b/src/test/ui/parser/removed-syntax-field-let.stderr
@@ -2,15 +2,13 @@ error: expected identifier, found keyword `let`
   --> $DIR/removed-syntax-field-let.rs:2:5
    |
 LL |     let foo: (),
-   |     ^^^ expected identifier, found keyword
+   |     ^^^-
+   |     |
+   |     expected identifier, found keyword
+   |     help: remove this `let` keyword
    |
    = note: the `let` keyword is not allowed in `struct` fields
    = note: see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information
-help: remove the let, the `let` keyword is not allowed in struct field definitions
-   |
-LL -     let foo: (),
-LL +     foo: (),
-   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index d0a938c03e8..6d4d2492225 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -5,7 +5,6 @@
 // ignore-sgx no libc
 // ignore-emscripten no processes
 // ignore-sgx no processes
-// ignore-android: FIXME(#85261)
 // ignore-fuchsia no fork
 
 #![feature(rustc_private)]
@@ -79,7 +78,49 @@ unsafe impl<A:GlobalAlloc> GlobalAlloc for PidChecking<A> {
 fn expect_aborted(status: ExitStatus) {
     dbg!(status);
     let signal = status.signal().expect("expected child process to die of signal");
+
+    #[cfg(not(target_os = "android"))]
     assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+
+    #[cfg(target_os = "android")]
+    {
+        // Android signals an abort() call with SIGSEGV at address 0xdeadbaad
+        // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
+        assert!(signal == libc::SIGSEGV);
+
+        // Additional checks performed:
+        // 1. Find last tombstone (similar to coredump but in text format) from the
+        //    same executable (path) as we are (must be because of usage of fork):
+        //    This ensures that we look into the correct tombstone.
+        // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
+        // 3. libc::abort call is in one of top two functions on callstack.
+        // The last two steps distinguish between a normal SIGSEGV and one caused
+        // by libc::abort.
+
+        let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
+        let exe_string = format!(">>> {this_exe} <<<");
+        let tombstone = (0..100)
+            .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
+            .filter(|f| std::path::Path::new(&f).exists())
+            .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
+            .filter(|f| f.contains(&exe_string))
+            .last()
+            .expect("no tombstone found");
+
+        println!("Content of tombstone:\n{tombstone}");
+
+        assert!(
+            tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad")
+        );
+        let abort_on_top = tombstone
+            .lines()
+            .skip_while(|l| !l.contains("backtrace:"))
+            .skip(1)
+            .take_while(|l| l.starts_with("    #"))
+            .take(2)
+            .any(|f| f.contains("/system/lib/libc.so (abort"));
+        assert!(abort_on_top);
+    }
 }
 
 fn main() {
diff --git a/src/test/ui/variance/variance-regions-unused-indirect.rs b/src/test/ui/variance/variance-regions-unused-indirect.rs
index 1514e39563e..6c2c24ddbc7 100644
--- a/src/test/ui/variance/variance-regions-unused-indirect.rs
+++ b/src/test/ui/variance/variance-regions-unused-indirect.rs
@@ -1,6 +1,7 @@
 // Test that disallow lifetime parameters that are unused.
 
 enum Foo<'a> { //~ ERROR parameter `'a` is never used
+    //~^ ERROR recursive types `Foo` and `Bar` have infinite size
     Foo1(Bar<'a>)
 }
 
diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr
index 93710cc133a..14fdd849294 100644
--- a/src/test/ui/variance/variance-regions-unused-indirect.stderr
+++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr
@@ -1,3 +1,26 @@
+error[E0072]: recursive types `Foo` and `Bar` have infinite size
+  --> $DIR/variance-regions-unused-indirect.rs:3:1
+   |
+LL | enum Foo<'a> {
+   | ^^^^^^^^^^^^
+LL |
+LL |     Foo1(Bar<'a>)
+   |          ------- recursive without indirection
+...
+LL | enum Bar<'a> {
+   | ^^^^^^^^^^^^
+LL |     Bar1(Foo<'a>)
+   |          ------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+   |
+LL ~     Foo1(Box<Bar<'a>>)
+LL | }
+LL | 
+LL | enum Bar<'a> {
+LL ~     Bar1(Box<Foo<'a>>)
+   |
+
 error[E0392]: parameter `'a` is never used
   --> $DIR/variance-regions-unused-indirect.rs:3:10
    |
@@ -7,13 +30,14 @@ LL | enum Foo<'a> {
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
 error[E0392]: parameter `'a` is never used
-  --> $DIR/variance-regions-unused-indirect.rs:7:10
+  --> $DIR/variance-regions-unused-indirect.rs:8:10
    |
 LL | enum Bar<'a> {
    |          ^^ unused parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0392`.
+Some errors have detailed explanations: E0072, E0392.
+For more information about an error, try `rustc --explain E0072`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 3cdf1ab25dc4fe56f890e8c7330d53a23ad905d
+Subproject b8f30cb23c4e5f20854a4f683325782b7cff983
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
new file mode 100644
index 00000000000..c9f1dfb707f
--- /dev/null
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -0,0 +1,113 @@
+//! Checks that a list of items is in alphabetical order
+//!
+//! To use, use the following annotation in the code:
+//! ```rust
+//! // tidy-alphabetical-start
+//! fn aaa() {}
+//! fn eee() {}
+//! fn z() {}
+//! // tidy-alphabetical-end
+//! ```
+//!
+//! The following lines are ignored:
+//! - Lines that are indented with more or less spaces than the first line
+//! - Lines starting with `//`, `#[`, `)`, `]`, `}` if the comment has the same indentation as
+//!   the first line
+//!
+//! If a line ends with an opening bracket, the line is ignored and the next line will have
+//! its extra indentation ignored.
+
+use std::{fmt::Display, path::Path};
+
+use crate::walk::{filter_dirs, walk};
+
+fn indentation(line: &str) -> usize {
+    line.find(|c| c != ' ').unwrap_or(0)
+}
+
+fn is_close_bracket(c: char) -> bool {
+    matches!(c, ')' | ']' | '}')
+}
+
+const START_COMMENT: &str = "// tidy-alphabetical-start";
+const END_COMMENT: &str = "// tidy-alphabetical-end";
+
+fn check_section<'a>(
+    file: impl Display,
+    lines: impl Iterator<Item = (usize, &'a str)>,
+    bad: &mut bool,
+) {
+    let content_lines = lines.take_while(|(_, line)| !line.contains(END_COMMENT));
+
+    let mut prev_line = String::new();
+    let mut first_indent = None;
+    let mut in_split_line = None;
+
+    for (line_idx, line) in content_lines {
+        if line.contains(START_COMMENT) {
+            tidy_error!(
+                bad,
+                "{file}:{} found `// tidy-alphabetical-start` expecting `// tidy-alphabetical-end`",
+                line_idx
+            )
+        }
+
+        let indent = first_indent.unwrap_or_else(|| {
+            let indent = indentation(line);
+            first_indent = Some(indent);
+            indent
+        });
+
+        let line = if let Some(prev_split_line) = in_split_line {
+            in_split_line = None;
+            format!("{prev_split_line}{}", line.trim_start())
+        } else {
+            line.to_string()
+        };
+
+        if indentation(&line) != indent {
+            continue;
+        }
+
+        let trimmed_line = line.trim_start_matches(' ');
+
+        if trimmed_line.starts_with("//")
+            || trimmed_line.starts_with("#[")
+            || trimmed_line.starts_with(is_close_bracket)
+        {
+            continue;
+        }
+
+        if line.trim_end().ends_with('(') {
+            in_split_line = Some(line);
+            continue;
+        }
+
+        let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ').to_lowercase();
+
+        if trimmed_line.to_lowercase() < prev_line_trimmed_lowercase {
+            tidy_error!(bad, "{file}:{}: line not in alphabetical order", line_idx + 1,);
+        }
+
+        prev_line = line;
+    }
+}
+
+pub fn check(path: &Path, bad: &mut bool) {
+    walk(path, &mut filter_dirs, &mut |entry, contents| {
+        let file = &entry.path().display();
+
+        let mut lines = contents.lines().enumerate().peekable();
+        while let Some((_, line)) = lines.next() {
+            if line.contains(START_COMMENT) {
+                check_section(file, &mut lines, bad);
+                if lines.peek().is_none() {
+                    tidy_error!(
+                        bad,
+                        "{file}: reached end of file expecting `// tidy-alphabetical-end`"
+                    )
+                }
+            }
+        }
+    });
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index e82cca402e2..fc0bce58572 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -38,6 +38,7 @@ macro_rules! tidy_error {
     });
 }
 
+pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
 pub mod deps;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index c1ce94f4705..8fe361c45a2 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -90,6 +90,8 @@ fn main() {
         check!(edition, &compiler_path);
         check!(edition, &library_path);
 
+        check!(alphabetical, &compiler_path);
+
         let collected = {
             while handles.len() >= concurrency.get() {
                 handles.pop_front().unwrap().join().unwrap();
diff --git a/triagebot.toml b/triagebot.toml
index d358e59c245..181fb1de930 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -189,6 +189,11 @@ trigger_files = [
     "src/tools/bump-stage0",
 ]
 
+[autolabel."T-style"]
+trigger_files = [
+    "src/doc/style-guide",
+]
+
 [autolabel."A-translation"]
 trigger_files = [
     "compiler/rustc_error_messages",