about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/rustdoc.md54
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs12
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs206
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs20
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs40
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs38
-rw-r--r--compiler/rustc_codegen_gcc/messages.ftl16
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs26
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs123
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs52
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl10
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs279
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl24
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs55
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs103
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs284
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs22
-rw-r--r--compiler/rustc_const_eval/src/errors.rs4
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0722.md8
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs21
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs1
-rw-r--r--compiler/rustc_infer/src/infer/canonical/instantiate.rs189
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_lint/src/expect.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map.rs16
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs10
-rw-r--r--compiler/rustc_middle/src/ty/context.rs43
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs8
-rw-r--r--compiler/rustc_session/messages.ftl8
-rw-r--r--compiler/rustc_session/src/errors.rs17
-rw-r--r--compiler/rustc_session/src/features.rs59
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs8
-rw-r--r--compiler/rustc_target/src/target_features.rs45
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs6
-rw-r--r--library/Cargo.lock10
-rw-r--r--library/alloc/src/collections/linked_list/tests.rs18
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs38
-rw-r--r--library/alloc/src/string.rs1
-rw-r--r--library/alloctests/testing/macros.rs37
-rw-r--r--library/alloctests/testing/mod.rs1
-rw-r--r--library/alloctests/tests/fmt.rs46
-rw-r--r--library/alloctests/tests/num.rs4
-rw-r--r--library/alloctests/tests/testing/mod.rs2
-rw-r--r--library/alloctests/tests/vec.rs119
-rw-r--r--library/alloctests/tests/vec_deque.rs119
-rw-r--r--library/core/src/fmt/num.rs199
-rw-r--r--library/core/src/fmt/rt.rs38
-rw-r--r--library/coretests/tests/atomic.rs30
-rw-r--r--library/coretests/tests/fmt/mod.rs15
-rw-r--r--library/std/src/os/unix/mod.rs3
-rw-r--r--library/std/src/os/unix/process.rs35
-rw-r--r--library/std/src/sys/pal/unix/linux/pidfd.rs6
-rw-r--r--library/std/src/sys/process/unix/fuchsia.rs5
-rw-r--r--library/std/src/sys/process/unix/unix.rs12
-rw-r--r--library/std/src/sys/process/unix/unsupported.rs6
-rw-r--r--library/std/src/sys/process/unix/vxworks.rs8
-rw-r--r--src/bootstrap/build.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs17
-rw-r--r--src/bootstrap/src/core/builder/tests.rs53
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/utils/helpers.rs5
-rw-r--r--src/bootstrap/src/utils/tests/mod.rs71
m---------src/doc/book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md25
-rw-r--r--src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md12
-rw-r--r--src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md2
-rw-r--r--src/doc/rustc-dev-guide/src/building/new-target.md4
-rw-r--r--src/doc/rustc-dev-guide/src/contributing.md2
-rw-r--r--src/doc/rustc-dev-guide/src/diagnostics.md2
-rw-r--r--src/doc/rustc-dev-guide/src/hir.md2
-rw-r--r--src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md63
-rw-r--r--src/doc/rustc-dev-guide/src/hir/debugging.md (renamed from src/doc/rustc-dev-guide/src/hir-debugging.md)0
-rw-r--r--src/doc/rustc-dev-guide/src/hir/lowering.md (renamed from src/doc/rustc-dev-guide/src/ast-lowering.md)2
-rw-r--r--src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md2
-rw-r--r--src/doc/rustc-dev-guide/src/offload/installation.md71
-rw-r--r--src/doc/rustc-dev-guide/src/offload/internals.md9
-rw-r--r--src/doc/rustc-dev-guide/src/overview.md2
-rw-r--r--src/doc/rustc-dev-guide/src/part-5-intro.md2
-rw-r--r--src/doc/rustc-dev-guide/src/pat-exhaustive-checking.md2
-rw-r--r--src/doc/rustc-dev-guide/src/profile-guided-optimization.md16
-rw-r--r--src/doc/rustc-dev-guide/src/profiling/with_perf.md4
-rw-r--r--src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md22
-rw-r--r--src/doc/rustc-dev-guide/src/query.md96
-rw-r--r--src/doc/rustc-dev-guide/src/sanitizers.md2
-rw-r--r--src/doc/rustc-dev-guide/src/ty.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/min-function-alignment.md2
-rw-r--r--src/librustdoc/clean/types.rs118
-rw-r--r--src/librustdoc/clean/utils.rs4
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/json/mod.rs5
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs4
-rw-r--r--src/tools/clippy/Cargo.toml1
-rw-r--r--src/tools/clippy/src/driver.rs35
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout39
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout35
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr23
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/assembly/s390x-backchain-toggle.rs5
-rw-r--r--tests/codegen/target-feature-negative-implication.rs20
-rw-r--r--tests/codegen/target-feature-overrides.rs5
-rw-r--r--tests/codegen/tied-features-strength.rs15
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff159
-rw-r--r--tests/ui/attributes/malformed-fn-align.rs5
-rw-r--r--tests/ui/attributes/malformed-fn-align.stderr49
-rw-r--r--tests/ui/borrowck/clone-on-ref.stderr4
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs16
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr31
-rw-r--r--tests/ui/check-cfg/target_feature.stderr4
-rw-r--r--tests/ui/consts/recursive-const-in-impl.stderr5
-rw-r--r--tests/ui/feature-gates/feature-gate-fn_align.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-optimize_attribute.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-optimize_attribute.stderr13
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.stderr2
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.stderr10
-rw-r--r--tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr2
-rw-r--r--tests/ui/macros/format-args-temporaries-in-write.stderr10
-rw-r--r--tests/ui/sized/unsized-binding.rs4
-rw-r--r--tests/ui/suggestions/issue-97760.stderr4
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr10
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs2
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr2
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr2
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr2
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.rs6
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stdout6
-rw-r--r--tests/ui/unpretty/flattened-format-args.stdout6
146 files changed, 2010 insertions, 1807 deletions
diff --git a/.github/ISSUE_TEMPLATE/rustdoc.md b/.github/ISSUE_TEMPLATE/rustdoc.md
new file mode 100644
index 00000000000..130d5f67102
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/rustdoc.md
@@ -0,0 +1,54 @@
+---
+name: Problem with rustdoc
+about: Report an issue with how docs get generated.
+labels: C-bug, T-rustdoc
+---
+<!--
+Thank you for filing a rustdoc issue! Rustdoc is the tool that handles the generation of docs.  It is usually invoked via `cargo doc`, but can also be used directly.
+
+If you have an issue with the actual content of the docs, use the "Documentation problem" template instead.
+-->
+
+# Code
+<!-- problematic snippet and/or link to repo and/or full path of standard library function -->
+
+```rust
+<code>
+```
+
+# Reproduction Steps
+<!--
+* command(s) to run, if any
+* permalink to hosted documentation, if any
+* search query, if any
+-->
+
+# Expected Outcome
+<!--
+What did you want to happen?
+
+For GUI issues, feel free to provide a mockup image of what you want it to look like.
+
+For diagnostics, please provide a mockup of the desired output in a code block.
+-->
+
+# Actual Output
+<!--
+* rustdoc console output
+* browser screenshot of generated html
+* rustdoc json (prettify by running through `jq` or running thorugh an online formatter)
+-->
+```console
+<code>
+```
+
+
+# Version
+<!--
+Available via `rustdoc --version` or under the "Help" menu.
+
+If the issue involves opening the documentation in a browser, please also provide the name and version of the browser used.
+-->
+
+# Additional Details
+<!-- Anything else you think is relevant -->
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 718edad0cc6..f297bf9f4cf 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2289,12 +2289,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         span: Span,
         elements: &'hir [hir::Expr<'hir>],
     ) -> hir::Expr<'hir> {
-        let addrof = hir::ExprKind::AddrOf(
-            hir::BorrowKind::Ref,
-            hir::Mutability::Not,
-            self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
-        );
-        self.expr(span, addrof)
+        let array = self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements)));
+        self.expr_ref(span, array)
+    }
+
+    pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
+        self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr))
     }
 
     pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 17b443b8ecc..12f0af75486 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -1,7 +1,5 @@
-use core::ops::ControlFlow;
 use std::borrow::Cow;
 
-use rustc_ast::visit::Visitor;
 use rustc_ast::*;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
@@ -476,77 +474,52 @@ fn expand_format_args<'hir>(
         return hir::ExprKind::Call(new, new_args);
     }
 
-    // If the args array contains exactly all the original arguments once,
-    // in order, we can use a simple array instead of a `match` construction.
-    // However, if there's a yield point in any argument except the first one,
-    // we don't do this, because an Argument cannot be kept across yield points.
-    //
-    // This is an optimization, speeding up compilation about 1-2% in some cases.
-    // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
-    let use_simple_array = argmap.len() == arguments.len()
-        && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j)
-        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
-
-    let args = if arguments.is_empty() {
+    let (let_statements, args) = if arguments.is_empty() {
         // Generate:
-        //    &<core::fmt::Argument>::none()
+        //     []
+        (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[]))))
+    } else if argmap.len() == 1 && arguments.len() == 1 {
+        // Only one argument, so we don't need to make the `args` tuple.
         //
-        // Note:
-        //     `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime.
-        //
-        //     This makes sure that this still fails to compile, even when the argument is inlined:
-        //
-        //     ```
-        //     let f = format_args!("{}", "a");
-        //     println!("{f}"); // error E0716
-        //     ```
-        //
-        //     Cases where keeping the object around is allowed, such as `format_args!("a")`,
-        //     are handled above by the `allow_const` case.
-        let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
-            macsp,
-            hir::LangItem::FormatArgument,
-            sym::none,
-        ));
-        let none = ctx.expr_call(macsp, none_fn, &[]);
-        ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none))
-    } else if use_simple_array {
         // Generate:
-        //     &[
-        //         <core::fmt::Argument>::new_display(&arg0),
-        //         <core::fmt::Argument>::new_lower_hex(&arg1),
-        //         <core::fmt::Argument>::new_debug(&arg2),
-        //         …
-        //     ]
-        let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map(
-            |(arg, ((_, ty), placeholder_span))| {
+        //     super let args = [<core::fmt::Argument>::new_display(&arg)];
+        let args = ctx.arena.alloc_from_iter(argmap.iter().map(
+            |(&(arg_index, ty), &placeholder_span)| {
+                let arg = &arguments[arg_index];
                 let placeholder_span =
                     placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
-                let arg_span = match arg.kind {
-                    FormatArgumentKind::Captured(_) => placeholder_span,
-                    _ => arg.expr.span.with_ctxt(macsp.ctxt()),
-                };
                 let arg = ctx.lower_expr(&arg.expr);
-                let ref_arg = ctx.arena.alloc(ctx.expr(
-                    arg_span,
-                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
-                ));
+                let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg));
                 make_argument(ctx, placeholder_span, ref_arg, ty)
             },
         ));
-        ctx.expr_array_ref(macsp, elements)
+        let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
+        let args_ident = Ident::new(sym::args, macsp);
+        let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
+        let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
+        (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)))
     } else {
         // Generate:
-        //     &match (&arg0, &arg1, &…) {
-        //         args => [
-        //             <core::fmt::Argument>::new_display(args.0),
-        //             <core::fmt::Argument>::new_lower_hex(args.1),
-        //             <core::fmt::Argument>::new_debug(args.0),
-        //             …
-        //         ]
-        //     }
+        //     super let args = (&arg0, &arg1, &…);
         let args_ident = Ident::new(sym::args, macsp);
         let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
+        let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
+            let arg_expr = ctx.lower_expr(&arg.expr);
+            ctx.expr(
+                arg.expr.span.with_ctxt(macsp.ctxt()),
+                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
+            )
+        }));
+        let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
+        let let_statement_1 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args_tuple));
+
+        // Generate:
+        //     super let args = [
+        //         <core::fmt::Argument>::new_display(args.0),
+        //         <core::fmt::Argument>::new_lower_hex(args.1),
+        //         <core::fmt::Argument>::new_debug(args.0),
+        //         …
+        //     ];
         let args = ctx.arena.alloc_from_iter(argmap.iter().map(
             |(&(arg_index, ty), &placeholder_span)| {
                 let arg = &arguments[arg_index];
@@ -567,58 +540,47 @@ fn expand_format_args<'hir>(
                 make_argument(ctx, placeholder_span, arg, ty)
             },
         ));
-        let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
-            let arg_expr = ctx.lower_expr(&arg.expr);
-            ctx.expr(
-                arg.expr.span.with_ctxt(macsp.ctxt()),
-                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
-            )
-        }));
-        let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
-        let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
-        let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
-        let match_expr = ctx.arena.alloc(ctx.expr_match(
-            macsp,
-            args_tuple,
-            match_arms,
-            hir::MatchSource::FormatArgs,
-        ));
-        ctx.expr(
-            macsp,
-            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
+        let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
+        let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
+        let let_statement_2 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
+        (
+            vec![let_statement_1, let_statement_2],
+            ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)),
         )
     };
 
-    if let Some(format_options) = format_options {
+    // Generate:
+    //     &args
+    let args = ctx.expr_ref(macsp, args);
+
+    let call = if let Some(format_options) = format_options {
         // Generate:
-        //     <core::fmt::Arguments>::new_v1_formatted(
-        //         lit_pieces,
-        //         args,
-        //         format_options,
-        //         unsafe { ::core::fmt::UnsafeArg::new() }
-        //     )
+        //     unsafe {
+        //         <core::fmt::Arguments>::new_v1_formatted(
+        //             lit_pieces,
+        //             args,
+        //             format_options,
+        //         )
+        //     }
         let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
             macsp,
             hir::LangItem::FormatArguments,
             sym::new_v1_formatted,
         ));
-        let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
-            macsp,
-            hir::LangItem::FormatUnsafeArg,
-            sym::new,
-        ));
-        let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
+        let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options]);
+        let call = ctx.expr_call(macsp, new_v1_formatted, args);
         let hir_id = ctx.next_id();
-        let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
-            stmts: &[],
-            expr: Some(unsafe_arg_new_call),
-            hir_id,
-            rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
-            span: macsp,
-            targeted_by_break: false,
-        }));
-        let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
-        hir::ExprKind::Call(new_v1_formatted, args)
+        hir::ExprKind::Block(
+            ctx.arena.alloc(hir::Block {
+                stmts: &[],
+                expr: Some(call),
+                hir_id,
+                rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
+                span: macsp,
+                targeted_by_break: false,
+            }),
+            None,
+        )
     } else {
         // Generate:
         //     <core::fmt::Arguments>::new_v1(
@@ -632,35 +594,21 @@ fn expand_format_args<'hir>(
         ));
         let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
         hir::ExprKind::Call(new_v1, new_args)
-    }
-}
-
-fn may_contain_yield_point(e: &ast::Expr) -> bool {
-    struct MayContainYieldPoint;
-
-    impl Visitor<'_> for MayContainYieldPoint {
-        type Result = ControlFlow<()>;
-
-        fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
-            if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
-                ControlFlow::Break(())
-            } else {
-                visit::walk_expr(self, e)
-            }
-        }
-
-        fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
-            // Macros should be expanded at this point.
-            unreachable!("unexpanded macro in ast lowering");
-        }
+    };
 
-        fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
-            // Do not recurse into nested items.
-            ControlFlow::Continue(())
-        }
+    if !let_statements.is_empty() {
+        // Generate:
+        //     {
+        //         super let …
+        //         super let …
+        //         <core::fmt::Arguments>::new_…(…)
+        //     }
+        let call = ctx.arena.alloc(ctx.expr(macsp, call));
+        let block = ctx.block_all(macsp, ctx.arena.alloc_from_iter(let_statements), Some(call));
+        hir::ExprKind::Block(block, None)
+    } else {
+        call
     }
-
-    MayContainYieldPoint.visit_expr(e).is_break()
 }
 
 fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e74fd1db15b..26d7c0cd6d3 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2292,6 +2292,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
     }
 
+    fn stmt_super_let_pat(
+        &mut self,
+        span: Span,
+        pat: &'hir hir::Pat<'hir>,
+        init: Option<&'hir hir::Expr<'hir>>,
+    ) -> hir::Stmt<'hir> {
+        let hir_id = self.next_id();
+        let local = hir::LetStmt {
+            super_: Some(span),
+            hir_id,
+            init,
+            pat,
+            els: None,
+            source: hir::LocalSource::Normal,
+            span: self.lower_span(span),
+            ty: None,
+        };
+        self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
+    }
+
     fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
         self.block_all(expr.span, &[], Some(expr))
     }
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index cdc01dc6c91..65061059a02 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -38,7 +38,8 @@ pub enum InstructionSetAttr {
     ArmT32,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic, Default)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum OptimizeAttr {
     /// No `#[optimize(..)]` attribute
     #[default]
@@ -229,7 +230,8 @@ pub enum AttributeKind {
 
     /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
-
+    /// Represents `#[optimize(size|speed)]`
+    Optimize(OptimizeAttr, Span),
     /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr(ThinVec<(ReprAttr, Span)>),
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
new file mode 100644
index 00000000000..ddcf82cbf7c
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -0,0 +1,40 @@
+use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::sym;
+
+use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct OptimizeParser;
+
+impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
+    const PATH: &[rustc_span::Symbol] = &[sym::optimize];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let Some(list) = args.list() else {
+            cx.expected_list(cx.attr_span);
+            return None;
+        };
+
+        let Some(single) = list.single() else {
+            cx.expected_single_argument(list.span);
+            return None;
+        };
+
+        let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
+            Some(sym::size) => OptimizeAttr::Size,
+            Some(sym::speed) => OptimizeAttr::Speed,
+            Some(sym::none) => OptimizeAttr::DoNotOptimize,
+            _ => {
+                cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]);
+                OptimizeAttr::Default
+            }
+        };
+
+        Some(AttributeKind::Optimize(res, cx.attr_span))
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index fa2a6087506..3bb4c163d32 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -28,6 +28,7 @@ use crate::session_diagnostics::UnusedMultiple;
 
 pub(crate) mod allow_unstable;
 pub(crate) mod cfg;
+pub(crate) mod codegen_attrs;
 pub(crate) mod confusables;
 pub(crate) mod deprecation;
 pub(crate) mod inline;
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index c9f9f34bdb7..eb16c3f95f0 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -273,7 +273,7 @@ pub(crate) struct AlignParser(Option<(Align, Span)>);
 
 impl AlignParser {
     const PATH: &'static [Symbol] = &[sym::align];
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "<alignment in bytes>");
+    const TEMPLATE: AttributeTemplate = template!(List: "<alignment in bytes>");
 
     fn parse<'c, S: Stage>(
         &mut self,
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index d7570634c1f..1708fd72e58 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -15,6 +15,7 @@ use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
 use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
+use crate::attributes::codegen_attrs::OptimizeParser;
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -108,6 +109,7 @@ attribute_parsers!(
         Single<ConstStabilityIndirectParser>,
         Single<DeprecationParser>,
         Single<InlineParser>,
+        Single<OptimizeParser>,
         Single<RustcForceInlineParser>,
         Single<TransparencyParser>,
         // tidy-alphabetical-end
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 34d36849939..98dc898db23 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3201,14 +3201,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         let expr_ty: Option<Ty<'_>> =
                             visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
 
-                        let is_format_arguments_item = if let Some(expr_ty) = expr_ty
-                            && let ty::Adt(adt, _) = expr_ty.kind()
-                        {
-                            self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments)
-                        } else {
-                            false
-                        };
-
                         if visitor.found == 0
                             && stmt.span.contains(proper_span)
                             && let Some(p) = sm.span_to_margin(stmt.span)
@@ -3236,25 +3228,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                 ""
                             };
 
-                            if !is_format_arguments_item {
-                                let addition = format!(
-                                    "let {}binding = {};\n{}",
-                                    mutability,
-                                    s,
-                                    " ".repeat(p)
-                                );
-                                err.multipart_suggestion_verbose(
-                                    msg,
-                                    vec![
-                                        (stmt.span.shrink_to_lo(), addition),
-                                        (proper_span, "binding".to_string()),
-                                    ],
-                                    Applicability::MaybeIncorrect,
-                                );
-                            } else {
-                                err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used");
-                                err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
-                            }
+                            let addition =
+                                format!("let {}binding = {};\n{}", mutability, s, " ".repeat(p));
+                            err.multipart_suggestion_verbose(
+                                msg,
+                                vec![
+                                    (stmt.span.shrink_to_lo(), addition),
+                                    (proper_span, "binding".to_string()),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+
                             suggested = true;
                             break;
                         }
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 18a8a5a1e04..55a28bc9493 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -1,7 +1,3 @@
-codegen_gcc_unknown_ctarget_feature_prefix =
-    unknown feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = features must begin with a `+` to enable or `-` to disable it
-
 codegen_gcc_unwinding_inline_asm =
     GCC backend does not support unwinding from inline asm
 
@@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
 codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
 
 codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
-
-codegen_gcc_unknown_ctarget_feature =
-    unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
-    .possible_feature = you might have meant: `{$rust_feature}`
-    .consider_filing_feature_request = consider filing a feature request
-
-codegen_gcc_missing_features =
-    add the missing features in a `target_feature` attribute
-
-codegen_gcc_target_feature_disable_or_enable =
-    the target features {$features} must all be either enabled or disabled together
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index 7786be9ae5d..b7e7343460f 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -1,31 +1,7 @@
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
-#[note]
-pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
-    pub feature: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_unknown_ctarget_feature)]
-#[note]
-pub(crate) struct UnknownCTargetFeature<'a> {
-    pub feature: &'a str,
-    #[subdiagnostic]
-    pub rust_feature: PossibleFeature<'a>,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum PossibleFeature<'a> {
-    #[help(codegen_gcc_possible_feature)]
-    Some { rust_feature: &'a str },
-    #[help(codegen_gcc_consider_filing_feature_request)]
-    None,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
     #[primary_span]
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 2e00d5fcb61..42ba40692b7 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -1,20 +1,12 @@
 #[cfg(feature = "master")]
 use gccjit::Context;
-use rustc_codegen_ssa::codegen_attrs::check_tied_features;
-use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::unord::UnordSet;
+use rustc_codegen_ssa::target_features;
 use rustc_session::Session;
-use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
-use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
 use smallvec::{SmallVec, smallvec};
 
-use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
-
-fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
-    let mut features: Vec<&str> = Vec::new();
-    retpoline_features_by_flags(sess, &mut features);
-    features
+fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    target_features::retpoline_features_by_flags(sess, features);
+    // FIXME: LLVM also sets +reserve-x18 here under some conditions.
 }
 
 /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -44,98 +36,29 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
 
     // -Ctarget-features
-    let known_features = sess.target.rust_target_features();
-    let mut featsmap = FxHashMap::default();
-
-    // Compute implied features
-    let mut all_rust_features = vec![];
-    for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
-        if let Some(feature) = feature.strip_prefix('+') {
-            all_rust_features.extend(
-                UnordSet::from(sess.target.implied_target_features(feature))
-                    .to_sorted_stable_ord()
-                    .iter()
-                    .map(|&&s| (true, s)),
-            )
-        } else if let Some(feature) = feature.strip_prefix('-') {
-            // FIXME: Why do we not remove implied features on "-" here?
-            // We do the equivalent above in `target_config`.
-            // See <https://github.com/rust-lang/rust/issues/134792>.
-            all_rust_features.push((false, feature));
-        } else if !feature.is_empty() && diagnostics {
-            sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
-        }
-    }
-    // Remove features that are meant for rustc, not codegen.
-    all_rust_features.retain(|&(_, feature)| {
-        // Retain if it is not a rustc feature
-        !RUSTC_SPECIFIC_FEATURES.contains(&feature)
-    });
-
-    // Check feature validity.
-    if diagnostics {
-        for &(enable, feature) in &all_rust_features {
-            let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
-            match feature_state {
-                None => {
-                    let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
-                        let gcc_features = to_gcc_features(sess, rust_feature);
-                        if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
-                        {
-                            Some(rust_feature)
-                        } else {
-                            None
-                        }
-                    });
-                    let unknown_feature = if let Some(rust_feature) = rust_feature {
-                        UnknownCTargetFeature {
-                            feature,
-                            rust_feature: PossibleFeature::Some { rust_feature },
-                        }
-                    } else {
-                        UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                    };
-                    sess.dcx().emit_warn(unknown_feature);
-                }
-                Some(&(_, stability, _)) => {
-                    stability.verify_feature_enabled_by_flag(sess, enable, feature);
-                }
-            }
-
-            // FIXME(nagisa): figure out how to not allocate a full hashset here.
-            featsmap.insert(feature, enable);
-        }
-    }
-
-    // Translate this into GCC features.
-    let feats =
-        all_rust_features.iter().flat_map(|&(enable, feature)| {
-            let enable_disable = if enable { '+' } else { '-' };
+    target_features::flag_to_backend_features(
+        sess,
+        diagnostics,
+        |feature| to_gcc_features(sess, feature),
+        |feature, enable| {
             // We run through `to_gcc_features` when
             // passing requests down to GCC. This means that all in-language
             // features also work on the command line instead of having two
             // different names when the GCC name and the Rust name differ.
-            to_gcc_features(sess, feature)
-                .iter()
-                .flat_map(|feat| to_gcc_features(sess, feat).into_iter())
-                .map(|feature| {
-                    if enable_disable == '-' {
-                        format!("-{}", feature)
-                    } else {
-                        feature.to_string()
-                    }
-                })
-                .collect::<Vec<_>>()
-        });
-    features.extend(feats);
-
-    if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.dcx().emit_err(TargetFeatureDisableOrEnable {
-            features: f,
-            span: None,
-            missing_features: None,
-        });
-    }
+            features.extend(
+                to_gcc_features(sess, feature)
+                    .iter()
+                    .flat_map(|feat| to_gcc_features(sess, feat).into_iter())
+                    .map(
+                        |feature| {
+                            if !enable { format!("-{}", feature) } else { feature.to_string() }
+                        },
+                    ),
+            );
+        },
+    );
+
+    gcc_features_by_flags(sess, &mut features);
 
     features
 }
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index aa57655921d..a912678ef2a 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -102,6 +102,7 @@ use rustc_codegen_ssa::back::write::{
     CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
 };
 use rustc_codegen_ssa::base::codegen_crate;
+use rustc_codegen_ssa::target_features::cfg_target_feature;
 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
 use rustc_data_structures::fx::FxIndexMap;
@@ -476,42 +477,21 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
 
 /// Returns the features that should be set in `cfg(target_feature)`.
 fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
-    // TODO(antoyo): use global_gcc_features.
-    let f = |allow_unstable| {
-        sess.target
-            .rust_target_features()
-            .iter()
-            .filter_map(|&(feature, gate, _)| {
-                if allow_unstable
-                    || (gate.in_cfg()
-                        && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
-                {
-                    Some(feature)
-                } else {
-                    None
-                }
-            })
-            .filter(|feature| {
-                // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
-                if *feature == "neon" {
-                    return false;
-                }
-                target_info.cpu_supports(feature)
-                // cSpell:disable
-                /*
-                  adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
-                  avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
-                  bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
-                  sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
-                */
-                // cSpell:enable
-            })
-            .map(Symbol::intern)
-            .collect()
-    };
-
-    let target_features = f(false);
-    let unstable_target_features = f(true);
+    let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
+        // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
+        if feature == "neon" {
+            return false;
+        }
+        target_info.cpu_supports(feature)
+        // cSpell:disable
+        /*
+          adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
+          avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
+          bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
+          sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
+        */
+        // cSpell:enable
+    });
 
     let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16);
     let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128);
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 3faeb9b3b22..3885f18271f 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined =
 codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
 codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
 
-codegen_llvm_unknown_ctarget_feature =
-    unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
-    .possible_feature = you might have meant: `{$rust_feature}`
-    .consider_filing_feature_request = consider filing a feature request
-
-codegen_llvm_unknown_ctarget_feature_prefix =
-    unknown feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = features must begin with a `+` to enable or `-` to disable it
-
 codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
 
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 8bc74fbec7e..d50ad8a1a9c 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -3,36 +3,12 @@ use std::path::Path;
 
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 use crate::fluent_generated as fluent;
 
 #[derive(Diagnostic)]
-#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
-#[note]
-pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
-    pub feature: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_unknown_ctarget_feature)]
-#[note]
-pub(crate) struct UnknownCTargetFeature<'a> {
-    pub feature: &'a str,
-    #[subdiagnostic]
-    pub rust_feature: PossibleFeature<'a>,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum PossibleFeature<'a> {
-    #[help(codegen_llvm_possible_feature)]
-    Some { rust_feature: &'a str },
-    #[help(codegen_llvm_consider_filing_feature_request)]
-    None,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_llvm_symbol_already_defined)]
 pub(crate) struct SymbolAlreadyDefined<'a> {
     #[primary_span]
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 0e77bc43df8..6fd07d562af 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -6,27 +6,20 @@ use std::sync::Once;
 use std::{ptr, slice, str};
 
 use libc::c_int;
-use rustc_codegen_ssa::TargetConfig;
 use rustc_codegen_ssa::base::wants_wasm_eh;
-use rustc_codegen_ssa::codegen_attrs::check_tied_features;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_codegen_ssa::target_features::cfg_target_feature;
+use rustc_codegen_ssa::{TargetConfig, target_features};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_data_structures::unord::UnordSet;
 use rustc_fs_util::path_to_c_string;
 use rustc_middle::bug;
 use rustc_session::Session;
 use rustc_session::config::{PrintKind, PrintRequest};
-use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
-use rustc_span::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
-use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
 use smallvec::{SmallVec, smallvec};
 
 use crate::back::write::create_informational_target_machine;
-use crate::errors::{
-    FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
-};
-use crate::llvm;
+use crate::{errors, llvm};
 
 static INIT: Once = Once::new();
 
@@ -195,15 +188,6 @@ impl<'a> LLVMFeature<'a> {
     ) -> Self {
         Self { llvm_feature_name, dependencies }
     }
-
-    fn contains(&'a self, feat: &str) -> bool {
-        self.iter().any(|dep| dep == feat)
-    }
-
-    fn iter(&'a self) -> impl Iterator<Item = &'a str> {
-        let dependencies = self.dependencies.iter().map(|feat| feat.as_str());
-        std::iter::once(self.llvm_feature_name).chain(dependencies)
-    }
 }
 
 impl<'a> IntoIterator for LLVMFeature<'a> {
@@ -216,18 +200,22 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
     }
 }
 
-// WARNING: the features after applying `to_llvm_features` must be known
-// to LLVM or the feature detection code will walk past the end of the feature
-// array, leading to crashes.
-//
-// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
-// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
-//
-// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/.
-// The commit in use can be found via the `llvm-project` submodule in
-// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with
-// an external precompiled version of LLVM which might lead to failures if the oldest tested /
-// supported LLVM version doesn't yet support the relevant intrinsics.
+/// Convert a Rust feature name to an LLVM feature name. Returning `None` means the
+/// feature should be skipped, usually because it is not supported by the current
+/// LLVM version.
+///
+/// WARNING: the features after applying `to_llvm_features` must be known
+/// to LLVM or the feature detection code will walk past the end of the feature
+/// array, leading to crashes.
+///
+/// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
+/// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
+///
+/// Check the current rustc fork of LLVM in the repo at
+/// <https://github.com/rust-lang/llvm-project/>. The commit in use can be found via the
+/// `llvm-project` submodule in <https://github.com/rust-lang/rust/tree/master/src> Though note that
+/// Rust can also be build with an external precompiled version of LLVM which might lead to failures
+/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics.
 pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFeature<'a>> {
     let arch = if sess.target.arch == "x86_64" {
         "x86"
@@ -343,98 +331,25 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
     // the target CPU, that is still expanded to target features (with all their implied features)
     // by LLVM.
     let target_machine = create_informational_target_machine(sess, true);
-    // Compute which of the known target features are enabled in the 'base' target machine. We only
-    // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
-    let mut features: FxHashSet<Symbol> = sess
-        .target
-        .rust_target_features()
-        .iter()
-        .filter(|(feature, _, _)| {
-            // skip checking special features, as LLVM may not understand them
-            if RUSTC_SPECIAL_FEATURES.contains(feature) {
-                return true;
-            }
-            if let Some(feat) = to_llvm_features(sess, feature) {
-                for llvm_feature in feat {
-                    let cstr = SmallCStr::new(llvm_feature);
-                    // `LLVMRustHasFeature` is moderately expensive. On targets with many
-                    // features (e.g. x86) these calls take a non-trivial fraction of runtime
-                    // when compiling very small programs.
-                    if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
-                        return false;
-                    }
+
+    let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
+        if let Some(feat) = to_llvm_features(sess, feature) {
+            // All the LLVM features this expands to must be enabled.
+            for llvm_feature in feat {
+                let cstr = SmallCStr::new(llvm_feature);
+                // `LLVMRustHasFeature` is moderately expensive. On targets with many
+                // features (e.g. x86) these calls take a non-trivial fraction of runtime
+                // when compiling very small programs.
+                if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
+                    return false;
                 }
-                true
-            } else {
-                false
             }
-        })
-        .map(|(feature, _, _)| Symbol::intern(feature))
-        .collect();
-
-    // Add enabled and remove disabled features.
-    for (enabled, feature) in
-        sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
-            Some('+') => Some((true, Symbol::intern(&s[1..]))),
-            Some('-') => Some((false, Symbol::intern(&s[1..]))),
-            _ => None,
-        })
-    {
-        if enabled {
-            // Also add all transitively implied features.
-
-            // We don't care about the order in `features` since the only thing we use it for is the
-            // `features.contains` below.
-            #[allow(rustc::potential_query_instability)]
-            features.extend(
-                sess.target
-                    .implied_target_features(feature.as_str())
-                    .iter()
-                    .map(|s| Symbol::intern(s)),
-            );
+            true
         } else {
-            // Remove transitively reverse-implied features.
-
-            // We don't care about the order in `features` since the only thing we use it for is the
-            // `features.contains` below.
-            #[allow(rustc::potential_query_instability)]
-            features.retain(|f| {
-                if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
-                    // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
-                    // remove `f`. (This is the standard logical contraposition principle.)
-                    false
-                } else {
-                    // We can keep `f`.
-                    true
-                }
-            });
+            false
         }
-    }
-
-    // Filter enabled features based on feature gates.
-    let f = |allow_unstable| {
-        sess.target
-            .rust_target_features()
-            .iter()
-            .filter_map(|(feature, gate, _)| {
-                // The `allow_unstable` set is used by rustc internally to determined which target
-                // features are truly available, so we want to return even perma-unstable
-                // "forbidden" features.
-                if allow_unstable
-                    || (gate.in_cfg()
-                        && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
-                {
-                    Some(Symbol::intern(feature))
-                } else {
-                    None
-                }
-            })
-            .filter(|feature| features.contains(&feature))
-            .collect()
-    };
+    });
 
-    let target_features = f(false);
-    let unstable_target_features = f(true);
     let mut cfg = TargetConfig {
         target_features,
         unstable_target_features,
@@ -707,10 +622,18 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
     handle_native(cpu_name)
 }
 
-fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
-    let mut features: Vec<&str> = Vec::new();
-    retpoline_features_by_flags(sess, &mut features);
-    features
+/// The target features for compiler flags other than `-Ctarget-features`.
+fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    target_features::retpoline_features_by_flags(sess, features);
+
+    // -Zfixed-x18
+    if sess.opts.unstable_opts.fixed_x18 {
+        if sess.target.arch != "aarch64" {
+            sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch });
+        } else {
+            features.push("+reserve-x18".into());
+        }
+    }
 }
 
 /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -777,6 +700,8 @@ pub(crate) fn global_llvm_features(
             .split(',')
             .filter(|v| !v.is_empty())
             // Drop +v8plus feature introduced in LLVM 20.
+            // (Hard-coded target features do not go through `to_llvm_feature` since they already
+            // are LLVM feature names, hence we need a special case here.)
             .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
             .map(String::from),
     );
@@ -787,86 +712,23 @@ pub(crate) fn global_llvm_features(
 
     // -Ctarget-features
     if !only_base_features {
-        let known_features = sess.target.rust_target_features();
-        // Will only be filled when `diagnostics` is set!
-        let mut featsmap = FxHashMap::default();
-
-        // Compute implied features
-        let mut all_rust_features = vec![];
-        for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
-            if let Some(feature) = feature.strip_prefix('+') {
-                all_rust_features.extend(
-                    UnordSet::from(sess.target.implied_target_features(feature))
-                        .to_sorted_stable_ord()
-                        .iter()
-                        .map(|&&s| (true, s)),
-                )
-            } else if let Some(feature) = feature.strip_prefix('-') {
-                // FIXME: Why do we not remove implied features on "-" here?
-                // We do the equivalent above in `target_config`.
-                // See <https://github.com/rust-lang/rust/issues/134792>.
-                all_rust_features.push((false, feature));
-            } else if !feature.is_empty() {
-                if diagnostics {
-                    sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
-                }
-            }
-        }
-        // Remove features that are meant for rustc, not LLVM.
-        all_rust_features.retain(|(_, feature)| {
-            // Retain if it is not a rustc feature
-            !RUSTC_SPECIFIC_FEATURES.contains(feature)
-        });
-
-        // Check feature validity.
-        if diagnostics {
-            for &(enable, feature) in &all_rust_features {
-                let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
-                match feature_state {
-                    None => {
-                        let rust_feature =
-                            known_features.iter().find_map(|&(rust_feature, _, _)| {
-                                let llvm_features = to_llvm_features(sess, rust_feature)?;
-                                if llvm_features.contains(feature)
-                                    && !llvm_features.contains(rust_feature)
-                                {
-                                    Some(rust_feature)
-                                } else {
-                                    None
-                                }
-                            });
-                        let unknown_feature = if let Some(rust_feature) = rust_feature {
-                            UnknownCTargetFeature {
-                                feature,
-                                rust_feature: PossibleFeature::Some { rust_feature },
-                            }
-                        } else {
-                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                        };
-                        sess.dcx().emit_warn(unknown_feature);
-                    }
-                    Some((_, stability, _)) => {
-                        stability.verify_feature_enabled_by_flag(sess, enable, feature);
-                    }
-                }
-
-                // FIXME(nagisa): figure out how to not allocate a full hashset here.
-                featsmap.insert(feature, enable);
-            }
-        }
-
-        // Translate this into LLVM features.
-        let feats = all_rust_features
-            .iter()
-            .filter_map(|&(enable, feature)| {
+        target_features::flag_to_backend_features(
+            sess,
+            diagnostics,
+            |feature| {
+                to_llvm_features(sess, feature)
+                    .map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter()))
+                    .unwrap_or_default()
+            },
+            |feature, enable| {
                 let enable_disable = if enable { '+' } else { '-' };
                 // We run through `to_llvm_features` when
                 // passing requests down to LLVM. This means that all in-language
                 // features also work on the command line instead of having two
                 // different names when the LLVM name and the Rust name differ.
-                let llvm_feature = to_llvm_features(sess, feature)?;
+                let Some(llvm_feature) = to_llvm_features(sess, feature) else { return };
 
-                Some(
+                features.extend(
                     std::iter::once(format!(
                         "{}{}",
                         enable_disable, llvm_feature.llvm_feature_name
@@ -881,27 +743,12 @@ pub(crate) fn global_llvm_features(
                         },
                     )),
                 )
-            })
-            .flatten();
-        features.extend(feats);
-
-        if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-            sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable {
-                features: f,
-                span: None,
-                missing_features: None,
-            });
-        }
+            },
+        );
     }
 
-    // -Zfixed-x18
-    if sess.opts.unstable_opts.fixed_x18 {
-        if sess.target.arch != "aarch64" {
-            sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch });
-        } else {
-            features.push("+reserve-x18".into());
-        }
-    }
+    // We add this in the "base target" so that these show up in `sess.unstable_target_features`.
+    llvm_features_by_flags(sess, &mut features);
 
     features
 }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 5322fe58cf3..2bd8644e0d7 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file =
 
 codegen_ssa_expected_name_value_pair = expected name value pair
 
-codegen_ssa_expected_one_argument = expected one argument
-
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -68,6 +66,11 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
 
 codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
 
+codegen_ssa_forbidden_ctarget_feature =
+    target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
+    .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+codegen_ssa_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
+
 codegen_ssa_forbidden_target_feature_attr =
     target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
 
@@ -86,9 +89,6 @@ codegen_ssa_incorrect_cgu_reuse_type =
 
 codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
 
-codegen_ssa_invalid_argument = invalid argument
-    .help = valid inline arguments are `always` and `never`
-
 codegen_ssa_invalid_instruction_set = invalid instruction set specified
 
 codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
@@ -368,8 +368,22 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name
 codegen_ssa_unknown_archive_kind =
     Don't know how to build archive of type: {$kind}
 
+codegen_ssa_unknown_ctarget_feature =
+    unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
+    .possible_feature = you might have meant: `{$rust_feature}`
+    .consider_filing_feature_request = consider filing a feature request
+
+codegen_ssa_unknown_ctarget_feature_prefix =
+    unknown feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = features must begin with a `+` to enable or `-` to disable it
+
 codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
 
+codegen_ssa_unstable_ctarget_feature =
+    unstable feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = this feature is not stably supported; its behavior can change in the future
+
 codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
 
 codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 98742255063..e855f1d3558 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -6,7 +6,6 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
 use rustc_attr_data_structures::{
     AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
 };
-use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -18,13 +17,15 @@ use rustc_middle::mir::mono::Linkage;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_session::lint;
 use rustc_session::parse::feature_err;
-use rustc_session::{Session, lint};
 use rustc_span::{Ident, Span, sym};
 use rustc_target::spec::SanitizerSet;
 
 use crate::errors;
-use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
+use crate::target_features::{
+    check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
+};
 
 fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
     use rustc_middle::mir::mono::Linkage::*;
@@ -455,33 +456,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         codegen_fn_attrs.inline = InlineAttr::Never;
     }
 
-    codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| {
-        if !attr.has_name(sym::optimize) {
-            return ia;
-        }
-        if attr.is_word() {
-            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
-            return ia;
-        }
-        let Some(ref items) = attr.meta_item_list() else {
-            return OptimizeAttr::Default;
-        };
-
-        let [item] = &items[..] else {
-            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
-            return OptimizeAttr::Default;
-        };
-        if item.has_name(sym::size) {
-            OptimizeAttr::Size
-        } else if item.has_name(sym::speed) {
-            OptimizeAttr::Speed
-        } else if item.has_name(sym::none) {
-            OptimizeAttr::DoNotOptimize
-        } else {
-            tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() });
-            OptimizeAttr::Default
-        }
-    });
+    codegen_fn_attrs.optimize =
+        find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default);
 
     // #73631: closures inherit `#[target_feature]` annotations
     //
@@ -615,25 +591,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     codegen_fn_attrs
 }
 
-/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
-/// combinations are allowed.
-pub fn check_tied_features(
-    sess: &Session,
-    features: &FxHashMap<&str, bool>,
-) -> Option<&'static [&'static str]> {
-    if !features.is_empty() {
-        for tied in sess.target.tied_target_features() {
-            // Tied features must be set to the same value, or not set at all
-            let mut tied_iter = tied.iter();
-            let enabled = features.get(tied_iter.next().unwrap());
-            if tied_iter.any(|f| enabled != features.get(f)) {
-                return Some(tied);
-            }
-        }
-    }
-    None
-}
-
 /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 5387b2a7f81..72e71b97a17 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -209,20 +209,6 @@ pub(crate) struct OutOfRangeInteger {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_expected_one_argument, code = E0722)]
-pub(crate) struct ExpectedOneArgumentOptimize {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_ssa_invalid_argument, code = E0722)]
-pub(crate) struct InvalidArgumentOptimize {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_ssa_copy_path_buf)]
 pub(crate) struct CopyPathBuf {
     pub source_file: PathBuf,
@@ -1217,30 +1203,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
     pub error: String,
 }
 
-pub struct TargetFeatureDisableOrEnable<'a> {
-    pub features: &'a [&'a str],
-    pub span: Option<Span>,
-    pub missing_features: Option<MissingFeatures>,
-}
-
-#[derive(Subdiagnostic)]
-#[help(codegen_ssa_missing_features)]
-pub struct MissingFeatures;
-
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
-        if let Some(span) = self.span {
-            diag.span(span);
-        };
-        if let Some(missing_features) = self.missing_features {
-            diag.subdiagnostic(missing_features);
-        }
-        diag.arg("features", self.features.join(", "));
-        diag
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_aix_strip_not_used)]
 pub(crate) struct AixStripNotUsed;
@@ -1283,3 +1245,68 @@ pub(crate) struct XcrunSdkPathWarning {
 #[derive(LintDiagnostic)]
 #[diag(codegen_ssa_aarch64_softfloat_neon)]
 pub(crate) struct Aarch64SoftfloatNeon;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_ctarget_feature_prefix)]
+#[note]
+pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum PossibleFeature<'a> {
+    #[help(codegen_ssa_possible_feature)]
+    Some { rust_feature: &'a str },
+    #[help(codegen_ssa_consider_filing_feature_request)]
+    None,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_ctarget_feature)]
+#[note]
+pub(crate) struct UnknownCTargetFeature<'a> {
+    pub feature: &'a str,
+    #[subdiagnostic]
+    pub rust_feature: PossibleFeature<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unstable_ctarget_feature)]
+#[note]
+pub(crate) struct UnstableCTargetFeature<'a> {
+    pub feature: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_forbidden_ctarget_feature)]
+#[note]
+#[note(codegen_ssa_forbidden_ctarget_feature_issue)]
+pub(crate) struct ForbiddenCTargetFeature<'a> {
+    pub feature: &'a str,
+    pub enabled: &'a str,
+    pub reason: &'a str,
+}
+
+pub struct TargetFeatureDisableOrEnable<'a> {
+    pub features: &'a [&'a str],
+    pub span: Option<Span>,
+    pub missing_features: Option<MissingFeatures>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(codegen_ssa_missing_features)]
+pub struct MissingFeatures;
+
+impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
+        if let Some(span) = self.span {
+            diag.span(span);
+        };
+        if let Some(missing_features) = self.missing_features {
+            diag.subdiagnostic(missing_features);
+        }
+        diag.arg("features", self.features.join(", "));
+        diag
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 640d197c219..67ac619091b 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,5 +1,5 @@
 use rustc_attr_data_structures::InstructionSetAttr;
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -8,11 +8,12 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::features::StabilityExt;
+use rustc_session::Session;
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
-use rustc_target::target_features::{self, Stability};
+use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability};
+use smallvec::SmallVec;
 
 use crate::errors;
 
@@ -67,7 +68,7 @@ pub(crate) fn from_target_feature_attr(
 
             // Only allow target features whose feature gates have been enabled
             // and which are permitted to be toggled.
-            if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
+            if let Err(reason) = stability.toggle_allowed() {
                 tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
                     span: item.span(),
                     feature,
@@ -88,7 +89,7 @@ pub(crate) fn from_target_feature_attr(
                 let feature_sym = Symbol::intern(feature);
                 for &name in tcx.implied_target_features(feature_sym) {
                     // But ensure the ABI does not forbid enabling this.
-                    // Here we do assume that LLVM doesn't add even more implied features
+                    // Here we do assume that the backend doesn't add even more implied features
                     // we don't know about, at least no features that would have ABI effects!
                     // We skip this logic in rustdoc, where we want to allow all target features of
                     // all targets, so we can't check their ABI compatibility and anyway we are not
@@ -156,6 +157,276 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
     }
 }
 
+/// Parse the value of `-Ctarget-feature`, also expanding implied features,
+/// and call the closure for each (expanded) Rust feature. If the list contains
+/// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked.
+fn parse_rust_feature_flag<'a>(
+    sess: &'a Session,
+    err_callback: impl Fn(&'a str),
+    mut callback: impl FnMut(
+        /* base_feature */ &'a str,
+        /* with_implied */ FxHashSet<&'a str>,
+        /* enable */ bool,
+    ),
+) {
+    // A cache for the backwards implication map.
+    let mut inverse_implied_features: Option<FxHashMap<&str, FxHashSet<&str>>> = None;
+
+    for feature in sess.opts.cg.target_feature.split(',') {
+        if let Some(base_feature) = feature.strip_prefix('+') {
+            // Skip features that are not target features, but rustc features.
+            if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
+                return;
+            }
+
+            callback(base_feature, sess.target.implied_target_features(base_feature), true)
+        } else if let Some(base_feature) = feature.strip_prefix('-') {
+            // Skip features that are not target features, but rustc features.
+            if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
+                return;
+            }
+
+            // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical
+            // contraposition. So we have to find all the reverse implications of `base_feature` and
+            // disable them, too.
+
+            let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| {
+                let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default();
+                for (f, _, is) in sess.target.rust_target_features() {
+                    for i in is.iter() {
+                        set.entry(i).or_default().insert(f);
+                    }
+                }
+                set
+            });
+
+            // Inverse implied target features have their own inverse implied target features, so we
+            // traverse the map until there are no more features to add.
+            let mut features = FxHashSet::default();
+            let mut new_features = vec![base_feature];
+            while let Some(new_feature) = new_features.pop() {
+                if features.insert(new_feature) {
+                    if let Some(implied_features) = inverse_implied_features.get(&new_feature) {
+                        new_features.extend(implied_features)
+                    }
+                }
+            }
+
+            callback(base_feature, features, false)
+        } else if !feature.is_empty() {
+            err_callback(feature)
+        }
+    }
+}
+
+/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically,
+/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and
+/// 2nd component of the return value, respectively).
+///
+/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is
+/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`.
+///
+/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere.
+pub fn cfg_target_feature(
+    sess: &Session,
+    mut target_base_has_feature: impl FnMut(&str) -> bool,
+) -> (Vec<Symbol>, Vec<Symbol>) {
+    // Compute which of the known target features are enabled in the 'base' target machine. We only
+    // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
+    let mut features: UnordSet<Symbol> = sess
+        .target
+        .rust_target_features()
+        .iter()
+        .filter(|(feature, _, _)| target_base_has_feature(feature))
+        .map(|(feature, _, _)| Symbol::intern(feature))
+        .collect();
+
+    // Add enabled and remove disabled features.
+    parse_rust_feature_flag(
+        sess,
+        /* err_callback */
+        |_| {
+            // Errors are already emitted in `flag_to_backend_features`; avoid duplicates.
+        },
+        |_base_feature, new_features, enabled| {
+            // Iteration order is irrelevant since this only influences an `UnordSet`.
+            #[allow(rustc::potential_query_instability)]
+            if enabled {
+                features.extend(new_features.into_iter().map(|f| Symbol::intern(f)));
+            } else {
+                // Remove `new_features` from `features`.
+                for new in new_features {
+                    features.remove(&Symbol::intern(new));
+                }
+            }
+        },
+    );
+
+    // Filter enabled features based on feature gates.
+    let f = |allow_unstable| {
+        sess.target
+            .rust_target_features()
+            .iter()
+            .filter_map(|(feature, gate, _)| {
+                // The `allow_unstable` set is used by rustc internally to determine which target
+                // features are truly available, so we want to return even perma-unstable
+                // "forbidden" features.
+                if allow_unstable
+                    || (gate.in_cfg()
+                        && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
+                {
+                    Some(Symbol::intern(feature))
+                } else {
+                    None
+                }
+            })
+            .filter(|feature| features.contains(&feature))
+            .collect()
+    };
+
+    (f(true), f(false))
+}
+
+/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
+/// combinations are allowed.
+pub fn check_tied_features(
+    sess: &Session,
+    features: &FxHashMap<&str, bool>,
+) -> Option<&'static [&'static str]> {
+    if !features.is_empty() {
+        for tied in sess.target.tied_target_features() {
+            // Tied features must be set to the same value, or not set at all
+            let mut tied_iter = tied.iter();
+            let enabled = features.get(tied_iter.next().unwrap());
+            if tied_iter.any(|f| enabled != features.get(f)) {
+                return Some(tied);
+            }
+        }
+    }
+    None
+}
+
+/// Translates the `-Ctarget-feature` flag into a backend target feature list.
+///
+/// `to_backend_features` converts a Rust feature name into a list of backend feature names; this is
+/// used for diagnostic purposes only.
+///
+/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state
+/// accessible by that closure) to enable/disable the given Rust feature name.
+pub fn flag_to_backend_features<'a, const N: usize>(
+    sess: &'a Session,
+    diagnostics: bool,
+    to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>,
+    mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool),
+) {
+    let known_features = sess.target.rust_target_features();
+
+    // Compute implied features
+    let mut rust_features = vec![];
+    parse_rust_feature_flag(
+        sess,
+        /* err_callback */
+        |feature| {
+            if diagnostics {
+                sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature });
+            }
+        },
+        |base_feature, new_features, enable| {
+            rust_features.extend(
+                UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)),
+            );
+            // Check feature validity.
+            if diagnostics {
+                let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature);
+                match feature_state {
+                    None => {
+                        // This is definitely not a valid Rust feature name. Maybe it is a backend
+                        // feature name? If so, give a better error message.
+                        let rust_feature =
+                            known_features.iter().find_map(|&(rust_feature, _, _)| {
+                                let backend_features = to_backend_features(rust_feature);
+                                if backend_features.contains(&base_feature)
+                                    && !backend_features.contains(&rust_feature)
+                                {
+                                    Some(rust_feature)
+                                } else {
+                                    None
+                                }
+                            });
+                        let unknown_feature = if let Some(rust_feature) = rust_feature {
+                            errors::UnknownCTargetFeature {
+                                feature: base_feature,
+                                rust_feature: errors::PossibleFeature::Some { rust_feature },
+                            }
+                        } else {
+                            errors::UnknownCTargetFeature {
+                                feature: base_feature,
+                                rust_feature: errors::PossibleFeature::None,
+                            }
+                        };
+                        sess.dcx().emit_warn(unknown_feature);
+                    }
+                    Some((_, stability, _)) => {
+                        if let Err(reason) = stability.toggle_allowed() {
+                            sess.dcx().emit_warn(errors::ForbiddenCTargetFeature {
+                                feature: base_feature,
+                                enabled: if enable { "enabled" } else { "disabled" },
+                                reason,
+                            });
+                        } else if stability.requires_nightly().is_some() {
+                            // An unstable feature. Warn about using it. It makes little sense
+                            // to hard-error here since we just warn about fully unknown
+                            // features above.
+                            sess.dcx().emit_warn(errors::UnstableCTargetFeature {
+                                feature: base_feature,
+                            });
+                        }
+                    }
+                }
+            }
+        },
+    );
+
+    if diagnostics {
+        // FIXME(nagisa): figure out how to not allocate a full hashmap here.
+        if let Some(f) = check_tied_features(
+            sess,
+            &FxHashMap::from_iter(rust_features.iter().map(|&(enable, feature)| (feature, enable))),
+        ) {
+            sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable {
+                features: f,
+                span: None,
+                missing_features: None,
+            });
+        }
+    }
+
+    // Add this to the backend features.
+    for (enable, feature) in rust_features {
+        extend_backend_features(feature, enable);
+    }
+}
+
+/// Computes the backend target features to be added to account for retpoline flags.
+/// Used by both LLVM and GCC since their target features are, conveniently, the same.
+pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    // -Zretpoline without -Zretpoline-external-thunk enables
+    // retpoline-indirect-branches and retpoline-indirect-calls target features
+    let unstable_opts = &sess.opts.unstable_opts;
+    if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
+        features.push("+retpoline-indirect-branches".into());
+        features.push("+retpoline-indirect-calls".into());
+    }
+    // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
+    // retpoline-external-thunk, retpoline-indirect-branches and
+    // retpoline-indirect-calls target features
+    if unstable_opts.retpoline_external_thunk {
+        features.push("+retpoline-external-thunk".into());
+        features.push("+retpoline-indirect-branches".into());
+        features.push("+retpoline-indirect-calls".into());
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
@@ -182,7 +453,8 @@ pub(crate) fn provide(providers: &mut Providers) {
                                     Stability::Unstable { .. } | Stability::Forbidden { .. },
                                 )
                                 | (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
-                                    // The stability in the entry is at least as good as the new one, just keep it.
+                                    // The stability in the entry is at least as good as the new
+                                    // one, just keep it.
                                 }
                                 _ => {
                                     // Overwrite stabilite.
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 4f252f3ccd4..576b174369d 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -463,12 +463,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         );
     }
 
-    fn crate_inject_span(&self) -> Option<Span> {
-        self.tcx.hir_crate_items(()).definitions().next().and_then(|id| {
-            self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id))
-        })
-    }
-
     /// Check the const stability of the given item (fn or trait).
     fn check_callee_stability(&mut self, def_id: DefId) {
         match self.tcx.lookup_const_stability(def_id) {
@@ -543,7 +537,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                         feature,
                         feature_enabled,
                         safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
-                        suggestion_span: self.crate_inject_span(),
                         is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait,
                     });
                 }
@@ -919,7 +912,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 name: intrinsic.name,
                                 feature,
                                 const_stable_indirect: is_const_stable,
-                                suggestion: self.crate_inject_span(),
                             });
                         }
                         Some(attrs::ConstStability {
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 9c30dbff99e..887275e7294 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -1,8 +1,8 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use hir::{ConstContext, LangItem};
+use rustc_errors::Diag;
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -384,7 +384,6 @@ pub(crate) struct CallUnstable {
     /// expose on stable.
     pub feature_enabled: bool,
     pub safe_to_expose_on_stable: bool,
-    pub suggestion_span: Option<Span>,
     /// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait.
     pub is_function_call: bool,
 }
@@ -412,20 +411,7 @@ impl<'tcx> NonConstOp<'tcx> for CallUnstable {
                 def_path: ccx.tcx.def_path_str(self.def_id),
             })
         };
-        // FIXME: make this translatable
-        let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
-        #[allow(rustc::untranslatable_diagnostic)]
-        if let Some(span) = self.suggestion_span {
-            err.span_suggestion_verbose(
-                span,
-                msg,
-                format!("#![feature({})]\n", self.feature),
-                Applicability::MachineApplicable,
-            );
-        } else {
-            err.help(msg);
-        }
-
+        ccx.tcx.disabled_nightly_features(&mut err, [(String::new(), self.feature)]);
         err
     }
 }
@@ -452,7 +438,6 @@ pub(crate) struct IntrinsicUnstable {
     pub name: Symbol,
     pub feature: Symbol,
     pub const_stable_indirect: bool,
-    pub suggestion: Option<Span>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
@@ -472,8 +457,7 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
             span,
             name: self.name,
             feature: self.feature,
-            suggestion: self.suggestion,
-            help: self.suggestion.is_none(),
+            suggestion: ccx.tcx.crate_level_attribute_injection_span(),
         })
     }
 }
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 037cbf777e7..69c71aef9f3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -136,9 +136,7 @@ pub(crate) struct UnstableIntrinsic {
         code = "#![feature({feature})]\n",
         applicability = "machine-applicable"
     )]
-    pub suggestion: Option<Span>,
-    #[help(const_eval_unstable_intrinsic_suggestion)]
-    pub help: bool,
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index ec77043cd12..688307a941f 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -292,7 +292,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
         }
         HirTree => {
             debug!("pretty printing HIR tree");
-            format!("{:#?}", ex.tcx().hir_crate(()))
+            ex.tcx()
+                .hir_crate_items(())
+                .owners()
+                .map(|owner| format!("{:#?} => {:#?}\n", owner, ex.tcx().hir_owner_nodes(owner)))
+                .collect()
         }
         Mir => {
             let mut out = Vec::new();
diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md
index 570717a92bd..1799458d46c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0722.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0722.md
@@ -1,8 +1,14 @@
+#### Note: this error code is no longer emitted by the compiler
+
+This is because it was too specific to the `optimize` attribute.
+Similar diagnostics occur for other attributes too.
+The example here will now emit `E0539`
+
 The `optimize` attribute was malformed.
 
 Erroneous code example:
 
-```compile_fail,E0722
+```compile_fail,E0539
 #![feature(optimize_attribute)]
 
 #[optimize(something)] // error: invalid argument
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 6f5e4829802..22cc1e894da 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -686,6 +686,7 @@ E0805: 0805,
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
 //  E0709, // multiple different lifetimes used in arguments of `async fn`
 //  E0721, // `await` keyword
+//  E0722, // replaced with a generic attribute input check
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
 //  E0744, // merged into E0728
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index a7bc6207149..91715851226 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -510,7 +510,7 @@ declare_features! (
     (unstable, ffi_pure, "1.45.0", Some(58329)),
     /// Controlling the behavior of fmt::Debug
     (unstable, fmt_debug, "1.82.0", Some(129709)),
-    /// Allows using `#[repr(align(...))]` on function items
+    /// Allows using `#[align(...)]` on function items
     (unstable, fn_align, "1.53.0", Some(82232)),
     /// Support delegating implementation of functions to other already implemented functions.
     (incomplete, fn_delegation, "1.76.0", Some(118212)),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index ca24d5a6424..bf2d4f662ef 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -311,9 +311,7 @@ fn default_body_is_unstable(
         reason: reason_str,
     });
 
-    let inject_span = item_did
-        .as_local()
-        .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
+    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
     rustc_session::parse::add_feature_diagnostics_for_issue(
         &mut err,
         &tcx.sess,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 20d0e87b7a7..13f95024e5a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1064,7 +1064,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                     Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
                 };
                 if let Some(features) = may_suggest_feature {
-                    tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features);
+                    tcx.disabled_nightly_features(&mut diag, features);
                 }
 
                 Err(diag.emit())
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index abb8cdc1cdf..5f59b3ad96e 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -30,8 +30,6 @@ pub(crate) struct BaseExpressionDoubleDot {
     )]
     pub default_field_values_suggestion: Option<Span>,
     #[subdiagnostic]
-    pub default_field_values_help: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>,
-    #[subdiagnostic]
     pub add_expr: Option<BaseExpressionDoubleDotAddExpr>,
     #[subdiagnostic]
     pub remove_dots: Option<BaseExpressionDoubleDotRemove>,
@@ -61,10 +59,6 @@ pub(crate) struct BaseExpressionDoubleDotAddExpr {
     pub span: Span,
 }
 
-#[derive(Subdiagnostic)]
-#[help(hir_typeck_base_expression_double_dot_enable_default_field_values)]
-pub(crate) struct BaseExpressionDoubleDotEnableDefaultFieldValues;
-
 #[derive(Diagnostic)]
 #[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)]
 pub(crate) struct FieldMultiplySpecifiedInInitializer {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 55c39d960e7..eca9c5faa32 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -43,10 +43,9 @@ use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectatio
 use crate::coercion::{CoerceMany, DynamicCoerceMany};
 use crate::errors::{
     AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
-    BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove,
-    CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
-    HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant,
-    ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
+    BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer,
+    FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType,
+    NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
     TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
 };
 use crate::{
@@ -2158,7 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             if !self.tcx.features().default_field_values() {
-                let sugg = self.tcx.crate_level_attribute_injection_span(expr.hir_id);
+                let sugg = self.tcx.crate_level_attribute_injection_span();
                 self.dcx().emit_err(BaseExpressionDoubleDot {
                     span: span.shrink_to_hi(),
                     // We only mention enabling the feature if this is a nightly rustc *and* the
@@ -2166,18 +2165,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     default_field_values_suggestion: if self.tcx.sess.is_nightly_build()
                         && missing_mandatory_fields.is_empty()
                         && !missing_optional_fields.is_empty()
-                        && sugg.is_some()
                     {
-                        sugg
-                    } else {
-                        None
-                    },
-                    default_field_values_help: if self.tcx.sess.is_nightly_build()
-                        && missing_mandatory_fields.is_empty()
-                        && !missing_optional_fields.is_empty()
-                        && sugg.is_none()
-                    {
-                        Some(BaseExpressionDoubleDotEnableDefaultFieldValues)
+                        Some(sugg)
                     } else {
                         None
                     },
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index a3fdf200c8e..589dbb53116 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1727,7 +1727,6 @@ impl<'tcx> Pick<'tcx> {
             }
             tcx.disabled_nightly_features(
                 lint,
-                Some(scope_expr_id),
                 self.unstable_candidates.iter().map(|(candidate, feature)| {
                     (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature)
                 }),
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index 67f13192b52..2385c68ef6b 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -7,8 +7,11 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use rustc_macros::extension;
-use rustc_middle::bug;
-use rustc_middle::ty::{self, FnMutDelegate, GenericArgKind, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
+    TypeVisitableExt, TypeVisitor,
+};
+use rustc_type_ir::TypeVisitable;
 
 use crate::infer::canonical::{Canonical, CanonicalVarValues};
 
@@ -58,23 +61,169 @@ where
     T: TypeFoldable<TyCtxt<'tcx>>,
 {
     if var_values.var_values.is_empty() {
-        value
-    } else {
-        let delegate = FnMutDelegate {
-            regions: &mut |br: ty::BoundRegion| match var_values[br.var].kind() {
-                GenericArgKind::Lifetime(l) => l,
-                r => bug!("{:?} is a region but value is {:?}", br, r),
-            },
-            types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].kind() {
-                GenericArgKind::Type(ty) => ty,
-                r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
-            },
-            consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].kind() {
-                GenericArgKind::Const(ct) => ct,
-                c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
-            },
-        };
-
-        tcx.replace_escaping_bound_vars_uncached(value, delegate)
+        return value;
     }
+
+    value.fold_with(&mut CanonicalInstantiator {
+        tcx,
+        current_index: ty::INNERMOST,
+        var_values: var_values.var_values,
+        cache: Default::default(),
+    })
+}
+
+/// Replaces the bound vars in a canonical binder with var values.
+struct CanonicalInstantiator<'tcx> {
+    tcx: TyCtxt<'tcx>,
+
+    // The values that the bound vars are are being instantiated with.
+    var_values: ty::GenericArgsRef<'tcx>,
+
+    /// As with `BoundVarReplacer`, represents the index of a binder *just outside*
+    /// the ones we have visited.
+    current_index: ty::DebruijnIndex,
+
+    // Instantiation is a pure function of `DebruijnIndex` and `Ty`.
+    cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.current_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.current_index.shift_out(1);
+        t
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
+                self.var_values[bound_ty.var.as_usize()].expect_ty()
+            }
+            _ => {
+                if !t.has_vars_bound_at_or_above(self.current_index) {
+                    t
+                } else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
+                    t
+                } else {
+                    let res = t.super_fold_with(self);
+                    assert!(self.cache.insert((self.current_index, t), res));
+                    res
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match r.kind() {
+            ty::ReBound(debruijn, br) if debruijn == self.current_index => {
+                self.var_values[br.var.as_usize()].expect_region()
+            }
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.kind() {
+            ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+                self.var_values[bound_const.as_usize()].expect_const()
+            }
+            _ => ct.super_fold_with(self),
+        }
+    }
+
+    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+    }
+
+    fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
+        if !c.has_vars_bound_at_or_above(self.current_index) {
+            return c;
+        }
+
+        // Since instantiation is a function of `DebruijnIndex`, we don't want
+        // to have to cache more copies of clauses when we're inside of binders.
+        // Since we currently expect to only have clauses in the outermost
+        // debruijn index, we just fold if we're inside of a binder.
+        if self.current_index > ty::INNERMOST {
+            return c.super_fold_with(self);
+        }
+
+        // Our cache key is `(clauses, var_values)`, but we also don't care about
+        // var values that aren't named in the clauses, since they can change without
+        // affecting the output. Since `ParamEnv`s are cached first, we compute the
+        // last var value that is mentioned in the clauses, and cut off the list so
+        // that we have more hits in the cache.
+
+        // We also cache the computation of "highest var named by clauses" since that
+        // is both expensive (depending on the size of the clauses) and a pure function.
+        let index = *self
+            .tcx
+            .highest_var_in_clauses_cache
+            .lock()
+            .entry(c)
+            .or_insert_with(|| highest_var_in_clauses(c));
+        let c_args = &self.var_values[..=index];
+
+        if let Some(c) = self.tcx.clauses_cache.lock().get(&(c, c_args)) {
+            c
+        } else {
+            let folded = c.super_fold_with(self);
+            self.tcx.clauses_cache.lock().insert((c, c_args), folded);
+            folded
+        }
+    }
+}
+
+fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
+    struct HighestVarInClauses {
+        max_var: usize,
+        current_index: ty::DebruijnIndex,
+    }
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses {
+        fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+            &mut self,
+            t: &ty::Binder<'tcx, T>,
+        ) -> Self::Result {
+            self.current_index.shift_in(1);
+            let t = t.super_visit_with(self);
+            self.current_index.shift_out(1);
+            t
+        }
+        fn visit_ty(&mut self, t: Ty<'tcx>) {
+            if let ty::Bound(debruijn, bound_ty) = *t.kind()
+                && debruijn == self.current_index
+            {
+                self.max_var = self.max_var.max(bound_ty.var.as_usize());
+            } else if t.has_vars_bound_at_or_above(self.current_index) {
+                t.super_visit_with(self);
+            }
+        }
+        fn visit_region(&mut self, r: ty::Region<'tcx>) {
+            if let ty::ReBound(debruijn, bound_region) = r.kind()
+                && debruijn == self.current_index
+            {
+                self.max_var = self.max_var.max(bound_region.var.as_usize());
+            }
+        }
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) {
+            if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind()
+                && debruijn == self.current_index
+            {
+                self.max_var = self.max_var.max(bound_const.as_usize());
+            } else if ct.has_vars_bound_at_or_above(self.current_index) {
+                ct.super_visit_with(self);
+            }
+        }
+    }
+    let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST };
+    c.visit_with(&mut visitor);
+    visitor.max_var
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 02d1ebdb31a..70ae9147fb1 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1011,8 +1011,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
 
     // Prefetch this to prevent multiple threads from blocking on it later.
     // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed
-    // to use `hir_crate`.
-    tcx.ensure_done().hir_crate(());
+    // to use `hir_crate_items`.
+    tcx.ensure_done().hir_crate_items(());
 
     let sess = tcx.sess;
     sess.time("misc_checking_1", || {
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 4c2b82a9a23..481e116d06e 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::CRATE_OWNER_ID;
 use rustc_middle::lint::LintExpectation;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -18,7 +17,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
 
     let mut expectations = Vec::new();
 
-    for owner in std::iter::once(CRATE_OWNER_ID).chain(krate.owners()) {
+    for owner in krate.owners() {
         let lints = tcx.shallow_lint_levels_on(owner);
         expectations.extend_from_slice(&lints.expectations);
     }
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index e5e1ae508ed..03bb97095a4 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -328,8 +328,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns an iterator of the `DefId`s for all body-owners in this
-    /// crate. If you would prefer to iterate over the bodies
-    /// themselves, you can do `self.hir_crate(()).body_ids.iter()`.
+    /// crate.
     #[inline]
     pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
         self.hir_crate_items(()).body_owners.iter().copied()
@@ -396,12 +395,11 @@ impl<'tcx> TyCtxt<'tcx> {
     where
         V: Visitor<'tcx>,
     {
-        let krate = self.hir_crate(());
-        for info in krate.owners.iter() {
-            if let MaybeOwner::Owner(info) = info {
-                for attrs in info.attrs.map.values() {
-                    walk_list!(visitor, visit_attribute, *attrs);
-                }
+        let krate = self.hir_crate_items(());
+        for owner in krate.owners() {
+            let attrs = self.hir_attr_map(owner);
+            for attrs in attrs.map.values() {
+                walk_list!(visitor, visit_attribute, *attrs);
             }
         }
         V::Result::output()
@@ -1225,6 +1223,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
         ..
     } = collector;
     ModuleItems {
+        add_root: false,
         submodules: submodules.into_boxed_slice(),
         free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
@@ -1260,6 +1259,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
     } = collector;
 
     ModuleItems {
+        add_root: true,
         submodules: submodules.into_boxed_slice(),
         free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 9f79ed4b5a5..d7a8dce0536 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -24,6 +24,9 @@ use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
 /// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
 #[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
+    /// Whether this represents the whole crate, in which case we need to add `CRATE_OWNER_ID` to
+    /// the iterators if we want to account for the crate root.
+    add_root: bool,
     submodules: Box<[OwnerId]>,
     free_items: Box<[ItemId]>,
     trait_items: Box<[TraitItemId]>,
@@ -66,9 +69,10 @@ impl ModuleItems {
     }
 
     pub fn owners(&self) -> impl Iterator<Item = OwnerId> {
-        self.free_items
-            .iter()
-            .map(|id| id.owner_id)
+        self.add_root
+            .then_some(CRATE_OWNER_ID)
+            .into_iter()
+            .chain(self.free_items.iter().map(|id| id.owner_id))
             .chain(self.trait_items.iter().map(|id| id.owner_id))
             .chain(self.impl_items.iter().map(|id| id.owner_id))
             .chain(self.foreign_items.iter().map(|id| id.owner_id))
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f1395c242f2..4f8cfd86597 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1479,6 +1479,12 @@ pub struct GlobalCtxt<'tcx> {
 
     pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
 
+    /// Caches the index of the highest bound var in clauses in a canonical binder.
+    pub highest_var_in_clauses_cache: Lock<FxHashMap<ty::Clauses<'tcx>, usize>>,
+    /// Caches the instantiation of a canonical binder given a set of args.
+    pub clauses_cache:
+        Lock<FxHashMap<(ty::Clauses<'tcx>, &'tcx [ty::GenericArg<'tcx>]), ty::Clauses<'tcx>>>,
+
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
@@ -1727,6 +1733,8 @@ impl<'tcx> TyCtxt<'tcx> {
             new_solver_evaluation_cache: Default::default(),
             new_solver_canonical_param_env_cache: Default::default(),
             canonical_param_env_cache: Default::default(),
+            highest_var_in_clauses_cache: Default::default(),
+            clauses_cache: Default::default(),
             data_layout,
             alloc_map: interpret::AllocMap::new(),
             current_gcx,
@@ -2113,7 +2121,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
         // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
-        self.ensure_ok().hir_crate(());
+        self.ensure_ok().hir_crate_items(());
         // Freeze definitions once we start iterating on them, to prevent adding new ones
         // while iterating. If some query needs to add definitions, it should be `ensure`d above.
         self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
@@ -3160,42 +3168,33 @@ impl<'tcx> TyCtxt<'tcx> {
         lint_level(self.sess, lint, level, Some(span.into()), decorate);
     }
 
-    /// Find the crate root and the appropriate span where `use` and outer attributes can be
-    /// inserted at.
-    pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option<Span> {
-        for (_hir_id, node) in self.hir_parent_iter(hir_id) {
-            if let hir::Node::Crate(m) = node {
-                return Some(m.spans.inject_use_span.shrink_to_lo());
-            }
-        }
-        None
+    /// Find the appropriate span where `use` and outer attributes can be inserted at.
+    pub fn crate_level_attribute_injection_span(self) -> Span {
+        let node = self.hir_node(hir::CRATE_HIR_ID);
+        let hir::Node::Crate(m) = node else { bug!() };
+        m.spans.inject_use_span.shrink_to_lo()
     }
 
     pub fn disabled_nightly_features<E: rustc_errors::EmissionGuarantee>(
         self,
         diag: &mut Diag<'_, E>,
-        hir_id: Option<HirId>,
         features: impl IntoIterator<Item = (String, Symbol)>,
     ) {
         if !self.sess.is_nightly_build() {
             return;
         }
 
-        let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id));
+        let span = self.crate_level_attribute_injection_span();
         for (desc, feature) in features {
             // FIXME: make this string translatable
             let msg =
                 format!("add `#![feature({feature})]` to the crate attributes to enable{desc}");
-            if let Some(span) = span {
-                diag.span_suggestion_verbose(
-                    span,
-                    msg,
-                    format!("#![feature({feature})]\n"),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                diag.help(msg);
-            }
+            diag.span_suggestion_verbose(
+                span,
+                msg,
+                format!("#![feature({feature})]\n"),
+                Applicability::MaybeIncorrect,
+            );
         }
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index a12215a44f9..646e996ff30 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -291,6 +291,7 @@ fn emit_malformed_attribute(
             | sym::repr
             | sym::align
             | sym::deprecated
+            | sym::optimize
     ) {
         return;
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 50d6c5d9764..a5d2ad4dc20 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -128,6 +128,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
                     self.check_inline(hir_id, *attr_span, span, kind, target)
                 }
+                Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => {
+                    self.check_optimize(hir_id, *attr_span, span, target)
+                }
                 Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
                     .check_allow_internal_unstable(
                         hir_id,
@@ -167,7 +170,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
                         }
                         [sym::coverage, ..] => self.check_coverage(attr, span, target),
-                        [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
                         [sym::no_sanitize, ..] => {
                             self.check_no_sanitize(attr, span, target)
                         }
@@ -529,7 +531,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
     /// Checks that `#[optimize(..)]` is applied to a function/closure/method,
     /// or to an impl block or module.
-    fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+    fn check_optimize(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
         let is_valid = matches!(
             target,
             Target::Fn
@@ -538,7 +540,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         );
         if !is_valid {
             self.dcx().emit_err(errors::OptimizeInvalidTarget {
-                attr_span: attr.span(),
+                attr_span,
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 61953614c77..528c52eace7 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -40,11 +40,6 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
 
 session_file_write_fail = failed to write `{$path}` due to error `{$err}`
 
-session_forbidden_ctarget_feature =
-    target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
-    .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
-
 session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
 
 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
@@ -137,9 +132,6 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
 session_unleashed_feature_help_named = skipping check for `{$gate}` feature
 session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
 
-session_unstable_ctarget_feature =
-    unstable feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = this feature is not stably supported; its behavior can change in the future
 session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
 
 session_unsupported_crate_type_for_target =
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 9c591dcf619..bf95014843d 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -501,20 +501,3 @@ pub(crate) struct SoftFloatIgnored;
 #[note]
 #[note(session_soft_float_deprecated_issue)]
 pub(crate) struct SoftFloatDeprecated;
-
-#[derive(Diagnostic)]
-#[diag(session_forbidden_ctarget_feature)]
-#[note]
-#[note(session_forbidden_ctarget_feature_issue)]
-pub(crate) struct ForbiddenCTargetFeature<'a> {
-    pub feature: &'a str,
-    pub enabled: &'a str,
-    pub reason: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(session_unstable_ctarget_feature)]
-#[note]
-pub(crate) struct UnstableCTargetFeature<'a> {
-    pub feature: &'a str,
-}
diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs
deleted file mode 100644
index 70a088a236f..00000000000
--- a/compiler/rustc_session/src/features.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use rustc_target::target_features::Stability;
-
-use crate::Session;
-use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
-
-pub trait StabilityExt {
-    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
-    /// Otherwise, some features also may only be enabled by flag (target modifier).
-    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
-    /// `requires_nightly`.)
-    fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
-
-    /// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
-    fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
-}
-
-impl StabilityExt for Stability {
-    fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
-        match self {
-            Stability::Forbidden { reason } => Err(reason),
-            Stability::TargetModifierOnly { reason, flag } => {
-                if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
-            }
-            _ => Ok(()),
-        }
-    }
-    fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
-        if let Err(reason) = self.is_toggle_permitted(sess) {
-            sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                feature,
-                enabled: if enable { "enabled" } else { "disabled" },
-                reason,
-            });
-        } else if self.requires_nightly().is_some() {
-            // An unstable feature. Warn about using it. It makes little sense
-            // to hard-error here since we just warn about fully unknown
-            // features above.
-            sess.dcx().emit_warn(UnstableCTargetFeature { feature });
-        }
-    }
-}
-
-pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
-    // -Zretpoline without -Zretpoline-external-thunk enables
-    // retpoline-indirect-branches and retpoline-indirect-calls target features
-    let unstable_opts = &sess.opts.unstable_opts;
-    if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
-        features.push("+retpoline-indirect-branches");
-        features.push("+retpoline-indirect-calls");
-    }
-    // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
-    // retpoline-external-thunk, retpoline-indirect-branches and
-    // retpoline-indirect-calls target features
-    if unstable_opts.retpoline_external_thunk {
-        features.push("+retpoline-external-thunk");
-        features.push("+retpoline-indirect-branches");
-        features.push("+retpoline-indirect-calls");
-    }
-}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 4added19e56..5e5872ee068 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -29,7 +29,6 @@ pub use session::*;
 pub mod output;
 
 pub use getopts;
-pub mod features;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 31b4237d3b2..7fef942525b 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -290,14 +290,6 @@ macro_rules! top_level_options {
                 mods.sort_by(|a, b| a.opt.cmp(&b.opt));
                 mods
             }
-
-            pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
-                match flag {
-                    "retpoline" => self.unstable_opts.retpoline,
-                    "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
-                    _ => false,
-                }
-            }
         }
     );
 }
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index a1eac1fba25..3eea1e070a6 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -11,11 +11,6 @@ use crate::spec::{FloatAbi, RustcAbi, Target};
 /// These exist globally and are not in the target-specific lists below.
 pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
 
-/// Features that require special handling when passing to LLVM:
-/// these are target-specific (i.e., must also be listed in the target-specific list below)
-/// but do not correspond to an LLVM target feature.
-pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
-
 /// Stability information for target features.
 #[derive(Debug, Copy, Clone)]
 pub enum Stability {
@@ -34,9 +29,6 @@ pub enum Stability {
     /// particular for features are actually ABI configuration flags (not all targets are as nice as
     /// RISC-V and have an explicit way to set the ABI separate from target features).
     Forbidden { reason: &'static str },
-    /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set
-    /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules.
-    TargetModifierOnly { reason: &'static str, flag: &'static str },
 }
 use Stability::*;
 
@@ -52,7 +44,6 @@ impl<CTX> HashStable<CTX> for Stability {
             Stability::Forbidden { reason } => {
                 reason.hash_stable(hcx, hasher);
             }
-            Stability::TargetModifierOnly { .. } => {}
         }
     }
 }
@@ -62,7 +53,7 @@ impl Stability {
     /// (It might still be nightly-only even if this returns `true`, so make sure to also check
     /// `requires_nightly`.)
     pub fn in_cfg(&self) -> bool {
-        !matches!(self, Stability::Forbidden { .. })
+        matches!(self, Stability::Stable | Stability::Unstable { .. })
     }
 
     /// Returns the nightly feature that is required to toggle this target feature via
@@ -78,7 +69,16 @@ impl Stability {
             Stability::Unstable(nightly_feature) => Some(nightly_feature),
             Stability::Stable { .. } => None,
             Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
-            Stability::TargetModifierOnly { .. } => None,
+        }
+    }
+
+    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
+    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
+    /// `requires_nightly`.)
+    pub fn toggle_allowed(&self) -> Result<(), &'static str> {
+        match self {
+            Stability::Unstable(_) | Stability::Stable { .. } => Ok(()),
+            Stability::Forbidden { reason } => Err(reason),
         }
     }
 }
@@ -270,12 +270,7 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
     // FEAT_RDM
     ("rdm", Stable, &["neon"]),
-    // This is needed for inline assembly, but shouldn't be stabilized as-is
-    // since it should be enabled globally using -Zfixed-x18, not
-    // #[target_feature].
-    // Note that cfg(target_feature = "reserve-x18") is currently not set for
-    // targets that reserve x18 by default.
-    ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]),
     // FEAT_SB
     ("sb", Stable, &[]),
     // FEAT_SHA1 & FEAT_SHA256
@@ -450,26 +445,17 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("rdseed", Stable, &[]),
     (
         "retpoline-external-thunk",
-        Stability::TargetModifierOnly {
-            reason: "use `retpoline-external-thunk` target modifier flag instead",
-            flag: "retpoline-external-thunk",
-        },
+        Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" },
         &[],
     ),
     (
         "retpoline-indirect-branches",
-        Stability::TargetModifierOnly {
-            reason: "use `retpoline` target modifier flag instead",
-            flag: "retpoline",
-        },
+        Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
         &[],
     ),
     (
         "retpoline-indirect-calls",
-        Stability::TargetModifierOnly {
-            reason: "use `retpoline` target modifier flag instead",
-            flag: "retpoline",
-        },
+        Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
         &[],
     ),
     ("rtm", Unstable(sym::rtm_target_feature), &[]),
@@ -732,6 +718,7 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 #[rustfmt::skip]
 const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
+    // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker
     ("backchain", Unstable(sym::s390x_target_feature), &[]),
     ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
     ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index ee5a5b247ce..6d07ae021ae 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3575,11 +3575,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::TrivialBound => {
                 err.help("see issue #48214");
-                tcx.disabled_nightly_features(
-                    err,
-                    Some(tcx.local_def_id_to_hir_id(body_id)),
-                    [(String::new(), sym::trivial_bounds)],
-                );
+                tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]);
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
                 let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 34012d6943b..4f0e7aed217 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -219,21 +219,19 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "r-efi-alloc"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
+checksum = "dc2f58ef3ca9bb0f9c44d9aa8537601bcd3df94cc9314a40178cadf7d4466354"
 dependencies = [
- "compiler_builtins",
  "r-efi",
  "rustc-std-workspace-core",
 ]
diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs
index 410e67d3fdb..3d6c740e80b 100644
--- a/library/alloc/src/collections/linked_list/tests.rs
+++ b/library/alloc/src/collections/linked_list/tests.rs
@@ -1,4 +1,3 @@
-use std::cell::Cell;
 use std::panic::{AssertUnwindSafe, catch_unwind};
 use std::thread;
 
@@ -6,6 +5,7 @@ use rand::RngCore;
 
 use super::*;
 use crate::testing::crash_test::{CrashTestDummy, Panic};
+use crate::testing::macros::struct_with_counted_drop;
 use crate::vec::Vec;
 
 #[test]
@@ -1010,22 +1010,6 @@ fn extract_if_drop_panic_leak() {
     assert_eq!(d7.dropped(), 1);
 }
 
-macro_rules! struct_with_counted_drop {
-    ($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => {
-        thread_local! {static $drop_counter: Cell<u32> = Cell::new(0);}
-
-        struct $struct_name$(($elt_ty))?;
-
-        impl Drop for $struct_name {
-            fn drop(&mut self) {
-                $drop_counter.set($drop_counter.get() + 1);
-
-                $($drop_stmt(self))?
-            }
-        }
-    };
-}
-
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn extract_if_pred_panic_leak() {
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index c90679f1797..ad76cb14deb 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -1,9 +1,7 @@
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
-
 use core::iter::TrustedLen;
 
 use super::*;
+use crate::testing::macros::struct_with_counted_drop;
 
 #[bench]
 fn bench_push_back_100(b: &mut test::Bencher) {
@@ -1086,36 +1084,24 @@ fn test_clone_from() {
 
 #[test]
 fn test_vec_deque_truncate_drop() {
-    static mut DROPS: u32 = 0;
-    #[derive(Clone)]
-    struct Elem(#[allow(dead_code)] i32);
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
-    let v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
-    for push_front in 0..=v.len() {
-        let v = v.clone();
-        let mut tester = VecDeque::with_capacity(5);
-        for (index, elem) in v.into_iter().enumerate() {
+    const LEN: usize = 5;
+    for push_front in 0..=LEN {
+        let mut tester = VecDeque::with_capacity(LEN);
+        for index in 0..LEN {
             if index < push_front {
-                tester.push_front(elem);
+                tester.push_front(Elem);
             } else {
-                tester.push_back(elem);
+                tester.push_back(Elem);
             }
         }
-        assert_eq!(unsafe { DROPS }, 0);
+        assert_eq!(DROPS.get(), 0);
         tester.truncate(3);
-        assert_eq!(unsafe { DROPS }, 2);
+        assert_eq!(DROPS.get(), 2);
         tester.truncate(0);
-        assert_eq!(unsafe { DROPS }, 5);
-        unsafe {
-            DROPS = 0;
-        }
+        assert_eq!(DROPS.get(), 5);
+        DROPS.set(0);
     }
 }
 
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 7c71594c430..5197e40764b 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2877,6 +2877,7 @@ impl_to_string! {
     i32, u32,
     i64, u64,
     isize, usize,
+    i128, u128,
 }
 
 #[cfg(not(no_global_oom_handling))]
diff --git a/library/alloctests/testing/macros.rs b/library/alloctests/testing/macros.rs
new file mode 100644
index 00000000000..2433e53ca89
--- /dev/null
+++ b/library/alloctests/testing/macros.rs
@@ -0,0 +1,37 @@
+macro_rules! struct_with_counted_drop {
+    ($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident $( => $drop_stmt:expr )? ) => {
+        thread_local! {static $drop_counter: ::core::cell::Cell<u32> = ::core::cell::Cell::new(0);}
+
+        #[derive(Clone, Debug, PartialEq)]
+        struct $struct_name $(( $( $elt_ty ),+ ))?;
+
+        impl ::std::ops::Drop for $struct_name {
+            fn drop(&mut self) {
+                $drop_counter.set($drop_counter.get() + 1);
+
+                $($drop_stmt(self))?
+            }
+        }
+    };
+    ($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident[ $drop_key:expr,$key_ty:ty ] $( => $drop_stmt:expr )? ) => {
+        thread_local! {
+            static $drop_counter: ::core::cell::RefCell<::std::collections::HashMap<$key_ty, u32>> =
+                ::core::cell::RefCell::new(::std::collections::HashMap::new());
+        }
+
+        #[derive(Clone, Debug, PartialEq)]
+        struct $struct_name $(( $( $elt_ty ),+ ))?;
+
+        impl ::std::ops::Drop for $struct_name {
+            fn drop(&mut self) {
+                $drop_counter.with_borrow_mut(|counter| {
+                    *counter.entry($drop_key(self)).or_default() += 1;
+                });
+
+                $($drop_stmt(self))?
+            }
+        }
+    };
+}
+
+pub(crate) use struct_with_counted_drop;
diff --git a/library/alloctests/testing/mod.rs b/library/alloctests/testing/mod.rs
index c8457daf93e..66a4f6682b9 100644
--- a/library/alloctests/testing/mod.rs
+++ b/library/alloctests/testing/mod.rs
@@ -1,3 +1,4 @@
 pub(crate) mod crash_test;
+pub(crate) mod macros;
 pub(crate) mod ord_chaos;
 pub(crate) mod rng;
diff --git a/library/alloctests/tests/fmt.rs b/library/alloctests/tests/fmt.rs
index dbcf0c3a114..0989a56b554 100644
--- a/library/alloctests/tests/fmt.rs
+++ b/library/alloctests/tests/fmt.rs
@@ -1,6 +1,4 @@
 #![deny(warnings)]
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
 #![allow(unnecessary_transmutes)]
 
 use std::cell::RefCell;
@@ -285,19 +283,32 @@ fn test_format_args() {
     t!(s, "args were: hello world");
 }
 
+macro_rules! counter_fn {
+    ($name:ident) => {
+        fn $name() -> u32 {
+            thread_local! {static COUNTER: ::core::cell::Cell<u32> = ::core::cell::Cell::new(0);}
+
+            COUNTER.set(COUNTER.get() + 1);
+            COUNTER.get()
+        }
+    };
+}
+
 #[test]
 fn test_order() {
-    // Make sure format!() arguments are always evaluated in a left-to-right
-    // ordering
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
+    // Make sure format!() arguments are always evaluated in a left-to-right ordering
+    counter_fn!(count);
+
     assert_eq!(
-        format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()),
+        format!(
+            "{} {} {a} {b} {} {c}",
+            count(),
+            count(),
+            count(),
+            a = count(),
+            b = count(),
+            c = count()
+        ),
         "1 2 4 5 3 6".to_string()
     );
 }
@@ -306,14 +317,9 @@ fn test_order() {
 fn test_once() {
     // Make sure each argument are evaluated only once even though it may be
     // formatted multiple times
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
-    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string());
+    counter_fn!(count);
+
+    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", count(), a = count()), "1 1 1 2 2 2".to_string());
 }
 
 #[test]
diff --git a/library/alloctests/tests/num.rs b/library/alloctests/tests/num.rs
index 3c76e68c606..a169bbec8e0 100644
--- a/library/alloctests/tests/num.rs
+++ b/library/alloctests/tests/num.rs
@@ -52,6 +52,8 @@ int_to_s!(
     i32,
     test_i64_to_string,
     i64,
+    test_isize_to_string,
+    isize,
     test_i128_to_string,
     i128,
 );
@@ -64,6 +66,8 @@ uint_to_s!(
     u32,
     test_u64_to_string,
     u64,
+    test_usize_to_string,
+    usize,
     test_u128_to_string,
     u128,
 );
diff --git a/library/alloctests/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs
index 30275a5125e..08856e39ded 100644
--- a/library/alloctests/tests/testing/mod.rs
+++ b/library/alloctests/tests/testing/mod.rs
@@ -1,2 +1,4 @@
 #[path = "../../testing/crash_test.rs"]
 pub mod crash_test;
+#[path = "../../testing/macros.rs"]
+pub mod macros;
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs
index 51b49b8edb3..00f640cd17e 100644
--- a/library/alloctests/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -1,6 +1,3 @@
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
-
 use core::alloc::{Allocator, Layout};
 use core::num::NonZero;
 use core::ptr::NonNull;
@@ -20,6 +17,8 @@ use std::rc::Rc;
 use std::sync::atomic::{AtomicU32, Ordering};
 use std::vec::{Drain, IntoIter};
 
+use crate::testing::macros::struct_with_counted_drop;
+
 struct DropCounter<'a> {
     count: &'a mut u32,
 }
@@ -548,32 +547,25 @@ fn test_cmp() {
 
 #[test]
 fn test_vec_truncate_drop() {
-    static mut DROPS: u32 = 0;
-    struct Elem(#[allow(dead_code)] i32);
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem(i32), DROPS);
 
     let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
-    assert_eq!(unsafe { DROPS }, 0);
+
+    assert_eq!(DROPS.get(), 0);
     v.truncate(3);
-    assert_eq!(unsafe { DROPS }, 2);
+    assert_eq!(DROPS.get(), 2);
     v.truncate(0);
-    assert_eq!(unsafe { DROPS }, 5);
+    assert_eq!(DROPS.get(), 5);
 }
 
 #[test]
 #[should_panic]
 fn test_vec_truncate_fail() {
     struct BadElem(i32);
+
     impl Drop for BadElem {
         fn drop(&mut self) {
-            let BadElem(ref mut x) = *self;
-            if *x == 0xbadbeef {
+            if let BadElem(0xbadbeef) = self {
                 panic!("BadElem panic: 0xbadbeef")
             }
         }
@@ -812,22 +804,7 @@ fn test_drain_end_overflow() {
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_drain_leak() {
-    static mut DROPS: i32 = 0;
-
-    #[derive(Debug, PartialEq)]
-    struct D(u32, bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.1 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); });
 
     let mut v = vec![
         D(0, false),
@@ -844,7 +821,7 @@ fn test_drain_leak() {
     }))
     .ok();
 
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
     assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
 }
 
@@ -1057,27 +1034,13 @@ fn test_into_iter_clone() {
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_into_iter_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); });
 
     let v = vec![D(false), D(true), D(false)];
 
     catch_unwind(move || drop(v.into_iter())).ok();
 
-    assert_eq!(unsafe { DROPS }, 3);
+    assert_eq!(DROPS.get(), 3);
 }
 
 #[test]
@@ -1274,55 +1237,31 @@ fn test_from_iter_specialization_panic_during_iteration_drops() {
 
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#[allow(static_mut_refs)]
 fn test_from_iter_specialization_panic_during_drop_doesnt_leak() {
-    static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5];
-    static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2];
-
-    #[derive(Debug)]
-    struct Old(usize);
-
-    impl Drop for Old {
-        fn drop(&mut self) {
-            unsafe {
-                DROP_COUNTER_OLD[self.0] += 1;
-            }
-
-            if self.0 == 3 {
-                panic!();
-            }
-
-            println!("Dropped Old: {}", self.0);
-        }
-    }
-
-    #[derive(Debug)]
-    struct New(usize);
-
-    impl Drop for New {
-        fn drop(&mut self) {
-            unsafe {
-                DROP_COUNTER_NEW[self.0] += 1;
+    struct_with_counted_drop!(
+        Old(usize), DROP_COUNTER_OLD[|this: &Old| this.0, usize] =>
+            |this: &Old| {
+                if this.0 == 3 { panic!(); } println!("Dropped Old: {}", this.0)
             }
-
-            println!("Dropped New: {}", self.0);
-        }
-    }
+    );
+    struct_with_counted_drop!(
+        New(usize), DROP_COUNTER_NEW[|this: &New| this.0, usize] =>
+            |this: &New| println!("Dropped New: {}", this.0)
+    );
 
     let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
         let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)];
         let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::<Vec<_>>();
     }));
 
-    assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1);
-    assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1);
-    assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1);
-    assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1);
-    assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1);
+    DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
+    DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
+    DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&2), Some(&1)));
+    DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&3), Some(&1)));
+    DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&4), Some(&1)));
 
-    assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1);
-    assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1);
+    DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
+    DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
 }
 
 // regression test for issue #85322. Peekable previously implemented InPlaceIterable,
diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs
index b77ea3a312b..a82906d55e5 100644
--- a/library/alloctests/tests/vec_deque.rs
+++ b/library/alloctests/tests/vec_deque.rs
@@ -1,6 +1,3 @@
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
-
 use core::num::NonZero;
 use std::assert_matches::assert_matches;
 use std::collections::TryReserveErrorKind::*;
@@ -14,6 +11,7 @@ use Taggy::*;
 use Taggypar::*;
 
 use crate::hash;
+use crate::testing::macros::struct_with_counted_drop;
 
 #[test]
 fn test_simple() {
@@ -719,15 +717,7 @@ fn test_show() {
 
 #[test]
 fn test_drop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = VecDeque::new();
     ring.push_back(Elem);
@@ -736,20 +726,12 @@ fn test_drop() {
     ring.push_front(Elem);
     drop(ring);
 
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 fn test_drop_with_pop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = VecDeque::new();
     ring.push_back(Elem);
@@ -759,23 +741,15 @@ fn test_drop_with_pop() {
 
     drop(ring.pop_back());
     drop(ring.pop_front());
-    assert_eq!(unsafe { DROPS }, 2);
+    assert_eq!(DROPS.get(), 2);
 
     drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 fn test_drop_clear() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = VecDeque::new();
     ring.push_back(Elem);
@@ -783,30 +757,16 @@ fn test_drop_clear() {
     ring.push_back(Elem);
     ring.push_front(Elem);
     ring.clear();
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 
     drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_drop_panic() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
 
     let mut q = VecDeque::new();
     q.push_back(D(false));
@@ -820,7 +780,7 @@ fn test_drop_panic() {
 
     catch_unwind(move || drop(q)).ok();
 
-    assert_eq!(unsafe { DROPS }, 8);
+    assert_eq!(DROPS.get(), 8);
 }
 
 #[test]
@@ -1655,21 +1615,7 @@ fn test_try_rfold_moves_iter() {
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn truncate_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
 
     let mut q = VecDeque::new();
     q.push_back(D(false));
@@ -1683,27 +1629,13 @@ fn truncate_leak() {
 
     catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok();
 
-    assert_eq!(unsafe { DROPS }, 7);
+    assert_eq!(DROPS.get(), 7);
 }
 
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn truncate_front_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
 
     let mut q = VecDeque::new();
     q.push_back(D(false));
@@ -1717,28 +1649,13 @@ fn truncate_front_leak() {
 
     catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok();
 
-    assert_eq!(unsafe { DROPS }, 7);
+    assert_eq!(DROPS.get(), 7);
 }
 
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_drain_leak() {
-    static mut DROPS: i32 = 0;
-
-    #[derive(Debug, PartialEq)]
-    struct D(u32, bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.1 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); } );
 
     let mut v = VecDeque::new();
     v.push_back(D(4, false));
@@ -1754,10 +1671,10 @@ fn test_drain_leak() {
     }))
     .ok();
 
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
     assert_eq!(v.len(), 3);
     drop(v);
-    assert_eq!(unsafe { DROPS }, 7);
+    assert_eq!(DROPS.get(), 7);
 }
 
 #[test]
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index ce878f2da4b..13cd7f71094 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -565,123 +565,134 @@ mod imp {
 }
 impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
 
+const U128_MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for u128 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt_u128(*self, true, f)
+        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
+
+        f.pad_integral(true, "", self._fmt(&mut buf))
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for i128 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt_u128(self.unsigned_abs(), *self >= 0, f)
+        // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
+        // `U128_MAX_DEC_N`.
+        let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
+
+        let is_nonnegative = *self >= 0;
+        f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf))
     }
 }
 
-/// Format optimized for u128. Computation of 128 bits is limited by proccessing
-/// in batches of 16 decimals at a time.
-fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    // Optimize common-case zero, which would also need special treatment due to
-    // its "leading" zero.
-    if n == 0 {
-        return f.pad_integral(true, "", "0");
-    }
+impl u128 {
+    /// Format optimized for u128. Computation of 128 bits is limited by proccessing
+    /// in batches of 16 decimals at a time.
+    #[doc(hidden)]
+    #[unstable(
+        feature = "fmt_internals",
+        reason = "specialized method meant to only be used by `SpecToString` implementation",
+        issue = "none"
+    )]
+    pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
+        // Optimize common-case zero, which would also need special treatment due to
+        // its "leading" zero.
+        if self == 0 {
+            return "0";
+        }
 
-    // U128::MAX has 39 significant-decimals.
-    const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1;
-    // Buffer decimals with right alignment.
-    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
-
-    // Take the 16 least-significant decimals.
-    let (quot_1e16, mod_1e16) = div_rem_1e16(n);
-    let (mut remain, mut offset) = if quot_1e16 == 0 {
-        (mod_1e16, MAX_DEC_N)
-    } else {
-        // Write digits at buf[23..39].
-        enc_16lsd::<{ MAX_DEC_N - 16 }>(&mut buf, mod_1e16);
-
-        // Take another 16 decimals.
-        let (quot2, mod2) = div_rem_1e16(quot_1e16);
-        if quot2 == 0 {
-            (mod2, MAX_DEC_N - 16)
+        // Take the 16 least-significant decimals.
+        let (quot_1e16, mod_1e16) = div_rem_1e16(self);
+        let (mut remain, mut offset) = if quot_1e16 == 0 {
+            (mod_1e16, U128_MAX_DEC_N)
         } else {
-            // Write digits at buf[7..23].
-            enc_16lsd::<{ MAX_DEC_N - 32 }>(&mut buf, mod2);
-            // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
-            (quot2 as u64, MAX_DEC_N - 32)
-        }
-    };
+            // Write digits at buf[23..39].
+            enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16);
 
-    // Format per four digits from the lookup table.
-    while remain > 999 {
-        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
-        // and the while condition ensures at least 4 more decimals.
-        unsafe { core::hint::assert_unchecked(offset >= 4) }
-        // SAFETY: The offset counts down from its initial buf.len()
-        // without underflow due to the previous precondition.
-        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
-        offset -= 4;
+            // Take another 16 decimals.
+            let (quot2, mod2) = div_rem_1e16(quot_1e16);
+            if quot2 == 0 {
+                (mod2, U128_MAX_DEC_N - 16)
+            } else {
+                // Write digits at buf[7..23].
+                enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2);
+                // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
+                (quot2 as u64, U128_MAX_DEC_N - 32)
+            }
+        };
 
-        // pull two pairs
-        let quad = remain % 1_00_00;
-        remain /= 1_00_00;
-        let pair1 = (quad / 100) as usize;
-        let pair2 = (quad % 100) as usize;
-        buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
-        buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
-        buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
-        buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
-    }
+        // Format per four digits from the lookup table.
+        while remain > 999 {
+            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
+            // and the while condition ensures at least 4 more decimals.
+            unsafe { core::hint::assert_unchecked(offset >= 4) }
+            // SAFETY: The offset counts down from its initial buf.len()
+            // without underflow due to the previous precondition.
+            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+            offset -= 4;
+
+            // pull two pairs
+            let quad = remain % 1_00_00;
+            remain /= 1_00_00;
+            let pair1 = (quad / 100) as usize;
+            let pair2 = (quad % 100) as usize;
+            buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
+            buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
+            buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
+            buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+        }
 
-    // Format per two digits from the lookup table.
-    if remain > 9 {
-        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
-        // and the if condition ensures at least 2 more decimals.
-        unsafe { core::hint::assert_unchecked(offset >= 2) }
-        // SAFETY: The offset counts down from its initial buf.len()
-        // without underflow due to the previous precondition.
-        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
-        offset -= 2;
-
-        let pair = (remain % 100) as usize;
-        remain /= 100;
-        buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
-        buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
-    }
+        // Format per two digits from the lookup table.
+        if remain > 9 {
+            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
+            // and the if condition ensures at least 2 more decimals.
+            unsafe { core::hint::assert_unchecked(offset >= 2) }
+            // SAFETY: The offset counts down from its initial buf.len()
+            // without underflow due to the previous precondition.
+            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+            offset -= 2;
+
+            let pair = (remain % 100) as usize;
+            remain /= 100;
+            buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
+            buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
+        }
 
-    // Format the last remaining digit, if any.
-    if remain != 0 {
-        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
-        // and the if condition ensures (at least) 1 more decimals.
-        unsafe { core::hint::assert_unchecked(offset >= 1) }
-        // SAFETY: The offset counts down from its initial buf.len()
-        // without underflow due to the previous precondition.
-        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
-        offset -= 1;
-
-        // Either the compiler sees that remain < 10, or it prevents
-        // a boundary check up next.
-        let last = (remain & 15) as usize;
-        buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
-        // not used: remain = 0;
-    }
+        // Format the last remaining digit, if any.
+        if remain != 0 {
+            // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
+            // and the if condition ensures (at least) 1 more decimals.
+            unsafe { core::hint::assert_unchecked(offset >= 1) }
+            // SAFETY: The offset counts down from its initial buf.len()
+            // without underflow due to the previous precondition.
+            unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+            offset -= 1;
+
+            // Either the compiler sees that remain < 10, or it prevents
+            // a boundary check up next.
+            let last = (remain & 15) as usize;
+            buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
+            // not used: remain = 0;
+        }
 
-    // SAFETY: All buf content since offset is set.
-    let written = unsafe { buf.get_unchecked(offset..) };
-    // SAFETY: Writes use ASCII from the lookup table exclusively.
-    let as_str = unsafe {
-        str::from_utf8_unchecked(slice::from_raw_parts(
-            MaybeUninit::slice_as_ptr(written),
-            written.len(),
-        ))
-    };
-    f.pad_integral(is_nonnegative, "", as_str)
+        // SAFETY: All buf content since offset is set.
+        let written = unsafe { buf.get_unchecked(offset..) };
+        // SAFETY: Writes use ASCII from the lookup table exclusively.
+        unsafe {
+            str::from_utf8_unchecked(slice::from_raw_parts(
+                MaybeUninit::slice_as_ptr(written),
+                written.len(),
+            ))
+        }
+    }
 }
 
 /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
 /// 16 ]`.
-fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>; 39], n: u64) {
+fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
     // Consume the least-significant decimals from a working copy.
     let mut remain = n;
 
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index 7fd8d3e5b53..fb858a05726 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -183,38 +183,6 @@ impl Argument<'_> {
             ArgumentType::Placeholder { .. } => None,
         }
     }
-
-    /// Used by `format_args` when all arguments are gone after inlining,
-    /// when using `&[]` would incorrectly allow for a bigger lifetime.
-    ///
-    /// This fails without format argument inlining, and that shouldn't be different
-    /// when the argument is inlined:
-    ///
-    /// ```compile_fail,E0716
-    /// let f = format_args!("{}", "a");
-    /// println!("{f}");
-    /// ```
-    #[inline]
-    pub const fn none() -> [Self; 0] {
-        []
-    }
-}
-
-/// This struct represents the unsafety of constructing an `Arguments`.
-/// It exists, rather than an unsafe function, in order to simplify the expansion
-/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
-#[lang = "format_unsafe_arg"]
-pub struct UnsafeArg {
-    _private: (),
-}
-
-impl UnsafeArg {
-    /// See documentation where `UnsafeArg` is required to know when it is safe to
-    /// create and use `UnsafeArg`.
-    #[inline]
-    pub const unsafe fn new() -> Self {
-        Self { _private: () }
-    }
 }
 
 /// Used by the format_args!() macro to create a fmt::Arguments object.
@@ -248,8 +216,7 @@ impl<'a> Arguments<'a> {
 
     /// Specifies nonstandard formatting parameters.
     ///
-    /// An `rt::UnsafeArg` is required because the following invariants must be held
-    /// in order for this function to be safe:
+    /// SAFETY: the following invariants must be held:
     /// 1. The `pieces` slice must be at least as long as `fmt`.
     /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`.
     /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`.
@@ -261,11 +228,10 @@ impl<'a> Arguments<'a> {
     /// const _: () = if false { panic!("a {:1}", "a") };
     /// ```
     #[inline]
-    pub fn new_v1_formatted(
+    pub unsafe fn new_v1_formatted(
         pieces: &'a [&'static str],
         args: &'a [rt::Argument<'a>],
         fmt: &'a [rt::Placeholder],
-        _unsafe_arg: rt::UnsafeArg,
     ) -> Arguments<'a> {
         Arguments { pieces, fmt: Some(fmt), args }
     }
diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs
index e0c0fe4790c..b1ab443aa6e 100644
--- a/library/coretests/tests/atomic.rs
+++ b/library/coretests/tests/atomic.rs
@@ -228,24 +228,20 @@ fn static_init() {
 }
 
 #[test]
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#[allow(static_mut_refs)]
 fn atomic_access_bool() {
-    static mut ATOMIC: AtomicBool = AtomicBool::new(false);
-
-    unsafe {
-        assert_eq!(*ATOMIC.get_mut(), false);
-        ATOMIC.store(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_or(false, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_and(false, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), false);
-        ATOMIC.fetch_nand(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_xor(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), false);
-    }
+    let mut atom = AtomicBool::new(false);
+
+    assert_eq!(*atom.get_mut(), false);
+    atom.store(true, SeqCst);
+    assert_eq!(*atom.get_mut(), true);
+    atom.fetch_or(false, SeqCst);
+    assert_eq!(*atom.get_mut(), true);
+    atom.fetch_and(false, SeqCst);
+    assert_eq!(*atom.get_mut(), false);
+    atom.fetch_nand(true, SeqCst);
+    assert_eq!(*atom.get_mut(), true);
+    atom.fetch_xor(true, SeqCst);
+    assert_eq!(*atom.get_mut(), false);
 }
 
 #[test]
diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs
index d9060fe903d..16f116d2590 100644
--- a/library/coretests/tests/fmt/mod.rs
+++ b/library/coretests/tests/fmt/mod.rs
@@ -3,6 +3,21 @@ mod float;
 mod num;
 
 #[test]
+fn test_lifetime() {
+    // Trigger all different forms of expansion,
+    // and check that each of them can be stored as a variable.
+    let a = format_args!("hello");
+    let a = format_args!("hello {a}");
+    let a = format_args!("hello {a:1}");
+    let a = format_args!("hello {a} {a:?}");
+    assert_eq!(a.to_string(), "hello hello hello hello hello hello hello");
+
+    // Without arguments, it should also work in consts.
+    const A: std::fmt::Arguments<'static> = format_args!("hello");
+    assert_eq!(A.to_string(), "hello");
+}
+
+#[test]
 fn test_format_flags() {
     // No residual flags left by pointer formatting
     let p = "".as_ptr();
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 5802b653965..78c957270c4 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -116,6 +116,9 @@ pub mod prelude {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
     #[doc(no_inline)]
+    #[unstable(feature = "unix_send_signal", issue = "141975")]
+    pub use super::process::ChildExt;
+    #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::process::{CommandExt, ExitStatusExt};
     #[doc(no_inline)]
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 57ce3c5a4bf..3f4fe2e56ec 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -378,6 +378,41 @@ impl ExitStatusExt for process::ExitStatusError {
     }
 }
 
+#[unstable(feature = "unix_send_signal", issue = "141975")]
+pub trait ChildExt: Sealed {
+    /// Sends a signal to a child process.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the signal is invalid. The integer values associated
+    /// with signals are implemenation-specific, so it's encouraged to use a crate that provides
+    /// posix bindings.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(unix_send_signal)]
+    ///
+    /// use std::{io, os::unix::process::ChildExt, process::{Command, Stdio}};
+    ///
+    /// use libc::SIGTERM;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let child = Command::new("cat").stdin(Stdio::piped()).spawn()?;
+    ///     child.send_signal(SIGTERM)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    fn send_signal(&self, signal: i32) -> io::Result<()>;
+}
+
+#[unstable(feature = "unix_send_signal", issue = "141975")]
+impl ChildExt for process::Child {
+    fn send_signal(&self, signal: i32) -> io::Result<()> {
+        self.handle.send_signal(signal)
+    }
+}
+
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawFd for process::Stdio {
     #[inline]
diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs
index 2d949ec9e91..47e9a616bfd 100644
--- a/library/std/src/sys/pal/unix/linux/pidfd.rs
+++ b/library/std/src/sys/pal/unix/linux/pidfd.rs
@@ -13,11 +13,15 @@ pub(crate) struct PidFd(FileDesc);
 
 impl PidFd {
     pub fn kill(&self) -> io::Result<()> {
+        self.send_signal(libc::SIGKILL)
+    }
+
+    pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
         cvt(unsafe {
             libc::syscall(
                 libc::SYS_pidfd_send_signal,
                 self.0.as_raw_fd(),
-                libc::SIGKILL,
+                signal,
                 crate::ptr::null::<()>(),
                 0,
             )
diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs
index 017ab91797c..d71be510b6a 100644
--- a/library/std/src/sys/process/unix/fuchsia.rs
+++ b/library/std/src/sys/process/unix/fuchsia.rs
@@ -152,6 +152,11 @@ impl Process {
         Ok(())
     }
 
+    pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
+        // Fuchsia doesn't have a direct equivalent for signals
+        unimplemented!()
+    }
+
     pub fn wait(&mut self) -> io::Result<ExitStatus> {
         let mut proc_info: zx_info_process_t = Default::default();
         let mut actual: size_t = 0;
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 4f595ac9a1c..1fe80c13b81 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -963,9 +963,13 @@ impl Process {
         self.pid as u32
     }
 
-    pub fn kill(&mut self) -> io::Result<()> {
+    pub fn kill(&self) -> io::Result<()> {
+        self.send_signal(libc::SIGKILL)
+    }
+
+    pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
         // If we've already waited on this process then the pid can be recycled
-        // and used for another process, and we probably shouldn't be killing
+        // and used for another process, and we probably shouldn't be signaling
         // random processes, so return Ok because the process has exited already.
         if self.status.is_some() {
             return Ok(());
@@ -973,9 +977,9 @@ impl Process {
         #[cfg(target_os = "linux")]
         if let Some(pid_fd) = self.pidfd.as_ref() {
             // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
-            return pid_fd.kill();
+            return pid_fd.send_signal(signal);
         }
-        cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
+        cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
     }
 
     pub fn wait(&mut self) -> io::Result<ExitStatus> {
diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs
index e86561a5c5c..87403cd50f8 100644
--- a/library/std/src/sys/process/unix/unsupported.rs
+++ b/library/std/src/sys/process/unix/unsupported.rs
@@ -40,7 +40,11 @@ impl Process {
         0
     }
 
-    pub fn kill(&mut self) -> io::Result<()> {
+    pub fn kill(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
         unsupported()
     }
 
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index f33b4a375da..51ae8c56bdb 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -146,14 +146,18 @@ impl Process {
         self.pid as u32
     }
 
-    pub fn kill(&mut self) -> io::Result<()> {
+    pub fn kill(&self) -> io::Result<()> {
+        self.send_signal(libc::SIGKILL)
+    }
+
+    pub fn send_signal(&self, signal: i32) -> io::Result<()> {
         // If we've already waited on this process then the pid can be recycled
         // and used for another process, and we probably shouldn't be killing
         // random processes, so return Ok because the process has exited already.
         if self.status.is_some() {
             Ok(())
         } else {
-            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
+            cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
         }
     }
 
diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs
index e0e32d31353..d9810e899a0 100644
--- a/src/bootstrap/build.rs
+++ b/src/bootstrap/build.rs
@@ -1,6 +1,7 @@
 use std::env;
 
 fn main() {
+    // this is needed because `HOST` is only available to build scripts.
     let host = env::var("HOST").unwrap();
     println!("cargo:rerun-if-changed=build.rs");
     println!("cargo:rustc-env=BUILD_TRIPLE={host}");
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 0088e851d39..53a5c6b282f 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1129,6 +1129,7 @@ macro_rules! tool_extended {
             tool_name: $tool_name:expr,
             stable: $stable:expr
             $( , add_bins_to_sysroot: $add_bins_to_sysroot:expr )?
+            $( , add_features: $add_features:expr )?
             $( , )?
         }
     ) => {
@@ -1168,6 +1169,7 @@ macro_rules! tool_extended {
                     $tool_name,
                     $path,
                     None $( .or(Some(&$add_bins_to_sysroot)) )?,
+                    None $( .or(Some($add_features)) )?,
                 )
             }
         }
@@ -1205,7 +1207,13 @@ fn run_tool_build_step(
     tool_name: &'static str,
     path: &'static str,
     add_bins_to_sysroot: Option<&[&str]>,
+    add_features: Option<fn(&Builder<'_>, TargetSelection, &mut Vec<String>)>,
 ) -> ToolBuildResult {
+    let mut extra_features = Vec::new();
+    if let Some(func) = add_features {
+        func(builder, target, &mut extra_features);
+    }
+
     let ToolBuildResult { tool_path, build_compiler, target_compiler } =
         builder.ensure(ToolBuild {
             compiler,
@@ -1213,7 +1221,7 @@ fn run_tool_build_step(
             tool: tool_name,
             mode: Mode::ToolRustc,
             path,
-            extra_features: vec![],
+            extra_features,
             source_type: SourceType::InTree,
             allow_features: "",
             cargo_args: vec![],
@@ -1256,7 +1264,12 @@ tool_extended!(Clippy {
     path: "src/tools/clippy",
     tool_name: "clippy-driver",
     stable: true,
-    add_bins_to_sysroot: ["clippy-driver"]
+    add_bins_to_sysroot: ["clippy-driver"],
+    add_features: |builder, target, features| {
+        if builder.config.jemalloc(target) {
+            features.push("jemalloc".to_string());
+        }
+    }
 });
 tool_extended!(Miri {
     path: "src/tools/miri",
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 6268a2b59d6..f1af2b285a2 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -9,6 +9,7 @@ use crate::Flags;
 use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::config::Config;
 use crate::utils::cache::ExecutedStep;
+use crate::utils::helpers::get_host_target;
 use crate::utils::tests::git::{GitCtx, git_test};
 
 static TEST_TRIPLE_1: &str = "i686-unknown-haiku";
@@ -1236,29 +1237,48 @@ fn any_debug() {
 /// The staging tests use insta for snapshot testing.
 /// See bootstrap's README on how to bless the snapshots.
 mod staging {
+    use crate::Build;
+    use crate::core::builder::Builder;
     use crate::core::builder::tests::{
         TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build,
     };
+    use crate::utils::tests::{ConfigBuilder, TestCtx};
 
     #[test]
     fn build_compiler_stage_1() {
-        let mut cache = run_build(
-            &["compiler".into()],
-            configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
-        );
-        let steps = cache.into_executed_steps();
-        insta::assert_snapshot!(render_steps(&steps), @r"
-        [build] rustc 0 <target1> -> std 0 <target1>
-        [build] llvm <target1>
-        [build] rustc 0 <target1> -> rustc 1 <target1>
-        [build] rustc 0 <target1> -> rustc 1 <target1>
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("build")
+                .path("compiler")
+                .stage(1)
+                .get_steps(), @r"
+        [build] rustc 0 <host> -> std 0 <host>
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
         ");
     }
+
+    impl ConfigBuilder {
+        fn get_steps(self) -> String {
+            let config = self.create_config();
+
+            let kind = config.cmd.kind();
+            let build = Build::new(config);
+            let builder = Builder::new(&build);
+            builder.run_step_descriptions(&Builder::get_step_descriptions(kind), &builder.paths);
+            render_steps(&builder.cache.into_executed_steps())
+        }
+    }
 }
 
 /// Renders the executed bootstrap steps for usage in snapshot tests with insta.
 /// Only renders certain important steps.
 /// Each value in `steps` should be a tuple of (Step, step output).
+///
+/// The arrow in the rendered output (`X -> Y`) means `X builds Y`.
+/// This is similar to the output printed by bootstrap to stdout, but here it is
+/// generated purely for the purpose of tests.
 fn render_steps(steps: &[ExecutedStep]) -> String {
     steps
         .iter()
@@ -1275,18 +1295,17 @@ fn render_steps(steps: &[ExecutedStep]) -> String {
             }
             let stage =
                 if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() };
-            write!(record, "{} {stage}<{}>", metadata.name, metadata.target);
+            write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target));
             Some(record)
         })
-        .map(|line| {
-            line.replace(TEST_TRIPLE_1, "target1")
-                .replace(TEST_TRIPLE_2, "target2")
-                .replace(TEST_TRIPLE_3, "target3")
-        })
         .collect::<Vec<_>>()
         .join("\n")
 }
 
+fn normalize_target(target: TargetSelection) -> String {
+    target.to_string().replace(&get_host_target().to_string(), "host")
+}
+
 fn render_compiler(compiler: Compiler) -> String {
-    format!("rustc {} <{}>", compiler.stage, compiler.host)
+    format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host))
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index ff0fda2d2e6..d3393afcae0 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -49,7 +49,7 @@ use crate::core::download::is_download_ci_available;
 use crate::utils::channel;
 use crate::utils::exec::command;
 use crate::utils::execution_context::ExecutionContext;
-use crate::utils::helpers::exe;
+use crate::utils::helpers::{exe, get_host_target};
 use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t};
 
 /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic.
@@ -349,7 +349,7 @@ impl Config {
             stderr_is_tty: std::io::stderr().is_terminal(),
 
             // set by build.rs
-            host_target: TargetSelection::from_user(env!("BUILD_TRIPLE")),
+            host_target: get_host_target(),
 
             src: {
                 let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 2f18fb60318..3c5f612daa7 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -178,6 +178,11 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
     }
 }
 
+/// Return the host target on which we are currently running.
+pub fn get_host_target() -> TargetSelection {
+    TargetSelection::from_user(env!("BUILD_TRIPLE"))
+}
+
 /// Rename a file if from and to are in the same filesystem or
 /// copy and remove the file otherwise
 pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 73c500f6e36..91877fd0da4 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -1,3 +1,74 @@
 //! This module contains shared utilities for bootstrap tests.
 
+use std::path::{Path, PathBuf};
+use std::thread;
+
+use tempfile::TempDir;
+
+use crate::core::builder::Builder;
+use crate::core::config::DryRun;
+use crate::{Build, Config, Flags, t};
+
 pub mod git;
+
+/// Holds temporary state of a bootstrap test.
+/// Right now it is only used to redirect the build directory of the bootstrap
+/// invocation, in the future it would be great if we could actually execute
+/// the whole test with this directory set as the workdir.
+pub struct TestCtx {
+    directory: TempDir,
+}
+
+impl TestCtx {
+    pub fn new() -> Self {
+        let directory = TempDir::new().expect("cannot create temporary directory");
+        eprintln!("Running test in {}", directory.path().display());
+        Self { directory }
+    }
+
+    /// Starts a new invocation of bootstrap that executes `kind` as its top level command
+    /// (i.e. `x <kind>`). Returns a builder that configures the created config through CLI flags.
+    pub fn config(&self, kind: &str) -> ConfigBuilder {
+        ConfigBuilder::from_args(&[kind], self.directory.path().to_owned())
+    }
+}
+
+/// Used to configure an invocation of bootstrap.
+/// Currently runs in the rustc checkout, long-term it should be switched
+/// to run in a (cache-primed) temporary directory instead.
+pub struct ConfigBuilder {
+    args: Vec<String>,
+    directory: PathBuf,
+}
+
+impl ConfigBuilder {
+    fn from_args(args: &[&str], directory: PathBuf) -> Self {
+        Self { args: args.iter().copied().map(String::from).collect(), directory }
+    }
+
+    pub fn path(mut self, path: &str) -> Self {
+        self.args.push(path.to_string());
+        self
+    }
+
+    pub fn stage(mut self, stage: u32) -> Self {
+        self.args.push("--stage".to_string());
+        self.args.push(stage.to_string());
+        self
+    }
+
+    pub fn create_config(mut self) -> Config {
+        // Run in dry-check, otherwise the test would be too slow
+        self.args.push("--dry-run".to_string());
+
+        // Ignore submodules
+        self.args.push("--set".to_string());
+        self.args.push("build.submodules=false".to_string());
+
+        // Do not mess with the local rustc checkout build directory
+        self.args.push("--build-dir".to_string());
+        self.args.push(self.directory.join("build").display().to_string());
+
+        Config::parse(Flags::parse(&self.args))
+    }
+}
diff --git a/src/doc/book b/src/doc/book
-Subproject 4433c9f0cad8460bee05ede040587f8a1fa3f1d
+Subproject 8a6d44e45b7b564eeb6bae30507e1fbac439d72
diff --git a/src/doc/reference b/src/doc/reference
-Subproject d4c66b346f4b72d29e70390a3fa3ea7d4e064db
+Subproject 50fc1628f36563958399123829c73755fa7a842
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 9baa9e863116cb9524a177d5a5c475baac18928
+Subproject 05c7d8bae65f23a1837430c5a19be129d414f5e
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 86d35b31498..30ba3070e1f 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-14346303d760027e53214e705109a62c0f00b214
+d1d8e386c5e84c4ba857f56c3291f73c27e2d62a
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index cba8eac617d..7f2f32c62ff 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -101,6 +101,8 @@
 	- [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md)
 	- [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md)
 	- [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md)
+- [GPU offload internals](./offload/internals.md)
+    - [Installation](./offload/installation.md)
 - [Autodiff internals](./autodiff/internals.md)
     - [Installation](./autodiff/installation.md)
     - [How to debug](./autodiff/debugging.md)
@@ -121,8 +123,9 @@
     - [Feature gate checking](./feature-gate-ck.md)
     - [Lang Items](./lang-items.md)
 - [The HIR (High-level IR)](./hir.md)
-    - [Lowering AST to HIR](./ast-lowering.md)
-    - [Debugging](./hir-debugging.md)
+    - [Lowering AST to HIR](./hir/lowering.md)
+    - [Ambig/Unambig Types and Consts](./hir/ambig-unambig-ty-and-consts.md)
+    - [Debugging](./hir/debugging.md)
 - [The THIR (Typed High-level IR)](./thir.md)
 - [The MIR (Mid-level IR)](./mir/index.md)
     - [MIR construction](./mir/construction.md)
@@ -181,7 +184,7 @@
         - [Significant changes and quirks](./solve/significant-changes.md)
     - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)
 - [Type checking](./type-checking.md)
-    - [Method Lookup](./method-lookup.md)
+    - [Method lookup](./method-lookup.md)
     - [Variance](./variance.md)
     - [Coherence checking](./coherence.md)
     - [Opaque types](./opaque-types-type-alias-impl-trait.md)
@@ -189,7 +192,7 @@
         - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md)
         - [Region inference restrictions][opaque-infer]
 - [Const condition checking](./effects.md)
-- [Pattern and Exhaustiveness Checking](./pat-exhaustive-checking.md)
+- [Pattern and exhaustiveness checking](./pat-exhaustive-checking.md)
 - [Unsafety checking](./unsafety-checking.md)
 - [MIR dataflow](./mir/dataflow.md)
 - [Drop elaboration](./mir/drop-elaboration.md)
@@ -209,7 +212,7 @@
 - [Closure capture inference](./closure.md)
 - [Async closures/"coroutine-closures"](coroutine-closures.md)
 
-# MIR to Binaries
+# MIR to binaries
 
 - [Prologue](./part-5-intro.md)
 - [MIR optimizations](./mir/optimizations.md)
@@ -218,15 +221,15 @@
     - [Interpreter](./const-eval/interpret.md)
 - [Monomorphization](./backend/monomorph.md)
 - [Lowering MIR](./backend/lowering-mir.md)
-- [Code Generation](./backend/codegen.md)
+- [Code generation](./backend/codegen.md)
     - [Updating LLVM](./backend/updating-llvm.md)
     - [Debugging LLVM](./backend/debugging.md)
     - [Backend Agnostic Codegen](./backend/backend-agnostic.md)
-    - [Implicit Caller Location](./backend/implicit-caller-location.md)
-- [Libraries and Metadata](./backend/libs-and-metadata.md)
-- [Profile-guided Optimization](./profile-guided-optimization.md)
-- [LLVM Source-Based Code Coverage](./llvm-coverage-instrumentation.md)
-- [Sanitizers Support](./sanitizers.md)
+    - [Implicit caller location](./backend/implicit-caller-location.md)
+- [Libraries and metadata](./backend/libs-and-metadata.md)
+- [Profile-guided optimization](./profile-guided-optimization.md)
+- [LLVM source-based code coverage](./llvm-coverage-instrumentation.md)
+- [Sanitizers support](./sanitizers.md)
 - [Debugging support in the Rust compiler](./debugging-support-in-rustc.md)
 
 ---
diff --git a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md
index 17158497d59..c5ee00813a3 100644
--- a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md
+++ b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md
@@ -1,4 +1,4 @@
-# Implicit Caller Location
+# Implicit caller location
 
 <!-- toc -->
 
@@ -8,7 +8,7 @@ adds the [`#[track_caller]`][attr-reference] attribute for functions, the
 [`caller_location`][intrinsic] intrinsic, and the stabilization-friendly
 [`core::panic::Location::caller`][wrapper] wrapper.
 
-## Motivating Example
+## Motivating example
 
 Take this example program:
 
@@ -39,7 +39,7 @@ These error messages are achieved through a combination of changes to `panic!` i
 of `core::panic::Location::caller` and a number of `#[track_caller]` annotations in the standard
 library which propagate caller information.
 
-## Reading Caller Location
+## Reading caller location
 
 Previously, `panic!` made use of the `file!()`, `line!()`, and `column!()` macros to construct a
 [`Location`] pointing to where the panic occurred. These macros couldn't be given an overridden
@@ -51,7 +51,7 @@ was expanded. This function is itself annotated with `#[track_caller]` and wraps
 [`caller_location`][intrinsic] compiler intrinsic implemented by rustc. This intrinsic is easiest
 explained in terms of how it works in a `const` context.
 
-## Caller Location in `const`
+## Caller location in `const`
 
 There are two main phases to returning the caller location in a const context: walking up the stack
 to find the right location and allocating a const value to return.
@@ -138,7 +138,7 @@ fn main() {
 }
 ```
 
-### Dynamic Dispatch
+### Dynamic dispatch
 
 In codegen contexts we have to modify the callee ABI to pass this information down the stack, but
 the attribute expressly does *not* modify the type of the function. The ABI change must be
@@ -156,7 +156,7 @@ probably the best we can do without modifying fully-stabilized type signatures.
 > whether we'll be called in a const context (safe to ignore shim) or in a codegen context (unsafe
 > to ignore shim). Even if we did know, the results from const and codegen contexts must agree.
 
-## The Attribute
+## The attribute
 
 The `#[track_caller]` attribute is checked alongside other codegen attributes to ensure the
 function:
diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
index eeb2af5e6bc..aa1d644703a 100644
--- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
+++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
@@ -1,4 +1,4 @@
-# Libraries and Metadata
+# Libraries and metadata
 
 When the compiler sees a reference to an external crate, it needs to load some
 information about that crate. This chapter gives an overview of that process,
diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md
index 8d323ba9646..e11a2cd8ee5 100644
--- a/src/doc/rustc-dev-guide/src/building/new-target.md
+++ b/src/doc/rustc-dev-guide/src/building/new-target.md
@@ -174,8 +174,8 @@ compiler, you can use it instead of the JSON file for both arguments.
 ## Promoting a target from tier 2 (target) to tier 2 (host)
 
 There are two levels of tier 2 targets:
-  a) Targets that are only cross-compiled (`rustup target add`)
-  b) Targets that [have a native toolchain][tier2-native] (`rustup toolchain install`)
+- Targets that are only cross-compiled (`rustup target add`)
+- Targets that [have a native toolchain][tier2-native] (`rustup toolchain install`)
 
 [tier2-native]: https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html#tier-2-with-host-tools
 
diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md
index 0575de642ee..46d74b96734 100644
--- a/src/doc/rustc-dev-guide/src/contributing.md
+++ b/src/doc/rustc-dev-guide/src/contributing.md
@@ -364,7 +364,7 @@ To find documentation-related issues, use the [A-docs label].
 
 You can find documentation style guidelines in [RFC 1574].
 
-To build the standard library documentation, use `x doc --stage 0 library --open`.
+To build the standard library documentation, use `x doc --stage 1 library --open`.
 To build the documentation for a book (e.g. the unstable book), use `x doc src/doc/unstable-book.`
 Results should appear in `build/host/doc`, as well as automatically open in your default browser.
 See [Building Documentation](./building/compiler-documenting.md#building-documentation) for more
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index 01e59c91904..33f5441d36e 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -553,7 +553,7 @@ compiler](#linting-early-in-the-compiler).
 
 
 [AST nodes]: the-parser.md
-[AST lowering]: ast-lowering.md
+[AST lowering]: ./hir/lowering.md
 [HIR nodes]: hir.md
 [MIR nodes]: mir/index.md
 [macro expansion]: macro-expansion.md
diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md
index 0c1c9941572..72fb1070157 100644
--- a/src/doc/rustc-dev-guide/src/hir.md
+++ b/src/doc/rustc-dev-guide/src/hir.md
@@ -5,7 +5,7 @@
 The HIR – "High-Level Intermediate Representation" – is the primary IR used
 in most of rustc. It is a compiler-friendly representation of the abstract
 syntax tree (AST) that is generated after parsing, macro expansion, and name
-resolution (see [Lowering](./ast-lowering.html) for how the HIR is created).
+resolution (see [Lowering](./hir/lowering.md) for how the HIR is created).
 Many parts of HIR resemble Rust surface syntax quite closely, with
 the exception that some of Rust's expression forms have been desugared away.
 For example, `for` loops are converted into a `loop` and do not appear in
diff --git a/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md
new file mode 100644
index 00000000000..709027883ae
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/hir/ambig-unambig-ty-and-consts.md
@@ -0,0 +1,63 @@
+# Ambig/Unambig Types and Consts
+
+Types and Consts args in the HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where
+it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to
+parse.
+
+```rust
+fn func<T, const N: usize>(arg: T) {
+    //                           ^ Unambig type position
+    let a: _ = arg; 
+    //     ^ Unambig type position
+
+    func::<T, N>(arg);
+    //     ^  ^
+    //     ^^^^ Ambig position 
+
+    let _: [u8; 10];
+    //      ^^  ^^ Unambig const position
+    //      ^^ Unambig type position
+}
+
+```
+
+Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. Single segment paths are always represented as types in the AST but may get resolved to a const parameter during name resolution, then lowered to a const argument during ast-lowering. The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. For example, in `Foo<_>` it is not clear whether the `_` argument is an inferred type argument, or an inferred const argument.
+
+In unambig positions, inferred arguments are represented with [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively.
+In ambig positions, inferred arguments are represented with `hir::GenericArg::Infer`.
+
+A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR:
+1. In unambig type position as a `hir::TyKind::Infer`
+2. In unambig const arg position as a `hir::ConstArgKind::Infer`
+3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty]
+4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const]
+5. In an ambig position as a [`GenericArg::Infer`][generic_arg_infer]
+
+Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position. 
+
+This has a few failure modes:
+- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident.
+- People may write visitors which check for `hir::TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident.
+- People may write visitors which check for `GenerArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenerigArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`.
+- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa).
+
+To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system:
+
+1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `hir::Ty<AmbigArg>` and `hir::Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position.
+
+2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method.
+
+This has a number of benefits:
+- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments
+- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong 
+- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases
+
+[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer
+[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer
+[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type
+[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const
+[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer
+[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html
+[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty
+[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg
+[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/hir-debugging.md b/src/doc/rustc-dev-guide/src/hir/debugging.md
index 5a0bda20842..5a0bda20842 100644
--- a/src/doc/rustc-dev-guide/src/hir-debugging.md
+++ b/src/doc/rustc-dev-guide/src/hir/debugging.md
diff --git a/src/doc/rustc-dev-guide/src/ast-lowering.md b/src/doc/rustc-dev-guide/src/hir/lowering.md
index 033fd4b76f2..02c69b8609f 100644
--- a/src/doc/rustc-dev-guide/src/ast-lowering.md
+++ b/src/doc/rustc-dev-guide/src/hir/lowering.md
@@ -1,6 +1,6 @@
 # AST lowering
 
-The AST lowering step converts AST to [HIR](hir.html).
+The AST lowering step converts AST to [HIR](../hir.md).
 This means many structures are removed if they are irrelevant
 for type analysis or similar syntax agnostic analyses. Examples
 of such structures include but are not limited to
diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md
index 6bc21b6deeb..28e0e7a908d 100644
--- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md
+++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md
@@ -1,4 +1,4 @@
-# LLVM Source-Based Code Coverage
+# LLVM source-based code coverage
 
 <!-- toc -->
 
diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md
new file mode 100644
index 00000000000..2536af09a23
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/offload/installation.md
@@ -0,0 +1,71 @@
+# Installation
+
+In the future, `std::offload` should become available in nightly builds for users. For now, everyone still needs to build rustc from source. 
+
+## Build instructions
+
+First you need to clone and configure the Rust repository:
+```bash
+git clone --depth=1 git@github.com:rust-lang/rust.git
+cd rust
+./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-offload --enable-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
+```
+
+Afterwards you can build rustc using:
+```bash
+./x.py build --stage 1 library
+```
+
+Afterwards rustc toolchain link will allow you to use it through cargo:
+```
+rustup toolchain link offload build/host/stage1
+rustup toolchain install nightly # enables -Z unstable-options
+```
+
+
+
+## Build instruction for LLVM itself
+```bash
+git clone --depth=1 git@github.com:llvm/llvm-project.git 
+cd llvm-project
+mkdir build
+cd build
+cmake -G Ninja ../llvm -DLLVM_TARGETS_TO_BUILD="host,AMDGPU,NVPTX" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_ENABLE_RUNTIMES="offload,openmp" -DLLVM_ENABLE_PLUGINS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=.
+ninja
+ninja install
+```
+This gives you a working LLVM build.
+
+
+## Testing
+run
+```
+./x.py test --stage 1 tests/codegen/gpu_offload
+```
+
+## Usage
+It is important to use a clang compiler build on the same llvm as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible.
+```
+/absolute/path/to/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc --edition=2024 --crate-type cdylib src/main.rs --emit=llvm-ir  -O -C lto=fat -Cpanic=abort -Zoffload=Enable
+/absolute/path/to/rust/build/x86_64-unknown-linux-gnu/llvm/bin/clang++ -fopenmp --offload-arch=native -g  -O3 main.ll -o main -save-temps
+LIBOMPTARGET_INFO=-1  ./main
+```
+The first step will generate a `main.ll` file, which has enough instructions to cause the offload runtime to move data to and from a gpu.
+The second step will use clang as the compilation driver to compile our IR file down to a working binary. Only a very small Rust subset will work out of the box here, unless
+you use features like build-std, which are not covered by this guide. Look at the codegen test to get a feeling for how to write a working example.
+In the last step you can run your binary, if all went well you will see a data transfer being reported:
+```
+omptarget device 0 info: Entering OpenMP data region with being_mapper at unknown:0:0 with 1 arguments:
+omptarget device 0 info: tofrom(unknown)[1024]
+omptarget device 0 info: Creating new map entry with HstPtrBase=0x00007fffffff9540, HstPtrBegin=0x00007fffffff9540, TgtAllocBegin=0x0000155547200000, TgtPtrBegin=0x0000155547200000, Size=1024, DynRefCount=1, HoldRefCount=0, Name=unknown
+omptarget device 0 info: Copying data from host to device, HstPtr=0x00007fffffff9540, TgtPtr=0x0000155547200000, Size=1024, Name=unknown
+omptarget device 0 info: OpenMP Host-Device pointer mappings after block at unknown:0:0:
+omptarget device 0 info: Host Ptr           Target Ptr         Size (B) DynRefCount HoldRefCount Declaration
+omptarget device 0 info: 0x00007fffffff9540 0x0000155547200000 1024     1           0            unknown at unknown:0:0
+// some other output
+omptarget device 0 info: Exiting OpenMP data region with end_mapper at unknown:0:0 with 1 arguments:
+omptarget device 0 info: tofrom(unknown)[1024]
+omptarget device 0 info: Mapping exists with HstPtrBegin=0x00007fffffff9540, TgtPtrBegin=0x0000155547200000, Size=1024, DynRefCount=0 (decremented, delayed deletion), HoldRefCount=0
+omptarget device 0 info: Copying data from device to host, TgtPtr=0x0000155547200000, HstPtr=0x00007fffffff9540, Size=1024, Name=unknown
+omptarget device 0 info: Removing map entry with HstPtrBegin=0x00007fffffff9540, TgtPtrBegin=0x0000155547200000, Size=1024, Name=unknown
+```
diff --git a/src/doc/rustc-dev-guide/src/offload/internals.md b/src/doc/rustc-dev-guide/src/offload/internals.md
new file mode 100644
index 00000000000..28857a6e78b
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/offload/internals.md
@@ -0,0 +1,9 @@
+# std::offload
+
+This module is under active development. Once upstream, it should allow Rust developers to run Rust code on GPUs.
+We aim to develop a `rusty` GPU programming interface, which is safe, convenient and sufficiently fast by default.
+This includes automatic data movement to and from the GPU, in a efficient way. We will (later)
+also offer more advanced, possibly unsafe, interfaces which allow a higher degree of control.
+
+The implementation is based on LLVM's "offload" project, which is already used by OpenMP to run Fortran or C++ code on GPUs.
+While the project is under development, users will need to call other compilers like clang to finish the compilation process.
diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md
index 92d0c7b0c38..8a1a22fad66 100644
--- a/src/doc/rustc-dev-guide/src/overview.md
+++ b/src/doc/rustc-dev-guide/src/overview.md
@@ -410,7 +410,7 @@ For more details on bootstrapping, see
   - Guide: [The HIR](hir.md)
   - Guide: [Identifiers in the HIR](hir.md#identifiers-in-the-hir)
   - Guide: [The `HIR` Map](hir.md#the-hir-map)
-  - Guide: [Lowering `AST` to `HIR`](ast-lowering.md)
+  - Guide: [Lowering `AST` to `HIR`](./hir/lowering.md)
   - How to view `HIR` representation for your code `cargo rustc -- -Z unpretty=hir-tree`
   - Rustc `HIR` definition: [`rustc_hir`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html)
   - Main entry point: **TODO**
diff --git a/src/doc/rustc-dev-guide/src/part-5-intro.md b/src/doc/rustc-dev-guide/src/part-5-intro.md
index f32508d2774..a44fff1e143 100644
--- a/src/doc/rustc-dev-guide/src/part-5-intro.md
+++ b/src/doc/rustc-dev-guide/src/part-5-intro.md
@@ -1,4 +1,4 @@
-# From MIR to Binaries
+# From MIR to binaries
 
 All of the preceding chapters of this guide have one thing in common:
 we never generated any executable machine code at all!
diff --git a/src/doc/rustc-dev-guide/src/pat-exhaustive-checking.md b/src/doc/rustc-dev-guide/src/pat-exhaustive-checking.md
index 4a796ac9500..e953931aa78 100644
--- a/src/doc/rustc-dev-guide/src/pat-exhaustive-checking.md
+++ b/src/doc/rustc-dev-guide/src/pat-exhaustive-checking.md
@@ -1,4 +1,4 @@
-# Pattern and Exhaustiveness Checking
+# Pattern and exhaustiveness checking
 
 In Rust, pattern matching and bindings have a few very helpful properties. The
 compiler will check that bindings are irrefutable when made and that match arms
diff --git a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md
index 39bc8b5e862..d279786ac45 100644
--- a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md
+++ b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md
@@ -1,4 +1,4 @@
-# Profile Guided Optimization
+# Profile-guided optimization
 
 <!-- toc -->
 
@@ -6,7 +6,7 @@
 This chapter describes what PGO is and how the support for it is
 implemented in `rustc`.
 
-## What Is Profiled-Guided Optimization?
+## What is profiled-guided optimization?
 
 The basic concept of PGO is to collect data about the typical execution of
 a program (e.g. which branches it is likely to take) and then use this data
@@ -52,7 +52,7 @@ instrumentation, via the experimental option
 [`-C instrument-coverage`](./llvm-coverage-instrumentation.md), but using these
 coverage results for PGO has not been attempted at this time.
 
-### Overall Workflow
+### Overall workflow
 
 Generating a PGO-optimized program involves the following four steps:
 
@@ -62,12 +62,12 @@ Generating a PGO-optimized program involves the following four steps:
 4. Compile the program again, this time making use of the profiling data
    (e.g. `rustc -C profile-use=merged.profdata main.rs`)
 
-### Compile-Time Aspects
+### Compile-time aspects
 
 Depending on which step in the above workflow we are in, two different things
 can happen at compile time:
 
-#### Create Binaries with Instrumentation
+#### Create binaries with instrumentation
 
 As mentioned above, the profiling instrumentation is added by LLVM.
 `rustc` instructs LLVM to do so [by setting the appropriate][pgo-gen-passmanager]
@@ -88,7 +88,7 @@ runtime are not removed [by marking the with the right export level][pgo-gen-sym
 [pgo-gen-symbols]:https://github.com/rust-lang/rust/blob/1.34.1/src/librustc_codegen_ssa/back/symbol_export.rs#L212-L225
 
 
-#### Compile Binaries Where Optimizations Make Use Of Profiling Data
+#### Compile binaries where optimizations make use of profiling data
 
 In the final step of the workflow described above, the program is compiled
 again, with the compiler using the gathered profiling data in order to drive
@@ -106,7 +106,7 @@ LLVM does the rest (e.g. setting branch weights, marking functions with
 `cold` or `inlinehint`, etc).
 
 
-### Runtime Aspects
+### Runtime aspects
 
 Instrumentation-based approaches always also have a runtime component, i.e.
 once we have an instrumented program, that program needs to be run in order
@@ -134,7 +134,7 @@ instrumentation artifacts show up in LLVM IR.
 [rmake-tests]: https://github.com/rust-lang/rust/tree/master/tests/run-make
 [codegen-test]: https://github.com/rust-lang/rust/blob/master/tests/codegen/pgo-instrumentation.rs
 
-## Additional Information
+## Additional information
 
 Clang's documentation contains a good overview on [PGO in LLVM][llvm-pgo].
 
diff --git a/src/doc/rustc-dev-guide/src/profiling/with_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_perf.md
index 742ea1c41a6..0d4f23bcd9a 100644
--- a/src/doc/rustc-dev-guide/src/profiling/with_perf.md
+++ b/src/doc/rustc-dev-guide/src/profiling/with_perf.md
@@ -7,8 +7,8 @@ This is a guide for how to profile rustc with [perf](https://perf.wiki.kernel.or
 - Get a clean checkout of rust-lang/master, or whatever it is you want
   to profile.
 - Set the following settings in your `bootstrap.toml`:
-  - `debuginfo-level = 1` - enables line debuginfo
-  - `jemalloc = false` - lets you do memory use profiling with valgrind
+  - `rust.debuginfo-level = 1` - enables line debuginfo
+  - `rust.jemalloc = false` - lets you do memory use profiling with valgrind
   - leave everything else the defaults
 - Run `./x build` to get a full build
 - Make a rustup toolchain pointing to that result
diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
index 03c822d4fee..18e0e25c531 100644
--- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
+++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
@@ -1,4 +1,4 @@
-# Incremental Compilation in detail
+# Incremental compilation in detail
 
 <!-- toc -->
 
@@ -66,7 +66,7 @@ because it reads the up-to-date version of `Hir(bar)`. Also, we re-run
 `type_check_item(bar)` because result of `type_of(bar)` might have changed.
 
 
-## The Problem With The Basic Algorithm: False Positives
+## The problem with the basic algorithm: false positives
 
 If you read the previous paragraph carefully you'll notice that it says that
 `type_of(bar)` *might* have changed because one of its inputs has changed.
@@ -93,7 +93,7 @@ of examples like this and small changes to the input often potentially affect
 very large parts of the output binaries. As a consequence, we had to make the
 change detection system smarter and more accurate.
 
-## Improving Accuracy: The red-green Algorithm
+## Improving accuracy: the red-green algorithm
 
 The "false positives" problem can be solved by interleaving change detection
 and query re-evaluation. Instead of walking the graph all the way to the
@@ -191,7 +191,7 @@ then itself involve recursively invoking more queries, which can mean we come ba
 to the `try_mark_green()` algorithm for the dependencies recursively.
 
 
-## The Real World: How Persistence Makes Everything Complicated
+## The real world: how persistence makes everything complicated
 
 The sections above described the underlying algorithm for incremental
 compilation but because the compiler process exits after being finished and
@@ -258,7 +258,7 @@ the `LocalId`s within it are still the same.
 
 
 
-### Checking Query Results For Changes: HashStable And Fingerprints
+### Checking query results for changes: `HashStable` and `Fingerprint`s
 
 In order to do red-green-marking we often need to check if the result of a
 query has changed compared to the result it had during the previous
@@ -306,7 +306,7 @@ This approach works rather well but it's not without flaws:
   their stable equivalents while doing the hashing.
 
 
-### A Tale Of Two DepGraphs: The Old And The New
+### A tale of two `DepGraph`s: the old and the new
 
 The initial description of dependency tracking glosses over a few details
 that quickly become a head scratcher when actually trying to implement things.
@@ -344,7 +344,7 @@ new graph is serialized out to disk, alongside the query result cache, and can
 act as the previous dep-graph in a subsequent compilation session.
 
 
-### Didn't You Forget Something?: Cache Promotion
+### Didn't you forget something?: cache promotion
 
 The system described so far has a somewhat subtle property: If all inputs of a
 dep-node are green then the dep-node itself can be marked as green without
@@ -374,7 +374,7 @@ the result cache doesn't unnecessarily shrink again.
 
 
 
-# Incremental Compilation and the Compiler Backend
+# Incremental compilation and the compiler backend
 
 The compiler backend, the part involving LLVM, is using the query system but
 it is not implemented in terms of queries itself. As a consequence it does not
@@ -406,7 +406,7 @@ would save.
 
 
 
-## Query Modifiers
+## Query modifiers
 
 The query system allows for applying [modifiers][mod] to queries. These
 modifiers affect certain aspects of how the system treats the query with
@@ -472,7 +472,7 @@ respect to incremental compilation:
 [mod]: ../query.html#adding-a-new-kind-of-query
 
 
-## The Projection Query Pattern
+## The projection query pattern
 
 It's interesting to note that `eval_always` and `no_hash` can be used together
 in the so-called "projection query" pattern. It is often the case that there is
@@ -516,7 +516,7 @@ because we have the projections to take care of keeping things green as much
 as possible.
 
 
-# Shortcomings of the Current System
+# Shortcomings of the current system
 
 There are many things that still can be improved.
 
diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md
index 782c5b4b3c0..0ca1b360a70 100644
--- a/src/doc/rustc-dev-guide/src/query.md
+++ b/src/doc/rustc-dev-guide/src/query.md
@@ -2,7 +2,7 @@
 
 <!-- toc -->
 
-As described in [the high-level overview of the compiler][hl], the Rust compiler
+As described in [Overview of the compiler], the Rust compiler
 is still (as of <!-- date-check --> July 2021) transitioning from a
 traditional "pass-based" setup to a "demand-driven" system. The compiler query
 system is the key to rustc's demand-driven organization.
@@ -13,7 +13,7 @@ there is a query called `type_of` that, given the [`DefId`] of
 some item, will compute the type of that item and return it to you.
 
 [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.DefId.html
-[hl]: ./compiler-src.md
+[Overview of the compiler]: overview.md#queries
 
 Query execution is *memoized*. The first time you invoke a
 query, it will go do the computation, but the next time, the result is
@@ -37,12 +37,15 @@ will in turn demand information about that crate, starting from the
   actual parsing.
 
 Although this vision is not fully realized, large sections of the
-compiler (for example, generating [MIR](./mir/index.md)) currently work exactly like this.
+compiler (for example, generating [MIR]) currently work exactly like this.
 
-[^incr-comp-detail]: The ["Incremental Compilation in Detail](queries/incremental-compilation-in-detail.md) chapter gives a more
+[^incr-comp-detail]: The [Incremental compilation in detail] chapter gives a more
 in-depth description of what queries are and how they work.
 If you intend to write a query of your own, this is a good read.
 
+[Incremental compilation in detail]: queries/incremental-compilation-in-detail.md
+[MIR]: mir/index.md
+
 ## Invoking queries
 
 Invoking a query is simple. The [`TyCtxt`] ("type context") struct offers a method
@@ -67,9 +70,15 @@ are cheaply cloneable; insert an `Rc` if necessary).
 ### Providers
 
 If, however, the query is *not* in the cache, then the compiler will
-try to find a suitable **provider**. A provider is a function that has
-been defined and linked into the compiler somewhere that contains the
-code to compute the result of the query.
+call the corresponding **provider** function. A provider is a function
+implemented in a specific module and **manually registered** into the
+[`Providers`][providers_struct] struct during compiler initialization.
+The macro system generates the [`Providers`][providers_struct] struct,
+which acts as a function table for all query implementations, where each
+field is a function pointer to the actual provider.
+
+**Note:** The `Providers` struct is generated by macros and acts as a function table for all query implementations.
+It is **not** a Rust trait, but a plain struct with function pointer fields.
 
 **Providers are defined per-crate.** The compiler maintains,
 internally, a table of providers for every crate, at least
@@ -97,7 +106,18 @@ fn provider<'tcx>(
 Providers take two arguments: the `tcx` and the query key.
 They return the result of the query.
 
-###  How providers are setup
+N.B. Most of the `rustc_*` crates only provide **local
+providers**. Almost all **extern providers** wind up going through the
+[`rustc_metadata` crate][rustc_metadata], which loads the information
+from the crate metadata. But in some cases there are crates that
+provide queries for *both* local and external crates, in which case
+they define both a `provide` and a `provide_extern` function, through
+[`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke.
+
+[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html
+[wasm_import_module_map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/back/symbol_export/fn.wasm_import_module_map.html
+
+### How providers are set up
 
 When the tcx is created, it is given the providers by its creator using
 the [`Providers`][providers_struct] struct. This struct is generated by
@@ -108,19 +128,16 @@ the macros here, but it is basically a big list of function pointers:
 ```rust,ignore
 struct Providers {
     type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
-    ...
+    // ... one field for each query
 }
 ```
 
-At present, we have one copy of the struct for local crates, and one
-for external crates, though the plan is that we may eventually have
-one per crate.
+#### How are providers registered?
+
+The `Providers` struct is filled in during compiler initialization, mainly by the `rustc_driver` crate.  
+But the actual provider functions are implemented in various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc).
 
-These `Providers` structs are ultimately created and populated by
-`rustc_driver`, but it does this by distributing the work
-throughout the other `rustc_*` crates. This is done by invoking
-various [`provide`][provide_fn] functions. These functions tend to look
-something like this:
+To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this:
 
 [provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
 
@@ -128,41 +145,34 @@ something like this:
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         type_of,
+        // ... add more providers here
         ..*providers
     };
 }
 ```
 
-That is, they take an `&mut Providers` and mutate it in place. Usually
-we use the formulation above just because it looks nice, but you could
-as well do `providers.type_of = type_of`, which would be equivalent.
-(Here, `type_of` would be a top-level function, defined as we saw
-before.) So, if we want to add a provider for some other query,
-let's call it `fubar`, into the crate above, we might modify the `provide()`
-function like so:
+- This function takes a mutable reference to the `Providers` struct and sets the fields to point to the correct provider functions.
+- You can also assign fields individually, e.g. `providers.type_of = type_of;`.
 
-```rust,ignore
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers {
-        type_of,
-        fubar,
-        ..*providers
-    };
-}
+#### Adding a new provider
 
-fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... }
-```
+Suppose you want to add a new query called `fubar`. You would:
 
-N.B. Most of the `rustc_*` crates only provide **local
-providers**. Almost all **extern providers** wind up going through the
-[`rustc_metadata` crate][rustc_metadata], which loads the information
-from the crate metadata. But in some cases there are crates that
-provide queries for *both* local and external crates, in which case
-they define both a `provide` and a `provide_extern` function, through
-[`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke.
+1. Implement the provider function:
+    ```rust,ignore
+    fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... }
+    ```
+2. Register it in the `provide` function:
+    ```rust,ignore
+    pub fn provide(providers: &mut Providers) {
+        *providers = Providers {
+            fubar,
+            ..*providers
+        };
+    }
+    ```
 
-[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html
-[wasm_import_module_map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/back/symbol_export/fn.wasm_import_module_map.html
+---
 
 ## Adding a new query
 
diff --git a/src/doc/rustc-dev-guide/src/sanitizers.md b/src/doc/rustc-dev-guide/src/sanitizers.md
index b1654b15e08..664b4feac4f 100644
--- a/src/doc/rustc-dev-guide/src/sanitizers.md
+++ b/src/doc/rustc-dev-guide/src/sanitizers.md
@@ -1,4 +1,4 @@
-# Sanitizers Support
+# Sanitizers support
 
 The rustc compiler contains support for following sanitizers:
 
diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md
index ce6cffec1ad..767ac3fdba2 100644
--- a/src/doc/rustc-dev-guide/src/ty.md
+++ b/src/doc/rustc-dev-guide/src/ty.md
@@ -62,8 +62,8 @@ Here is a summary:
 | Describe the *syntax* of a type: what the user wrote (with some desugaring).  | Describe the *semantics* of a type: the meaning of what the user wrote. |
 | Each `rustc_hir::Ty` has its own spans corresponding to the appropriate place in the program. | Doesn’t correspond to a single place in the user’s program. |
 | `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeKind::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out |
-| `fn foo(x: u32) → u32 { }` - Two `rustc_hir::Ty` representing each usage of `u32`, each has its own `Span`s, and `rustc_hir::Ty` doesn’t tell us that both are the same type | `fn foo(x: u32) → u32 { }` - One `ty::Ty` for all instances of `u32` throughout the program, and `ty::Ty` tells us that both usages of `u32` mean the same type. |
-| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeKind::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. |
+| `fn foo(x: u32) -> u32 { }` - Two `rustc_hir::Ty` representing each usage of `u32`, each has its own `Span`s, and `rustc_hir::Ty` doesn’t tell us that both are the same type | `fn foo(x: u32) -> u32 { }` - One `ty::Ty` for all instances of `u32` throughout the program, and `ty::Ty` tells us that both usages of `u32` mean the same type. |
+| `fn foo(x: &u32) -> &u32 { }` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeKind::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32 { }`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. |
 
 [implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeKind.html#variant.Implicit
 
diff --git a/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md b/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md
index b7a3aa71fc4..03e576e3e30 100644
--- a/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md
+++ b/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md
@@ -15,7 +15,7 @@ This flag is equivalent to:
 - `-fmin-function-alignment` for [GCC](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fmin-function-alignment_003dn)
 - `-falign-functions` for [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang1-falign-functions)
 
-The specified alignment is a minimum. A higher alignment can be specified for specific functions by using the [`repr(align(...))`](https://github.com/rust-lang/rust/issues/82232) feature and annotating the function with a `#[repr(align(<align>))]` attribute. The attribute's value is ignored when it is lower than the value passed to `min-function-alignment`.
+The specified alignment is a minimum. A higher alignment can be specified for specific functions by using the [`align(...)`](https://github.com/rust-lang/rust/issues/82232) feature and annotating the function with a `#[align(<align>)]` attribute. The attribute's value is ignored when it is lower than the value passed to `min-function-alignment`.
 
 There are two additional edge cases for this flag:
 
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2d9670a3d10..408ef611ee5 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -4,6 +4,7 @@ use std::sync::{Arc, OnceLock as OnceCell};
 use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
+use itertools::Either;
 use rustc_abi::{ExternAbi, VariantIdx};
 use rustc_attr_data_structures::{
     AttributeKind, ConstStability, Deprecation, Stability, StableSince,
@@ -199,49 +200,49 @@ impl ExternalCrate {
             .unwrap_or(Unknown) // Well, at least we tried.
     }
 
-    pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
+    fn mapped_root_modules<T>(
+        &self,
+        tcx: TyCtxt<'_>,
+        f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>,
+    ) -> impl Iterator<Item = (DefId, T)> {
         let root = self.def_id();
 
-        let as_keyword = |res: Res<!>| {
-            if let Res::Def(DefKind::Mod, def_id) = res {
-                let mut keyword = None;
-                let meta_items = tcx
-                    .get_attrs(def_id, sym::doc)
-                    .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
-                for meta in meta_items {
-                    if meta.has_name(sym::keyword)
-                        && let Some(v) = meta.value_str()
-                    {
-                        keyword = Some(v);
-                        break;
-                    }
-                }
-                return keyword.map(|p| (def_id, p));
-            }
-            None
-        };
         if root.is_local() {
-            tcx.hir_root_module()
-                .item_ids
-                .iter()
-                .filter_map(|&id| {
-                    let item = tcx.hir_item(id);
-                    match item.kind {
-                        hir::ItemKind::Mod(..) => {
-                            as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
-                        }
-                        _ => None,
-                    }
-                })
-                .collect()
+            Either::Left(
+                tcx.hir_root_module()
+                    .item_ids
+                    .iter()
+                    .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Mod(..)))
+                    .filter_map(move |&id| f(id.owner_id.into(), tcx)),
+            )
         } else {
-            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+            Either::Right(
+                tcx.module_children(root)
+                    .iter()
+                    .filter_map(|item| {
+                        if let Res::Def(DefKind::Mod, did) = item.res { Some(did) } else { None }
+                    })
+                    .filter_map(move |did| f(did, tcx)),
+            )
         }
     }
 
-    pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
-        let root = self.def_id();
+    pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
+        fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> {
+            tcx.get_attrs(did, sym::doc)
+                .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+                .filter(|meta| meta.has_name(sym::keyword))
+                .find_map(|meta| meta.value_str())
+                .map(|value| (did, value))
+        }
 
+        self.mapped_root_modules(tcx, as_keyword)
+    }
+
+    pub(crate) fn primitives(
+        &self,
+        tcx: TyCtxt<'_>,
+    ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
         // Collect all inner modules which are tagged as implementations of
         // primitives.
         //
@@ -259,40 +260,21 @@ impl ExternalCrate {
         // Also note that this does not attempt to deal with modules tagged
         // duplicately for the same primitive. This is handled later on when
         // rendering by delegating everything to a hash map.
-        let as_primitive = |res: Res<!>| {
-            let Res::Def(DefKind::Mod, def_id) = res else { return None };
-            tcx.get_attrs(def_id, sym::rustc_doc_primitive)
-                .map(|attr| {
-                    let attr_value = attr.value_str().expect("syntax should already be validated");
-                    let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
-                        span_bug!(
-                            attr.span(),
-                            "primitive `{attr_value}` is not a member of `PrimitiveType`"
-                        );
-                    };
-
-                    (def_id, prim)
-                })
-                .next()
-        };
+        fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
+            tcx.get_attrs(def_id, sym::rustc_doc_primitive).next().map(|attr| {
+                let attr_value = attr.value_str().expect("syntax should already be validated");
+                let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
+                    span_bug!(
+                        attr.span(),
+                        "primitive `{attr_value}` is not a member of `PrimitiveType`"
+                    );
+                };
 
-        if root.is_local() {
-            tcx.hir_root_module()
-                .item_ids
-                .iter()
-                .filter_map(|&id| {
-                    let item = tcx.hir_item(id);
-                    match item.kind {
-                        hir::ItemKind::Mod(..) => {
-                            as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
-                        }
-                        _ => None,
-                    }
-                })
-                .collect()
-        } else {
-            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
+                (def_id, prim)
+            })
         }
+
+        self.mapped_root_modules(tcx, as_primitive)
     }
 }
 
@@ -1966,7 +1948,7 @@ impl PrimitiveType {
                 let e = ExternalCrate { crate_num };
                 let crate_name = e.name(tcx);
                 debug!(?crate_num, ?crate_name);
-                for &(def_id, prim) in &e.primitives(tcx) {
+                for (def_id, prim) in e.primitives(tcx) {
                     // HACK: try to link to std instead where possible
                     if crate_name == sym::core && primitive_locations.contains_key(&prim) {
                         continue;
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c58b07a5b67..2c9878636ab 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -61,7 +61,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
     let keywords = local_crate.keywords(cx.tcx);
     {
         let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() };
-        m.items.extend(primitives.iter().map(|&(def_id, prim)| {
+        m.items.extend(primitives.map(|(def_id, prim)| {
             Item::from_def_id_and_parts(
                 def_id,
                 Some(prim.as_sym()),
@@ -69,7 +69,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
                 cx,
             )
         }));
-        m.items.extend(keywords.into_iter().map(|(def_id, kw)| {
+        m.items.extend(keywords.map(|(def_id, kw)| {
             Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx)
         }));
     }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 204f8decffc..d73600a4636 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -387,8 +387,6 @@ pub(crate) fn run_global_ctxt(
         ctxt.external_traits.insert(sized_trait_did, sized_trait);
     }
 
-    debug!("crate: {:?}", tcx.hir_crate(()));
-
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
 
     if krate.module.doc_value().is_empty() {
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 2feadce26d0..29c63a391e2 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_session::features::StabilityExt;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustdoc_json_types as types;
 // It's important to use the FxHashMap from rustdoc_json_types here, instead of
@@ -148,7 +147,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
             .copied()
             .filter(|(_, stability, _)| {
                 // Describe only target features which the user can toggle
-                stability.is_toggle_permitted(sess).is_ok()
+                stability.toggle_allowed().is_ok()
             })
             .map(|(name, stability, implied_features)| {
                 types::TargetFeature {
@@ -164,7 +163,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
                             // Imply only target features which the user can toggle
                             feature_stability
                                 .get(name)
-                                .map(|stability| stability.is_toggle_permitted(sess).is_ok())
+                                .map(|stability| stability.toggle_allowed().is_ok())
                                 .unwrap_or(false)
                         })
                         .map(String::from)
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index f4e4cd924f7..2339a6b69cd 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -35,7 +35,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
     });
 
     let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
-    let prims: FxHashSet<PrimitiveType> = local_crate.primitives(tcx).iter().map(|p| p.1).collect();
+    let prims: FxHashSet<PrimitiveType> = local_crate.primitives(tcx).map(|(_, p)| p).collect();
 
     let crate_items = {
         let mut coll = ItemAndAliasCollector::new(&cx.cache);
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 1f93895ae07..d5de43feb58 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
 // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
 // are deliberately not in a doc comment, because they need not be in public docs.)
 //
-// Latest feature: Pretty printing of inline attributes changed
-pub const FORMAT_VERSION: u32 = 48;
+// Latest feature: Pretty printing of optimize attributes changed
+pub const FORMAT_VERSION: u32 = 49;
 
 /// The root of the emitted JSON blob.
 ///
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 3a76c61489e..13cf82a062b 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -58,6 +58,7 @@ rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 [features]
 integration = ["dep:tempfile"]
 internal = ["dep:clippy_lints_internal", "dep:tempfile"]
+jemalloc = []
 
 [package.metadata.rust-analyzer]
 # This package uses #[feature(rustc_private)]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 37adb14169a..426ba870f5f 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -13,6 +13,11 @@ extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
 
+// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
+// about jemalloc.
+#[cfg(feature = "jemalloc")]
+extern crate tikv_jemalloc_sys as jemalloc_sys;
+
 use clippy_utils::sym;
 use rustc_interface::interface;
 use rustc_session::EarlyDiagCtxt;
@@ -181,6 +186,36 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
 #[allow(clippy::too_many_lines)]
 #[allow(clippy::ignored_unit_patterns)]
 pub fn main() {
+    // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
+    // about jemalloc.
+    #[cfg(feature = "jemalloc")]
+    {
+        use std::os::raw::{c_int, c_void};
+
+        #[used]
+        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
+        #[used]
+        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = jemalloc_sys::posix_memalign;
+        #[used]
+        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
+        #[used]
+        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
+        #[used]
+        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
+        #[used]
+        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
+
+        #[cfg(target_os = "macos")]
+        {
+            unsafe extern "C" {
+                fn _rjem_je_zone_register();
+            }
+
+            #[used]
+            static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
+        }
+    }
+
     let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     rustc_driver::init_rustc_env_logger(&early_dcx);
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
index 5f8a4ce2363..49595e2fec2 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -9,28 +9,35 @@ if let StmtKind::Let(local) = stmt.kind
     && let ExprKind::Call(func, args) = e.kind
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
-    && let ExprKind::Call(func1, args1) = args[0].kind
-    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 2
+    && let ExprKind::Block(block1, None) = args[0].kind
+    && block1.stmts.len() == 1
+    && let StmtKind::Let(local1) = block1.stmts[0].kind
+    && let Some(init1) = local1.init
+    && let ExprKind::Array(elements) = init1.kind
+    && elements.len() == 1
+    && let ExprKind::Call(func1, args1) = elements[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
-    && let ExprKind::Array(elements) = inner.kind
-    && elements.len() == 2
-    && let ExprKind::Lit(ref lit) = elements[0].kind
+    && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
+    && name.as_str() == "args"
+    && let Some(trailing_expr) = block1.expr
+    && let ExprKind::Call(func2, args2) = trailing_expr.kind
+    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
+    && args2.len() == 2
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
+    && let ExprKind::Array(elements1) = inner1.kind
+    && elements1.len() == 2
+    && let ExprKind::Lit(ref lit) = elements1[0].kind
     && let LitKind::Str(s, _) = lit.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit1) = elements[1].kind
+    && let ExprKind::Lit(ref lit1) = elements1[1].kind
     && let LitKind::Str(s1, _) = lit1.node
     && s1.as_str() == "\n"
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 1
-    && let ExprKind::Call(func2, args2) = elements1[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
-    && args2.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
     && block.expr.is_none()
-    && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
-    && name.as_str() == "print_text"
+    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
+    && name1.as_str() == "print_text"
 {
     // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
index ecc25254311..4fc7b49464d 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -19,25 +19,32 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && let ExprKind::Call(func, args) = e1.kind
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
-    && let ExprKind::Call(func1, args1) = args[0].kind
-    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 2
+    && let ExprKind::Block(block2, None) = args[0].kind
+    && block2.stmts.len() == 1
+    && let StmtKind::Let(local) = block2.stmts[0].kind
+    && let Some(init) = local.init
+    && let ExprKind::Array(elements) = init.kind
+    && elements.len() == 1
+    && let ExprKind::Call(func1, args1) = elements[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
-    && let ExprKind::Array(elements) = inner.kind
-    && elements.len() == 2
-    && let ExprKind::Lit(ref lit2) = elements[0].kind
+    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
+    && name1.as_str() == "args"
+    && let Some(trailing_expr) = block2.expr
+    && let ExprKind::Call(func2, args2) = trailing_expr.kind
+    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
+    && args2.len() == 2
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
+    && let ExprKind::Array(elements1) = inner1.kind
+    && elements1.len() == 2
+    && let ExprKind::Lit(ref lit2) = elements1[0].kind
     && let LitKind::Str(s, _) = lit2.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit3) = elements[1].kind
+    && let ExprKind::Lit(ref lit3) = elements1[1].kind
     && let LitKind::Str(s1, _) = lit3.node
     && s1.as_str() == "\n"
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 1
-    && let ExprKind::Call(func2, args2) = elements1[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
-    && args2.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
     && block1.expr.is_none()
     && block.expr.is_none()
 {
diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed
index 9b768dbad70..00a19155a51 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.fixed
+++ b/src/tools/clippy/tests/ui/manual_inspect.fixed
@@ -154,7 +154,6 @@ fn main() {
     });
 
     let _ = [0]
-        //~^ suspicious_map
         .into_iter()
         .inspect(|&x| {
             //~^ manual_inspect
diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs
index e679636201e..b3b17139cde 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.rs
+++ b/src/tools/clippy/tests/ui/manual_inspect.rs
@@ -165,7 +165,6 @@ fn main() {
     });
 
     let _ = [0]
-        //~^ suspicious_map
         .into_iter()
         .map(|x| {
             //~^ manual_inspect
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index 78b085fdfca..70c00c1f755 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -157,25 +157,8 @@ LL |
 LL ~         println!("{}", x);
    |
 
-error: this call to `map()` won't have an effect on the call to `count()`
-  --> tests/ui/manual_inspect.rs:167:13
-   |
-LL |       let _ = [0]
-   |  _____________^
-LL | |
-LL | |         .into_iter()
-LL | |         .map(|x| {
-...  |
-LL | |         })
-LL | |         .count();
-   | |________________^
-   |
-   = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
-   = note: `-D clippy::suspicious-map` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
-
 error: using `map` over `inspect`
-  --> tests/ui/manual_inspect.rs:170:10
+  --> tests/ui/manual_inspect.rs:169:10
    |
 LL |         .map(|x| {
    |          ^^^
@@ -188,7 +171,7 @@ LL ~             println!("{}", x);
    |
 
 error: using `map` over `inspect`
-  --> tests/ui/manual_inspect.rs:203:30
+  --> tests/ui/manual_inspect.rs:202:30
    |
 LL |     if let Some(x) = Some(1).map(|x| { println!("{x}");
    |                              ^^^
@@ -200,5 +183,5 @@ LL |         // Do not collapse code into this comment
 LL ~          }) {
    |
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 045f2f0692a..b3517b2e9da 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -305,7 +305,6 @@ ui/borrowck/issue-104639-lifetime-order.rs
 ui/borrowck/issue-10876.rs
 ui/borrowck/issue-109271-pass-self-into-closure.rs
 ui/borrowck/issue-111554.rs
-ui/borrowck/issue-114374-invalid-help-fmt-args.rs
 ui/borrowck/issue-11493.rs
 ui/borrowck/issue-115259-suggest-iter-mut.rs
 ui/borrowck/issue-119915-bad-clone-suggestion.rs
diff --git a/tests/assembly/s390x-backchain-toggle.rs b/tests/assembly/s390x-backchain-toggle.rs
index 83c7b82d0d4..9bae15b7d11 100644
--- a/tests/assembly/s390x-backchain-toggle.rs
+++ b/tests/assembly/s390x-backchain-toggle.rs
@@ -1,5 +1,5 @@
 //@ add-core-stubs
-//@ revisions: enable-backchain disable-backchain
+//@ revisions: enable-backchain disable-backchain default-backchain
 //@ assembly-output: emit-asm
 //@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu
 //@ needs-llvm-components: systemz
@@ -26,6 +26,8 @@ extern "C" fn test_backchain() -> i32 {
     // enable-backchain: stg [[REG1]], 0(%r15)
     // disable-backchain: aghi %r15, -160
     // disable-backchain-NOT: stg %r{{.*}}, 0(%r15)
+    // default-backchain: aghi %r15, -160
+    // default-backchain-NOT: stg %r{{.*}}, 0(%r15)
     unsafe {
         extern_func();
     }
@@ -35,6 +37,7 @@ extern "C" fn test_backchain() -> i32 {
     // Make sure that the expected return value is written into %r2 (return register):
     // enable-backchain-NEXT: lghi %r2, 1
     // disable-backchain: lghi %r2, 0
+    // default-backchain: lghi %r2, 0
     #[cfg(target_feature = "backchain")]
     {
         1
diff --git a/tests/codegen/target-feature-negative-implication.rs b/tests/codegen/target-feature-negative-implication.rs
new file mode 100644
index 00000000000..36cd82dd8cf
--- /dev/null
+++ b/tests/codegen/target-feature-negative-implication.rs
@@ -0,0 +1,20 @@
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu
+//@ compile-flags: -Ctarget-feature=-avx2
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub unsafe fn banana() {
+    // CHECK-LABEL: @banana()
+    // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] {
+}
+
+// CHECK: attributes [[BANANAATTRS]]
+// CHECK-SAME: -avx512
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index 0fc1e0136b3..eb19b0de2fa 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-linelength
 //@ add-core-stubs
 //@ revisions: COMPAT INCOMPAT
 //@ needs-llvm-components: x86
@@ -39,7 +40,7 @@ pub unsafe fn banana() -> u32 {
 
 // CHECK: attributes [[APPLEATTRS]]
 // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
+// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}"
 // CHECK: attributes [[BANANAATTRS]]
 // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx"
+// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 6be0e21e0ef..81499c070d1 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -4,14 +4,23 @@
 //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
 //@ needs-llvm-components: aarch64
 
+// Rust made SVE require neon.
 //@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
-// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
+// ENABLE_SVE: attributes #0
+// ENABLE_SVE-SAME: +neon
+// ENABLE_SVE-SAME: +sve
 
+// However, disabling SVE does not disable neon.
 //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
-// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-sve,?)|(\+neon,?))*}}" }
+// DISABLE_SVE: attributes #0
+// DISABLE_SVE-NOT: -neon
+// DISABLE_SVE-SAME: -sve
 
+// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way.
 //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
-// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-fp-armv8,?)|(-neon,?))*}}" }
+// DISABLE_NEON: attributes #0
+// DISABLE_NEON-SAME: -neon
+// DISABLE_NEON-SAME: -fp-armv8
 
 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" }
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
index 33f1ad9bef4..e2d3c6c41b8 100644
--- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -11,28 +11,29 @@
       let _9: ();
       let _10: ();
       let mut _11: std::fmt::Arguments<'_>;
-      let mut _12: &[&str; 3];
-      let _13: &[&str; 3];
-      let _14: [&str; 3];
-      let mut _15: &[core::fmt::rt::Argument<'_>; 2];
-      let _16: &[core::fmt::rt::Argument<'_>; 2];
-      let _17: [core::fmt::rt::Argument<'_>; 2];
+      let mut _13: &std::boxed::Box<dyn std::fmt::Display>;
+      let mut _14: &u32;
+      let mut _16: core::fmt::rt::Argument<'_>;
+      let mut _17: &std::boxed::Box<dyn std::fmt::Display>;
       let mut _18: core::fmt::rt::Argument<'_>;
-      let mut _19: &std::boxed::Box<dyn std::fmt::Display>;
-      let _20: &std::boxed::Box<dyn std::fmt::Display>;
-      let mut _21: core::fmt::rt::Argument<'_>;
-      let mut _22: &u32;
-      let _23: &u32;
-      let mut _25: bool;
-      let mut _26: isize;
-      let mut _27: isize;
-      let mut _28: isize;
-+     let _29: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
-+     let _30: u32;
+      let mut _19: &u32;
+      let mut _20: &[&str; 3];
+      let _21: &[&str; 3];
+      let _22: [&str; 3];
+      let mut _23: &[core::fmt::rt::Argument<'_>; 2];
+      let _24: &[core::fmt::rt::Argument<'_>; 2];
+      let mut _26: &std::boxed::Box<dyn std::fmt::Display>;
+      let mut _27: &u32;
+      let mut _28: bool;
+      let mut _29: isize;
+      let mut _30: isize;
+      let mut _31: isize;
++     let _32: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
++     let _33: u32;
       scope 1 {
 -         debug foo => _1;
-+         debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _29;
-+         debug ((foo: Foo<T>).1: u32) => _30;
++         debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _32;
++         debug ((foo: Foo<T>).1: u32) => _33;
           let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
           scope 2 {
               debug x => _5;
@@ -42,17 +43,29 @@
                   scope 4 {
                       debug x => _8;
                       let _8: std::boxed::Box<dyn std::fmt::Display>;
-                      let mut _24: &[&str; 3];
+                      let _12: (&std::boxed::Box<dyn std::fmt::Display>, &u32);
++                     let _34: &std::boxed::Box<dyn std::fmt::Display>;
++                     let _35: &u32;
+                      scope 5 {
+-                         debug args => _12;
++                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).0: &std::boxed::Box<dyn std::fmt::Display>) => _34;
++                         debug ((args: (&Box<dyn std::fmt::Display>, &u32)).1: &u32) => _35;
+                          let _15: [core::fmt::rt::Argument<'_>; 2];
+                          scope 6 {
+                              debug args => _15;
+                              let mut _25: &[&str; 3];
+                          }
+                      }
                   }
               }
           }
       }
   
       bb0: {
-          _25 = const false;
+          _28 = const false;
 -         StorageLive(_1);
-+         StorageLive(_29);
-+         StorageLive(_30);
++         StorageLive(_32);
++         StorageLive(_33);
 +         nop;
           StorageLive(_2);
           StorageLive(_3);
@@ -66,77 +79,93 @@
           _2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3);
           StorageDead(_3);
 -         _1 = Foo::<T> { x: move _2, y: const 7_u32 };
-+         _29 = move _2;
-+         _30 = const 7_u32;
++         _32 = move _2;
++         _33 = const 7_u32;
 +         nop;
           StorageDead(_2);
           StorageLive(_5);
-          _25 = const true;
+          _28 = const true;
 -         _5 = move (_1.0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>);
-+         _5 = move _29;
++         _5 = move _32;
           StorageLive(_6);
 -         _6 = copy (_1.1: u32);
-+         _6 = copy _30;
++         _6 = copy _33;
           _7 = discriminant(_5);
           switchInt(move _7) -> [0: bb2, otherwise: bb7];
       }
   
       bb2: {
           StorageLive(_8);
-          _25 = const false;
+          _28 = const false;
           _8 = move ((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>);
           StorageLive(_9);
           StorageLive(_10);
           StorageLive(_11);
-          StorageLive(_12);
+-         StorageLive(_12);
++         StorageLive(_34);
++         StorageLive(_35);
++         nop;
           StorageLive(_13);
-          _24 = const foo::<T>::promoted[0];
-          _13 = &(*_24);
-          _12 = &(*_13);
+          _13 = &_8;
+          StorageLive(_14);
+          _14 = &_6;
+-         _12 = (move _13, move _14);
++         _34 = move _13;
++         _35 = move _14;
++         nop;
+          StorageDead(_14);
+          StorageDead(_13);
           StorageLive(_15);
           StorageLive(_16);
           StorageLive(_17);
-          StorageLive(_18);
-          StorageLive(_19);
-          StorageLive(_20);
-          _20 = &_8;
-          _19 = &(*_20);
-          _18 = core::fmt::rt::Argument::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _19) -> [return: bb3, unwind unreachable];
+-         _26 = deref_copy (_12.0: &std::boxed::Box<dyn std::fmt::Display>);
++         _26 = deref_copy _34;
+          _17 = &(*_26);
+          _16 = core::fmt::rt::Argument::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _17) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
-          StorageDead(_19);
-          StorageLive(_21);
-          StorageLive(_22);
-          StorageLive(_23);
-          _23 = &_6;
-          _22 = &(*_23);
-          _21 = core::fmt::rt::Argument::<'_>::new_display::<u32>(move _22) -> [return: bb4, unwind unreachable];
+          StorageDead(_17);
+          StorageLive(_18);
+          StorageLive(_19);
+-         _27 = deref_copy (_12.1: &u32);
++         _27 = deref_copy _35;
+          _19 = &(*_27);
+          _18 = core::fmt::rt::Argument::<'_>::new_display::<u32>(move _19) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
-          StorageDead(_22);
-          _17 = [move _18, move _21];
-          StorageDead(_21);
+          StorageDead(_19);
+          _15 = [move _16, move _18];
           StorageDead(_18);
-          _16 = &_17;
-          _15 = &(*_16);
-          _11 = core::fmt::rt::<impl Arguments<'_>>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable];
+          StorageDead(_16);
+          StorageLive(_20);
+          StorageLive(_21);
+          _25 = const foo::<T>::promoted[0];
+          _21 = &(*_25);
+          _20 = &(*_21);
+          StorageLive(_23);
+          StorageLive(_24);
+          _24 = &_15;
+          _23 = &(*_24);
+          _11 = core::fmt::rt::<impl Arguments<'_>>::new_v1::<3, 2>(move _20, move _23) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
-          StorageDead(_15);
-          StorageDead(_12);
+          StorageDead(_24);
+          StorageDead(_23);
+          StorageDead(_21);
+          StorageDead(_20);
           _10 = _eprint(move _11) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
           StorageDead(_11);
-          StorageDead(_23);
-          StorageDead(_20);
-          StorageDead(_17);
-          StorageDead(_16);
-          StorageDead(_13);
+          StorageDead(_15);
+-         StorageDead(_12);
++         StorageDead(_34);
++         StorageDead(_35);
++         nop;
           StorageDead(_10);
           _9 = const ();
           StorageDead(_9);
@@ -156,22 +185,22 @@
   
       bb9: {
           StorageDead(_6);
-          _26 = discriminant(_5);
-          switchInt(move _26) -> [0: bb11, otherwise: bb13];
+          _29 = discriminant(_5);
+          switchInt(move _29) -> [0: bb11, otherwise: bb13];
       }
   
       bb10: {
-          _25 = const false;
+          _28 = const false;
           StorageDead(_5);
 -         StorageDead(_1);
-+         StorageDead(_29);
-+         StorageDead(_30);
++         StorageDead(_32);
++         StorageDead(_33);
 +         nop;
           return;
       }
   
       bb11: {
-          switchInt(copy _25) -> [0: bb10, otherwise: bb12];
+          switchInt(copy _28) -> [0: bb10, otherwise: bb12];
       }
   
       bb12: {
diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs
index 35ffd6d8acc..f5ab9555e56 100644
--- a/tests/ui/attributes/malformed-fn-align.rs
+++ b/tests/ui/attributes/malformed-fn-align.rs
@@ -3,7 +3,10 @@
 
 trait MyTrait {
     #[align] //~ ERROR malformed `align` attribute input
-    fn myfun();
+    fn myfun1();
+
+    #[align(1, 2)] //~ ERROR malformed `align` attribute input
+    fn myfun2();
 }
 
 #[align = 16] //~ ERROR malformed `align` attribute input
diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr
index 765255c2c3a..b769d0b457d 100644
--- a/tests/ui/attributes/malformed-fn-align.stderr
+++ b/tests/ui/attributes/malformed-fn-align.stderr
@@ -2,54 +2,55 @@ error[E0539]: malformed `align` attribute input
   --> $DIR/malformed-fn-align.rs:5:5
    |
 LL |     #[align]
-   |     ^^^^^^^^ expected this to be a list
-   |
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL |     #[align(<alignment in bytes>)]
-   |            ++++++++++++++++++++++
+   |     ^^^^^^^^
+   |     |
+   |     expected this to be a list
+   |     help: must be of the form: `#[align(<alignment in bytes>)]`
+
+error[E0805]: malformed `align` attribute input
+  --> $DIR/malformed-fn-align.rs:8:5
+   |
+LL |     #[align(1, 2)]
+   |     ^^^^^^^------^
+   |     |      |
+   |     |      expected a single argument here
+   |     help: must be of the form: `#[align(<alignment in bytes>)]`
 
 error[E0539]: malformed `align` attribute input
-  --> $DIR/malformed-fn-align.rs:9:1
+  --> $DIR/malformed-fn-align.rs:12:1
    |
 LL | #[align = 16]
-   | ^^^^^^^^^^^^^ expected this to be a list
-   |
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL - #[align = 16]
-LL + #[align(<alignment in bytes>)]
-   |
-LL - #[align = 16]
-LL + #[align]
-   |
+   | ^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[align(<alignment in bytes>)]`
 
 error[E0589]: invalid alignment value: not an unsuffixed integer
-  --> $DIR/malformed-fn-align.rs:12:9
+  --> $DIR/malformed-fn-align.rs:15:9
    |
 LL | #[align("hello")]
    |         ^^^^^^^
 
 error[E0589]: invalid alignment value: not a power of two
-  --> $DIR/malformed-fn-align.rs:15:9
+  --> $DIR/malformed-fn-align.rs:18:9
    |
 LL | #[align(0)]
    |         ^
 
 error: `#[repr(align(...))]` is not supported on function items
-  --> $DIR/malformed-fn-align.rs:18:8
+  --> $DIR/malformed-fn-align.rs:21:8
    |
 LL | #[repr(align(16))]
    |        ^^^^^^^^^
    |
 help: use `#[align(...)]` instead
-  --> $DIR/malformed-fn-align.rs:18:8
+  --> $DIR/malformed-fn-align.rs:21:8
    |
 LL | #[repr(align(16))]
    |        ^^^^^^^^^
 
 error: `#[align(...)]` is not supported on struct items
-  --> $DIR/malformed-fn-align.rs:21:1
+  --> $DIR/malformed-fn-align.rs:24:1
    |
 LL | #[align(16)]
    | ^^^^^^^^^^^^
@@ -60,7 +61,7 @@ LL - #[align(16)]
 LL + #[repr(align(16))]
    |
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0539, E0589.
+Some errors have detailed explanations: E0539, E0589, E0805.
 For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
index 911c136086c..72580e7464b 100644
--- a/tests/ui/borrowck/clone-on-ref.stderr
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -30,7 +30,7 @@ LL |     drop(x);
    |          ^ move out of `x` occurs here
 LL |
 LL |     println!("{b}");
-   |               --- borrow later used here
+   |                - borrow later used here
    |
 help: if `T` implemented `Clone`, you could clone the value
   --> $DIR/clone-on-ref.rs:11:8
@@ -57,7 +57,7 @@ LL |     drop(x);
    |          ^ move out of `x` occurs here
 LL |
 LL |     println!("{b:?}");
-   |               ----- borrow later used here
+   |                - borrow later used here
    |
 note: if `A` implemented `Clone`, you could clone the value
   --> $DIR/clone-on-ref.rs:19:1
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
deleted file mode 100644
index 4a6c2f9ed06..00000000000
--- a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![allow(dead_code)]
-
-fn bar<'a>(_: std::fmt::Arguments<'a>) {}
-fn main() {
-    let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
-    //~^ ERROR temporary value dropped while borrowed
-
-    bar(x);
-
-    let foo = format_args!("{}", "hi");
-    //~^ ERROR temporary value dropped while borrowed
-    bar(foo);
-
-    let foo = format_args!("hi"); // no placeholder in arguments, so no error
-    bar(foo);
-}
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
deleted file mode 100644
index 30f292f71a2..00000000000
--- a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13
-   |
-LL |     let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
-   |             |
-   |             creates a temporary value which is freed while still in use
-...
-LL |     bar(x);
-   |         - borrow later used here
-   |
-   = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
-   = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15
-   |
-LL |     let foo = format_args!("{}", "hi");
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
-   |               |
-   |               creates a temporary value which is freed while still in use
-LL |
-LL |     bar(foo);
-   |         --- borrow later used here
-   |
-   = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
-   = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index f29a41d6a8e..f422919983b 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -211,10 +211,6 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
 `reference-types`
 `relax`
 `relaxed-simd`
-`reserve-x18`
-`retpoline-external-thunk`
-`retpoline-indirect-branches`
-`retpoline-indirect-calls`
 `rtm`
 `sb`
 `scq`
diff --git a/tests/ui/consts/recursive-const-in-impl.stderr b/tests/ui/consts/recursive-const-in-impl.stderr
index 6175112c8cc..035d9c2f21c 100644
--- a/tests/ui/consts/recursive-const-in-impl.stderr
+++ b/tests/ui/consts/recursive-const-in-impl.stderr
@@ -1,11 +1,12 @@
 error: queries overflow the depth limit!
-  --> $DIR/recursive-const-in-impl.rs:11:14
+  --> $DIR/recursive-const-in-impl.rs:11:20
    |
 LL |     println!("{}", Thing::<i32>::X);
-   |              ^^^^
+   |                    ^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "14"]` attribute to your crate (`recursive_const_in_impl`)
    = note: query depth increased by 9 when simplifying constant for the type system `main::promoted[1]`
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr
index 93ef136dc73..921cf08435c 100644
--- a/tests/ui/feature-gates/feature-gate-fn_align.stderr
+++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr
@@ -22,12 +22,10 @@ error[E0539]: malformed `align` attribute input
   --> $DIR/feature-gate-fn_align.rs:8:5
    |
 LL |     #[align]
-   |     ^^^^^^^^ expected this to be a list
-   |
-help: try changing it to one of the following valid forms of the attribute
-   |
-LL |     #[align(<alignment in bytes>)]
-   |            ++++++++++++++++++++++
+   |     ^^^^^^^^
+   |     |
+   |     expected this to be a list
+   |     help: must be of the form: `#[align(<alignment in bytes>)]`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs
index 77cc307c9f4..ed5a11270f8 100644
--- a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs
+++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs
@@ -11,5 +11,5 @@ fn none() {}
 
 #[optimize(banana)]
 //~^ ERROR the `#[optimize]` attribute is an experimental feature
-//~| ERROR E0722
+//~| ERROR malformed `optimize` attribute input [E0539]
 fn not_known() {}
diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
index 4e6e4ac2703..e7e62b4f989 100644
--- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
+++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
@@ -38,13 +38,16 @@ LL | #[optimize(banana)]
    = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0722]: invalid argument
-  --> $DIR/feature-gate-optimize_attribute.rs:12:12
+error[E0539]: malformed `optimize` attribute input
+  --> $DIR/feature-gate-optimize_attribute.rs:12:1
    |
 LL | #[optimize(banana)]
-   |            ^^^^^^
+   | ^^^^^^^^^^^------^^
+   | |          |
+   | |          valid arguments are `size`, `speed` or `none`
+   | help: must be of the form: `#[optimize(size|speed|none)]`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0658, E0722.
-For more information about an error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0539, E0658.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
index cd9ed0fb885..1dcd800cfc5 100644
--- a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
+++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
@@ -8,7 +8,7 @@ LL |     x.push(0);
    |     ^^^^^^^^^ mutable borrow occurs here
 ...
 LL |     println!("{h}");
-   |               --- immutable borrow later used here
+   |                - immutable borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/foreign-2021.rs:7:13
diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
index 676b6c12f52..aa0f6400091 100644
--- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr
+++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
@@ -23,7 +23,7 @@ LL |     x.push(1);
    |     ^^^^^^^^^ mutable borrow occurs here
 ...
 LL |     println!("{a}");
-   |               --- immutable borrow later used here
+   |                - immutable borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/migration-note.rs:16:13
@@ -99,7 +99,7 @@ LL |     x.push(1);
    |     ^ second mutable borrow occurs here
 ...
 LL |     println!("{a}");
-   |               --- first borrow later used here
+   |                - first borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/migration-note.rs:63:13
@@ -175,7 +175,7 @@ LL |     s.f = 1;
    |     ^^^^^^^ `s.f` is assigned to here but it was already borrowed
 ...
 LL |     println!("{a}");
-   |               --- borrow later used here
+   |                - borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/migration-note.rs:112:13
@@ -197,7 +197,7 @@ LL |     s.f = 1;
    |     ^^^^^^^ `s.f` is assigned to here but it was already borrowed
 ...
 LL |     println!("{a}");
-   |               --- borrow later used here
+   |                - borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/migration-note.rs:128:13
@@ -219,7 +219,7 @@ LL |     s.f;
    |     ^^^ use of borrowed `s.f`
 ...
 LL |     println!("{a}");
-   |               --- borrow later used here
+   |                - borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
   --> $DIR/migration-note.rs:140:13
diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr
index 66f9140f63c..b0d64b531cb 100644
--- a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr
+++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr
@@ -6,7 +6,7 @@ LL |     let g = some(&temp());
    |                   |
    |                   creates a temporary value which is freed while still in use
 LL |     println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}");
-   |                                                   ----- borrow later used here
+   |                                                    - borrow later used here
    |
 help: consider using a `let` binding to create a longer lived value
    |
diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr
index e58a43383f6..489987899cd 100644
--- a/tests/ui/macros/format-args-temporaries-in-write.stderr
+++ b/tests/ui/macros/format-args-temporaries-in-write.stderr
@@ -13,11 +13,6 @@ LL |     };
    |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
    |     |
    |     `mutex` dropped here while still borrowed
-   |
-help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
-   |
-LL |         write!(Out, "{}", mutex.lock()); /* no semicolon */
-   |                                        +
 
 error[E0597]: `mutex` does not live long enough
   --> $DIR/format-args-temporaries-in-write.rs:47:29
@@ -34,11 +29,6 @@ LL |     };
    |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
    |     |
    |     `mutex` dropped here while still borrowed
-   |
-help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
-   |
-LL |         writeln!(Out, "{}", mutex.lock()); /* no semicolon */
-   |                                          +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/sized/unsized-binding.rs b/tests/ui/sized/unsized-binding.rs
index 3b99b0f6e96..ce6c1527376 100644
--- a/tests/ui/sized/unsized-binding.rs
+++ b/tests/ui/sized/unsized-binding.rs
@@ -1,5 +1,5 @@
 fn main() {
     let x = *""; //~ ERROR E0277
-    println!("{}", x);
-    println!("{}", x);
+    drop(x);
+    drop(x);
 }
diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr
index c3cf7e13987..ddd143b967c 100644
--- a/tests/ui/suggestions/issue-97760.stderr
+++ b/tests/ui/suggestions/issue-97760.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-97760.rs:4:19
+  --> $DIR/issue-97760.rs:4:20
    |
 LL |         println!("{x}");
-   |                   ^^^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
+   |                    ^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
    |
    = help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr
index 2dca0c22033..0b2d71f97d0 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr
@@ -7,13 +7,5 @@ warning: unstable feature specified for `-Ctarget-feature`: `d`
    |
    = note: this feature is not stably supported; its behavior can change in the future
 
-warning: unstable feature specified for `-Ctarget-feature`: `f`
-   |
-   = note: this feature is not stably supported; its behavior can change in the future
-
-warning: unstable feature specified for `-Ctarget-feature`: `zicsr`
-   |
-   = note: this feature is not stably supported; its behavior can change in the future
-
-warning: 4 warnings emitted
+warning: 2 warnings emitted
 
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
index 302cceccf69..1006b078bab 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
@@ -24,5 +24,3 @@ pub trait Freeze {}
 
 //~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly
 //~? WARN unstable feature specified for `-Ctarget-feature`
-//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
-//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
index 2a0f5f01aef..79e89823c51 100644
--- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
@@ -1,4 +1,4 @@
-warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
+warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline-external-thunk` compiler flag instead
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
index f7b6cb16447..f5ff15df632 100644
--- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
@@ -1,4 +1,4 @@
-warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
index 4f2cd1d1a52..158cca08a76 100644
--- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
@@ -1,4 +1,4 @@
-warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs
index de3c44c3ed0..05c85860385 100644
--- a/tests/ui/target-feature/retpoline-target-feature-flag.rs
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs
@@ -16,6 +16,6 @@
 #![no_core]
 extern crate minicore;
 
-//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
-//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
-//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`
+//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`
+//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index c20f123b16e..5d6e3907d75 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -405,8 +405,10 @@ mod expressions {
     fn expr_format_args() {
         let expr;
         format_arguments::new_const(&[]);
-        format_arguments::new_v1(&[""],
-            &[format_argument::new_display(&expr)]);
+        {
+            super let args = [format_argument::new_display(&expr)];
+            format_arguments::new_v1(&[""], &args)
+        };
     }
 }
 mod items {
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index a5d943281ad..4af82924c7b 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -10,7 +10,9 @@ fn main() {
     let x = 1;
     // Should flatten to println!("a 123 b {x} xyz\n"):
     {
-        ::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"],
-                &[format_argument::new_display(&x)]));
+        ::std::io::_print({
+                super let args = [format_argument::new_display(&x)];
+                format_arguments::new_v1(&["a 123 b ", " xyz\n"], &args)
+            });
     };
 }