about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-15 00:14:11 +0000
committerbors <bors@rust-lang.org>2023-12-15 00:14:11 +0000
commit03515c6a2278aba8d64def5c522fb146e721368f (patch)
treea9b096290e84558dc5cf7b628dac00e97fceadf4
parentde686cbc65478db53e3d51c52497685e852cc092 (diff)
parent9648c485de28befa0e010cedbdb46ee965d8143d (diff)
downloadrust-03515c6a2278aba8d64def5c522fb146e721368f.tar.gz
rust-03515c6a2278aba8d64def5c522fb146e721368f.zip
Auto merge of #118957 - workingjubilee:rollup-2hcwnp3, r=workingjubilee
Rollup of 4 pull requests

Successful merges:

 - #118908 (Add all known `target_feature` configs to check-cfg)
 - #118933 (Cleanup errors handlers even more)
 - #118943 (update `measureme` to 10.1.2 to deduplicate `parking_lot`)
 - #118948 (Use the `Waker::noop` API in tests)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock43
-rw-r--r--compiler/rustc_borrowck/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs434
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs20
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs129
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs6
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs2
-rw-r--r--compiler/rustc_parse/src/errors.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs3
-rw-r--r--compiler/rustc_parse/src/lib.rs8
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs4
-rw-r--r--compiler/rustc_session/src/config.rs10
-rw-r--r--compiler/rustc_session/src/errors.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs11
-rw-r--r--compiler/rustc_session/src/session.rs2
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_target/src/target_features.rs429
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle_dyn.rs2
-rw-r--r--src/tools/miri/src/diagnostics.rs2
-rw-r--r--src/tools/rustfmt/src/parse/session.rs6
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/ui/async-await/in-trait/async-default-fn-overridden.rs24
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs25
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr26
-rw-r--r--tests/ui/check-cfg/well-known-values.rs6
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr34
-rw-r--r--tests/ui/coroutine/async_gen_fn_iter.rs24
-rw-r--r--tests/ui/dyn-star/dispatch-on-pin-mut.rs24
40 files changed, 651 insertions, 690 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a5bdc14fe99..98c030b3996 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -548,7 +548,7 @@ dependencies = [
  "futures",
  "if_chain",
  "itertools",
- "parking_lot 0.12.1",
+ "parking_lot",
  "quote",
  "regex",
  "rustc_tools_util",
@@ -2356,13 +2356,13 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "10.1.1"
+version = "10.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1930d162935fecd56fc4e0f6729eb3483bac1264542eb4ea31570b86a434b6bc"
+checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe"
 dependencies = [
  "log",
  "memmap2",
- "parking_lot 0.11.2",
+ "parking_lot",
  "perf-event-open-sys",
  "rustc-hash",
  "smallvec",
@@ -2782,37 +2782,12 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
-dependencies = [
- "instant",
- "lock_api",
- "parking_lot_core 0.8.6",
-]
-
-[[package]]
-name = "parking_lot"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.8",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
-dependencies = [
- "cfg-if",
- "instant",
- "libc",
- "redox_syscall 0.2.16",
- "smallvec",
- "winapi",
+ "parking_lot_core",
 ]
 
 [[package]]
@@ -3682,7 +3657,7 @@ dependencies = [
  "libc",
  "measureme",
  "memmap2",
- "parking_lot 0.12.1",
+ "parking_lot",
  "portable-atomic",
  "rustc-hash",
  "rustc-rayon",
@@ -4417,7 +4392,7 @@ dependencies = [
 name = "rustc_query_system"
 version = "0.0.0"
 dependencies = [
- "parking_lot 0.12.1",
+ "parking_lot",
  "rustc-rayon-core",
  "rustc_ast",
  "rustc_data_structures",
@@ -5134,7 +5109,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
 dependencies = [
  "new_debug_unreachable",
  "once_cell",
- "parking_lot 0.12.1",
+ "parking_lot",
  "phf_shared",
  "precomputed-hash",
  "serde",
@@ -5659,7 +5634,7 @@ dependencies = [
  "matchers",
  "nu-ansi-term",
  "once_cell",
- "parking_lot 0.12.1",
+ "parking_lot",
  "regex",
  "sharded-slab",
  "smallvec",
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 3d3fd412ae0..7e0e598cd9f 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2502,8 +2502,8 @@ mod error {
             if !self.errors.buffered.is_empty() {
                 self.errors.buffered.sort_by_key(|diag| diag.sort_span);
 
-                for mut diag in self.errors.buffered.drain(..) {
-                    self.infcx.tcx.sess.diagnostic().emit_diagnostic(&mut diag);
+                for diag in self.errors.buffered.drain(..) {
+                    self.infcx.tcx.sess.diagnostic().emit_diagnostic(diag);
                 }
             }
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 0a3af2c2e13..3d02cd72e54 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -453,7 +453,7 @@ impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
             rustc::untranslatable_diagnostic,
             reason = "cannot translate user-provided messages"
         )]
-        let mut diag = handler.struct_diagnostic(self.msg_from_user.to_string());
+        let mut diag = handler.struct_err(self.msg_from_user.to_string());
         diag.set_span(self.span);
         diag
     }
@@ -804,7 +804,7 @@ pub(crate) struct AsmClobberNoReg {
 impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut diag =
-            handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
+            handler.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
         diag.set_span(self.spans.clone());
         // eager translation as `span_labels` takes `AsRef<str>`
         let lbl1 = handler.eagerly_translate_to_string(
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 1248fdcd259..2aa84f26797 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -2,12 +2,10 @@
 use gccjit::Context;
 use smallvec::{smallvec, SmallVec};
 
-use rustc_codegen_ssa::target_features::{
-    supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
-};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
 use rustc_session::Session;
+use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
 
 use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
 
@@ -44,7 +42,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     );
 
     // -Ctarget-features
-    let supported_features = supported_target_features(sess);
+    let supported_features = sess.target.supported_target_features();
     let mut featsmap = FxHashMap::default();
     let feats = sess.opts.cg.target_feature
         .split(',')
@@ -187,7 +185,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
 // 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]> {
-    for tied in tied_target_features(sess) {
+    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());
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index d54057615d2..0ececc5dda0 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -97,7 +97,6 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_codegen_ssa::base::codegen_crate;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
-use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::IntoDynSyncSend;
 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods};
@@ -397,7 +396,9 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
 }
 
 pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec<Symbol> {
-    supported_target_features(sess)
+    sess
+        .target
+        .supported_target_features()
         .iter()
         .filter_map(
             |&(feature, gate)| {
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 57ea13ddcd6..e6e37a02335 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -107,7 +107,8 @@ impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> {
         let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
         let message = handler.eagerly_translate_to_string(message.clone(), diag.args());
 
-        let mut diag = handler.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config);
+        let mut diag =
+            handler.struct_almost_fatal(fluent::codegen_llvm_parse_target_machine_config);
         diag.set_arg("error", message);
         diag
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 93cb7327a01..08519723eba 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -5,9 +5,6 @@ use crate::errors::{
 };
 use crate::llvm;
 use libc::c_int;
-use rustc_codegen_ssa::target_features::{
-    supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
-};
 use rustc_codegen_ssa::traits::PrintBackendInfo;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::small_c_str::SmallCStr;
@@ -17,6 +14,7 @@ use rustc_session::config::{PrintKind, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
+use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
 
 use std::ffi::{c_char, c_void, CStr, CString};
 use std::path::Path;
@@ -278,7 +276,7 @@ pub fn check_tied_features(
     features: &FxHashMap<&str, bool>,
 ) -> Option<&'static [&'static str]> {
     if !features.is_empty() {
-        for tied in tied_target_features(sess) {
+        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());
@@ -294,7 +292,8 @@ pub fn check_tied_features(
 /// Must express features in the way Rust understands them
 pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
     let target_machine = create_informational_target_machine(sess);
-    supported_target_features(sess)
+    sess.target
+        .supported_target_features()
         .iter()
         .filter_map(|&(feature, gate)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
@@ -362,7 +361,9 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
 fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) {
     let mut llvm_target_features = llvm_target_features(tm);
     let mut known_llvm_target_features = FxHashSet::<&'static str>::default();
-    let mut rustc_target_features = supported_target_features(sess)
+    let mut rustc_target_features = sess
+        .target
+        .supported_target_features()
         .iter()
         .map(|(feature, _gate)| {
             // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
@@ -515,7 +516,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     );
 
     // -Ctarget-features
-    let supported_features = supported_target_features(sess);
+    let supported_features = sess.target.supported_target_features();
     let mut featsmap = FxHashMap::default();
     let feats = sess
         .opts
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 618a72272e5..40fd8c5c1d6 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1848,7 +1848,7 @@ impl SharedEmitterMain {
                         d.code(code);
                     }
                     d.replace_args(diag.args);
-                    handler.emit_diagnostic(&mut d);
+                    handler.emit_diagnostic(d);
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
                     let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index c3b8859c779..0b9b08c6a24 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -11,436 +11,10 @@ use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-/// Features that control behaviour of rustc, rather than the codegen.
-pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
-
-/// Stability information for target features.
-#[derive(Debug, Clone, Copy)]
-pub enum Stability {
-    /// This target feature is stable, it can be used in `#[target_feature]` and
-    /// `#[cfg(target_feature)]`.
-    Stable,
-    /// This target feature is unstable; using it in `#[target_feature]` or `#[cfg(target_feature)]`
-    /// requires enabling the given nightly feature.
-    Unstable(Symbol),
-}
-use Stability::*;
-
-impl Stability {
-    fn as_feature_name(self) -> Option<Symbol> {
-        match self {
-            Stable => None,
-            Unstable(s) => Some(s),
-        }
-    }
-
-    pub fn is_stable(self) -> bool {
-        matches!(self, Stable)
-    }
-}
-
-// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
-// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with
-// `-Ctarget-feature`.
-//
-// When adding features to the below lists
-// check whether they're named already elsewhere in rust
-// e.g. in stdarch and whether the given name matches LLVM's
-// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted.
-//
-// Also note that all target features listed here must be purely additive: for target_feature 1.1 to
-// be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a
-// per-function level, since we would then allow safe calls from functions with `+soft-float` to
-// functions without that feature!
-//
-// When adding a new feature, be particularly mindful of features that affect function ABIs. Those
-// need to be treated very carefully to avoid introducing unsoundness! This often affects features
-// that enable/disable hardfloat support (see https://github.com/rust-lang/rust/issues/116344 for an
-// example of this going wrong), but features enabling new SIMD registers are also a concern (see
-// https://github.com/rust-lang/rust/issues/116558 for an example of this going wrong).
-//
-// Stabilizing a target feature requires t-lang approval.
-
-const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("aclass", Unstable(sym::arm_target_feature)),
-    ("aes", Unstable(sym::arm_target_feature)),
-    ("crc", Unstable(sym::arm_target_feature)),
-    ("d32", Unstable(sym::arm_target_feature)),
-    ("dotprod", Unstable(sym::arm_target_feature)),
-    ("dsp", Unstable(sym::arm_target_feature)),
-    ("fp-armv8", Unstable(sym::arm_target_feature)),
-    ("i8mm", Unstable(sym::arm_target_feature)),
-    ("mclass", Unstable(sym::arm_target_feature)),
-    ("neon", Unstable(sym::arm_target_feature)),
-    ("rclass", Unstable(sym::arm_target_feature)),
-    ("sha2", Unstable(sym::arm_target_feature)),
-    // This is needed for inline assembly, but shouldn't be stabilized as-is
-    // since it should be enabled per-function using #[instruction_set], not
-    // #[target_feature].
-    ("thumb-mode", Unstable(sym::arm_target_feature)),
-    ("thumb2", Unstable(sym::arm_target_feature)),
-    ("trustzone", Unstable(sym::arm_target_feature)),
-    ("v5te", Unstable(sym::arm_target_feature)),
-    ("v6", Unstable(sym::arm_target_feature)),
-    ("v6k", Unstable(sym::arm_target_feature)),
-    ("v6t2", Unstable(sym::arm_target_feature)),
-    ("v7", Unstable(sym::arm_target_feature)),
-    ("v8", Unstable(sym::arm_target_feature)),
-    ("vfp2", Unstable(sym::arm_target_feature)),
-    ("vfp3", Unstable(sym::arm_target_feature)),
-    ("vfp4", Unstable(sym::arm_target_feature)),
-    ("virtualization", Unstable(sym::arm_target_feature)),
-    // tidy-alphabetical-end
-];
-
-const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    // FEAT_AES
-    ("aes", Stable),
-    // FEAT_BF16
-    ("bf16", Stable),
-    // FEAT_BTI
-    ("bti", Stable),
-    // FEAT_CRC
-    ("crc", Stable),
-    // FEAT_DIT
-    ("dit", Stable),
-    // FEAT_DotProd
-    ("dotprod", Stable),
-    // FEAT_DPB
-    ("dpb", Stable),
-    // FEAT_DPB2
-    ("dpb2", Stable),
-    // FEAT_F32MM
-    ("f32mm", Stable),
-    // FEAT_F64MM
-    ("f64mm", Stable),
-    // FEAT_FCMA
-    ("fcma", Stable),
-    // FEAT_FHM
-    ("fhm", Stable),
-    // FEAT_FLAGM
-    ("flagm", Stable),
-    // FEAT_FP16
-    ("fp16", Stable),
-    // FEAT_FRINTTS
-    ("frintts", Stable),
-    // FEAT_I8MM
-    ("i8mm", Stable),
-    // FEAT_JSCVT
-    ("jsconv", Stable),
-    // FEAT_LOR
-    ("lor", Stable),
-    // FEAT_LSE
-    ("lse", Stable),
-    // FEAT_MTE
-    ("mte", Stable),
-    // FEAT_AdvSimd & FEAT_FP
-    ("neon", Stable),
-    // FEAT_PAUTH (address authentication)
-    ("paca", Stable),
-    // FEAT_PAUTH (generic authentication)
-    ("pacg", Stable),
-    // FEAT_PAN
-    ("pan", Stable),
-    // FEAT_PMUv3
-    ("pmuv3", Stable),
-    // FEAT_RAND
-    ("rand", Stable),
-    // FEAT_RAS
-    ("ras", Stable),
-    // FEAT_RCPC
-    ("rcpc", Stable),
-    // FEAT_RCPC2
-    ("rcpc2", Stable),
-    // FEAT_RDM
-    ("rdm", Stable),
-    // FEAT_SB
-    ("sb", Stable),
-    // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", Stable),
-    // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", Stable),
-    // FEAT_SM3 & FEAT_SM4
-    ("sm4", Stable),
-    // FEAT_SPE
-    ("spe", Stable),
-    // FEAT_SSBS
-    ("ssbs", Stable),
-    // FEAT_SVE
-    ("sve", Stable),
-    // FEAT_SVE2
-    ("sve2", Stable),
-    // FEAT_SVE2_AES
-    ("sve2-aes", Stable),
-    // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", Stable),
-    // FEAT_SVE2_SHA3
-    ("sve2-sha3", Stable),
-    // FEAT_SVE2_SM4
-    ("sve2-sm4", Stable),
-    // FEAT_TME
-    ("tme", Stable),
-    ("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
-    // FEAT_VHE
-    ("vh", Stable),
-    // tidy-alphabetical-end
-];
-
-const AARCH64_TIED_FEATURES: &[&[&str]] = &[
-    &["paca", "pacg"], // Together these represent `pauth` in LLVM
-];
-
-const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("adx", Stable),
-    ("aes", Stable),
-    ("avx", Stable),
-    ("avx2", Stable),
-    ("avx512bf16", Unstable(sym::avx512_target_feature)),
-    ("avx512bitalg", Unstable(sym::avx512_target_feature)),
-    ("avx512bw", Unstable(sym::avx512_target_feature)),
-    ("avx512cd", Unstable(sym::avx512_target_feature)),
-    ("avx512dq", Unstable(sym::avx512_target_feature)),
-    ("avx512er", Unstable(sym::avx512_target_feature)),
-    ("avx512f", Unstable(sym::avx512_target_feature)),
-    ("avx512ifma", Unstable(sym::avx512_target_feature)),
-    ("avx512pf", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi2", Unstable(sym::avx512_target_feature)),
-    ("avx512vl", Unstable(sym::avx512_target_feature)),
-    ("avx512vnni", Unstable(sym::avx512_target_feature)),
-    ("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
-    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
-    ("bmi1", Stable),
-    ("bmi2", Stable),
-    ("cmpxchg16b", Stable),
-    ("ermsb", Unstable(sym::ermsb_target_feature)),
-    ("f16c", Stable),
-    ("fma", Stable),
-    ("fxsr", Stable),
-    ("gfni", Unstable(sym::avx512_target_feature)),
-    ("lzcnt", Stable),
-    ("movbe", Stable),
-    ("pclmulqdq", Stable),
-    ("popcnt", Stable),
-    ("rdrand", Stable),
-    ("rdseed", Stable),
-    ("rtm", Unstable(sym::rtm_target_feature)),
-    ("sha", Stable),
-    ("sse", Stable),
-    ("sse2", Stable),
-    ("sse3", Stable),
-    ("sse4.1", Stable),
-    ("sse4.2", Stable),
-    ("sse4a", Unstable(sym::sse4a_target_feature)),
-    ("ssse3", Stable),
-    ("tbm", Unstable(sym::tbm_target_feature)),
-    ("vaes", Unstable(sym::avx512_target_feature)),
-    ("vpclmulqdq", Unstable(sym::avx512_target_feature)),
-    ("xsave", Stable),
-    ("xsavec", Stable),
-    ("xsaveopt", Stable),
-    ("xsaves", Stable),
-    // tidy-alphabetical-end
-];
-
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("hvx", Unstable(sym::hexagon_target_feature)),
-    ("hvx-length128b", Unstable(sym::hexagon_target_feature)),
-    // tidy-alphabetical-end
-];
-
-const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("altivec", Unstable(sym::powerpc_target_feature)),
-    ("power10-vector", Unstable(sym::powerpc_target_feature)),
-    ("power8-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power8-vector", Unstable(sym::powerpc_target_feature)),
-    ("power9-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power9-vector", Unstable(sym::powerpc_target_feature)),
-    ("vsx", Unstable(sym::powerpc_target_feature)),
-    // tidy-alphabetical-end
-];
-
-const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("fp64", Unstable(sym::mips_target_feature)),
-    ("msa", Unstable(sym::mips_target_feature)),
-    ("virt", Unstable(sym::mips_target_feature)),
-    // tidy-alphabetical-end
-];
-
-const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("a", Stable),
-    ("c", Stable),
-    ("d", Unstable(sym::riscv_target_feature)),
-    ("e", Unstable(sym::riscv_target_feature)),
-    ("f", Unstable(sym::riscv_target_feature)),
-    ("fast-unaligned-access", Unstable(sym::riscv_target_feature)),
-    ("m", Stable),
-    ("relax", Unstable(sym::riscv_target_feature)),
-    ("v", Unstable(sym::riscv_target_feature)),
-    ("zba", Stable),
-    ("zbb", Stable),
-    ("zbc", Stable),
-    ("zbkb", Stable),
-    ("zbkc", Stable),
-    ("zbkx", Stable),
-    ("zbs", Stable),
-    ("zdinx", Unstable(sym::riscv_target_feature)),
-    ("zfh", Unstable(sym::riscv_target_feature)),
-    ("zfhmin", Unstable(sym::riscv_target_feature)),
-    ("zfinx", Unstable(sym::riscv_target_feature)),
-    ("zhinx", Unstable(sym::riscv_target_feature)),
-    ("zhinxmin", Unstable(sym::riscv_target_feature)),
-    ("zk", Stable),
-    ("zkn", Stable),
-    ("zknd", Stable),
-    ("zkne", Stable),
-    ("zknh", Stable),
-    ("zkr", Stable),
-    ("zks", Stable),
-    ("zksed", Stable),
-    ("zksh", Stable),
-    ("zkt", Stable),
-    // tidy-alphabetical-end
-];
-
-const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("atomics", Unstable(sym::wasm_target_feature)),
-    ("bulk-memory", Unstable(sym::wasm_target_feature)),
-    ("exception-handling", Unstable(sym::wasm_target_feature)),
-    ("multivalue", Unstable(sym::wasm_target_feature)),
-    ("mutable-globals", Unstable(sym::wasm_target_feature)),
-    ("nontrapping-fptoint", Unstable(sym::wasm_target_feature)),
-    ("reference-types", Unstable(sym::wasm_target_feature)),
-    ("relaxed-simd", Unstable(sym::wasm_target_feature)),
-    ("sign-ext", Unstable(sym::wasm_target_feature)),
-    ("simd128", Stable),
-    // tidy-alphabetical-end
-];
-
-const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
-
-const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("10e60", Unstable(sym::csky_target_feature)),
-    ("2e3", Unstable(sym::csky_target_feature)),
-    ("3e3r1", Unstable(sym::csky_target_feature)),
-    ("3e3r2", Unstable(sym::csky_target_feature)),
-    ("3e3r3", Unstable(sym::csky_target_feature)),
-    ("3e7", Unstable(sym::csky_target_feature)),
-    ("7e10", Unstable(sym::csky_target_feature)),
-    ("cache", Unstable(sym::csky_target_feature)),
-    ("doloop", Unstable(sym::csky_target_feature)),
-    ("dsp1e2", Unstable(sym::csky_target_feature)),
-    ("dspe60", Unstable(sym::csky_target_feature)),
-    ("e1", Unstable(sym::csky_target_feature)),
-    ("e2", Unstable(sym::csky_target_feature)),
-    ("edsp", Unstable(sym::csky_target_feature)),
-    ("elrw", Unstable(sym::csky_target_feature)),
-    ("float1e2", Unstable(sym::csky_target_feature)),
-    ("float1e3", Unstable(sym::csky_target_feature)),
-    ("float3e4", Unstable(sym::csky_target_feature)),
-    ("float7e60", Unstable(sym::csky_target_feature)),
-    ("floate1", Unstable(sym::csky_target_feature)),
-    ("hard-tp", Unstable(sym::csky_target_feature)),
-    ("high-registers", Unstable(sym::csky_target_feature)),
-    ("hwdiv", Unstable(sym::csky_target_feature)),
-    ("mp", Unstable(sym::csky_target_feature)),
-    ("mp1e2", Unstable(sym::csky_target_feature)),
-    ("nvic", Unstable(sym::csky_target_feature)),
-    ("trust", Unstable(sym::csky_target_feature)),
-    ("vdsp2e60f", Unstable(sym::csky_target_feature)),
-    ("vdspv1", Unstable(sym::csky_target_feature)),
-    ("vdspv2", Unstable(sym::csky_target_feature)),
-    // tidy-alphabetical-end
-    //fpu
-    // tidy-alphabetical-start
-    ("fdivdu", Unstable(sym::csky_target_feature)),
-    ("fpuv2_df", Unstable(sym::csky_target_feature)),
-    ("fpuv2_sf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_df", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hi", Unstable(sym::csky_target_feature)),
-    ("fpuv3_sf", Unstable(sym::csky_target_feature)),
-    ("hard-float", Unstable(sym::csky_target_feature)),
-    ("hard-float-abi", Unstable(sym::csky_target_feature)),
-    // tidy-alphabetical-end
-];
-
-const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
-    // tidy-alphabetical-start
-    ("d", Unstable(sym::loongarch_target_feature)),
-    ("f", Unstable(sym::loongarch_target_feature)),
-    ("lasx", Unstable(sym::loongarch_target_feature)),
-    ("lbt", Unstable(sym::loongarch_target_feature)),
-    ("lsx", Unstable(sym::loongarch_target_feature)),
-    ("lvz", Unstable(sym::loongarch_target_feature)),
-    ("ual", Unstable(sym::loongarch_target_feature)),
-    // tidy-alphabetical-end
-];
-
-/// When rustdoc is running, provide a list of all known features so that all their respective
-/// primitives may be documented.
-///
-/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
-pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
-    std::iter::empty()
-        .chain(ARM_ALLOWED_FEATURES.iter())
-        .chain(AARCH64_ALLOWED_FEATURES.iter())
-        .chain(X86_ALLOWED_FEATURES.iter())
-        .chain(HEXAGON_ALLOWED_FEATURES.iter())
-        .chain(POWERPC_ALLOWED_FEATURES.iter())
-        .chain(MIPS_ALLOWED_FEATURES.iter())
-        .chain(RISCV_ALLOWED_FEATURES.iter())
-        .chain(WASM_ALLOWED_FEATURES.iter())
-        .chain(BPF_ALLOWED_FEATURES.iter())
-        .chain(CSKY_ALLOWED_FEATURES)
-        .chain(LOONGARCH_ALLOWED_FEATURES)
-        .cloned()
-}
-
-pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Stability)] {
-    match &*sess.target.arch {
-        "arm" => ARM_ALLOWED_FEATURES,
-        "aarch64" => AARCH64_ALLOWED_FEATURES,
-        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
-        "hexagon" => HEXAGON_ALLOWED_FEATURES,
-        "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_ALLOWED_FEATURES,
-        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
-        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
-        "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
-        "bpf" => BPF_ALLOWED_FEATURES,
-        "csky" => CSKY_ALLOWED_FEATURES,
-        "loongarch64" => LOONGARCH_ALLOWED_FEATURES,
-        _ => &[],
-    }
-}
-
-pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
-    match &*sess.target.arch {
-        "aarch64" => AARCH64_TIED_FEATURES,
-        _ => &[],
-    }
-}
-
 pub fn from_target_feature(
     tcx: TyCtxt<'_>,
     attr: &ast::Attribute,
@@ -562,9 +136,13 @@ pub(crate) fn provide(providers: &mut Providers) {
             if tcx.sess.opts.actually_rustdoc {
                 // rustdoc needs to be able to document functions that use all the features, so
                 // whitelist them all
-                all_known_features().map(|(a, b)| (a.to_string(), b.as_feature_name())).collect()
+                rustc_target::target_features::all_known_features()
+                    .map(|(a, b)| (a.to_string(), b.as_feature_name()))
+                    .collect()
             } else {
-                supported_target_features(tcx.sess)
+                tcx.sess
+                    .target
+                    .supported_target_features()
                     .iter()
                     .map(|&(a, b)| (a.to_string(), b.as_feature_name()))
                     .collect()
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 5380d3071d6..bb17602d3ba 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -277,8 +277,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         // "secondary" errors if they occurred.
         let secondary_errors = mem::take(&mut self.secondary_errors);
         if self.error_emitted.is_none() {
-            for mut error in secondary_errors {
-                self.tcx.sess.diagnostic().emit_diagnostic(&mut error);
+            for error in secondary_errors {
+                self.tcx.sess.diagnostic().emit_diagnostic(error);
             }
         } else {
             assert!(self.tcx.sess.has_errors().is_some());
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index b8bd86a72e4..315e47c0971 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -132,7 +132,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                let guar = handler.emit_diagnostic(&mut db.inner.diagnostic);
+                let guar = handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
 
                 // Only allow a guarantee if the `level` wasn't switched to a
                 // non-error - the field isn't `pub`, but the whole `Diagnostic`
@@ -181,7 +181,7 @@ impl EmissionGuarantee for () {
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic(&mut db.inner.diagnostic);
+                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -207,7 +207,7 @@ impl EmissionGuarantee for Noted {
             // First `.emit()` call, the `&Handler` is still available.
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
-                handler.emit_diagnostic(&mut db.inner.diagnostic);
+                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -236,7 +236,7 @@ impl EmissionGuarantee for Bug {
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic(&mut db.inner.diagnostic);
+                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -260,7 +260,7 @@ impl EmissionGuarantee for ! {
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic(&mut db.inner.diagnostic);
+                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -284,7 +284,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
             DiagnosticBuilderState::Emittable(handler) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic(&mut db.inner.diagnostic);
+                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -365,7 +365,9 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         }
     }
 
-    /// Emit the diagnostic.
+    /// Emit the diagnostic. Does not consume `self`, which may be surprising,
+    /// but there are various places that rely on continuing to use `self`
+    /// after calling `emit`.
     #[track_caller]
     pub fn emit(&mut self) -> G {
         G::diagnostic_builder_emit_producing_guarantee(self)
@@ -640,13 +642,13 @@ impl Drop for DiagnosticBuilderInner<'_> {
             // No `.emit()` or `.cancel()` calls.
             DiagnosticBuilderState::Emittable(handler) => {
                 if !panicking() {
-                    handler.emit_diagnostic(&mut Diagnostic::new(
+                    handler.emit_diagnostic(Diagnostic::new(
                         Level::Bug,
                         DiagnosticMessage::from(
                             "the following error was constructed but not emitted",
                         ),
                     ));
-                    handler.emit_diagnostic(&mut self.diagnostic);
+                    handler.emit_diagnostic_without_consuming(&mut self.diagnostic);
                     panic!("error was constructed but not emitted");
                 }
             }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 3f257fdd9cf..379883a0c18 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -581,7 +581,7 @@ impl Emitter for SilentEmitter {
             if let Some(ref note) = self.fatal_note {
                 d.note(note.clone());
             }
-            self.fatal_handler.emit_diagnostic(&mut d);
+            self.fatal_handler.emit_diagnostic(d);
         }
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index daa8a7706eb..cf73c638d85 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -585,11 +585,6 @@ impl Handler {
         self
     }
 
-    pub fn treat_err_as_bug(mut self, treat_err_as_bug: NonZeroUsize) -> Self {
-        self.inner.get_mut().flags.treat_err_as_bug = Some(treat_err_as_bug);
-        self
-    }
-
     pub fn with_flags(mut self, flags: HandlerFlags) -> Self {
         self.inner.get_mut().flags = flags;
         self
@@ -727,7 +722,12 @@ impl Handler {
         self.inner.borrow_mut().emit_stashed_diagnostics()
     }
 
-    /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`.
+    /// Construct a builder with the `msg` at the level appropriate for the
+    /// specific `EmissionGuarantee`.
+    ///
+    /// Note: this is necessary for `derive(Diagnostic)`, but shouldn't be used
+    /// outside of that. Instead use `struct_err`, `struct_warn`, etc., which
+    /// make the diagnostic kind clearer.
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_diagnostic<G: EmissionGuarantee>(
@@ -942,13 +942,23 @@ impl Handler {
         result
     }
 
-    /// Construct a builder at the `Error` level with the `msg`.
+    /// Construct a builder at the `Fatal` level with the `msg`.
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         DiagnosticBuilder::new(self, Level::Fatal, msg)
     }
 
+    /// Construct a builder at the `Fatal` level with the `msg`, that doesn't abort.
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_almost_fatal(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, FatalError> {
+        DiagnosticBuilder::new(self, Level::Fatal, msg)
+    }
+
     /// Construct a builder at the `Help` level with the `msg`.
     #[rustc_lint_diagnostics]
     pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
@@ -965,8 +975,7 @@ impl Handler {
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
-        FatalError.raise()
+        self.struct_span_fatal(span, msg).emit()
     }
 
     #[rustc_lint_diagnostics]
@@ -977,8 +986,7 @@ impl Handler {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> ! {
-        self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
-        FatalError.raise()
+        self.struct_span_fatal_with_code(span, msg, code).emit()
     }
 
     #[rustc_lint_diagnostics]
@@ -988,7 +996,7 @@ impl Handler {
         span: impl Into<MultiSpan>,
         msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
-        self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
+        self.struct_span_err(span, msg).emit()
     }
 
     #[rustc_lint_diagnostics]
@@ -999,17 +1007,13 @@ impl Handler {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> ErrorGuaranteed {
-        self.emit_diag_at_span(
-            Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
-            span,
-        )
-        .unwrap()
+        self.struct_span_err_with_code(span, msg, code).emit()
     }
 
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
+        self.struct_span_warn(span, msg).emit()
     }
 
     #[rustc_lint_diagnostics]
@@ -1020,10 +1024,10 @@ impl Handler {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) {
-        self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
+        self.struct_span_warn_with_code(span, msg, code).emit()
     }
 
-    pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<String>) -> ! {
+    pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
         self.inner.borrow_mut().span_bug(span, msg)
     }
 
@@ -1035,7 +1039,7 @@ impl Handler {
     pub fn span_delayed_bug(
         &self,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<String>,
+        msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
         let mut inner = self.inner.borrow_mut();
 
@@ -1046,11 +1050,11 @@ impl Handler {
             inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get()
         }) {
             // FIXME: don't abort here if report_delayed_bugs is off
-            inner.span_bug(sp, msg.into());
+            inner.span_bug(sp, msg);
         }
-        let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
-        diagnostic.set_span(sp.into());
-        inner.emit_diagnostic(&mut diagnostic).unwrap()
+        let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
+        diagnostic.set_span(sp);
+        inner.emit_diagnostic(diagnostic).unwrap()
     }
 
     // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
@@ -1060,7 +1064,7 @@ impl Handler {
 
         let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
         if inner.flags.report_delayed_bugs {
-            inner.emit_diagnostic(&mut diagnostic);
+            inner.emit_diagnostic_without_consuming(&mut diagnostic);
         }
         let backtrace = std::backtrace::Backtrace::capture();
         inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
@@ -1068,20 +1072,22 @@ impl Handler {
 
     #[track_caller]
     pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
+        let mut diag = Diagnostic::new(Bug, msg);
+        diag.set_span(span);
+        self.emit_diagnostic(diag);
     }
 
     #[track_caller]
     #[rustc_lint_diagnostics]
     pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
+        self.struct_span_note(span, msg).emit()
     }
 
     #[track_caller]
     #[rustc_lint_diagnostics]
     pub fn struct_span_note(
         &self,
-        span: Span,
+        span: impl Into<MultiSpan>,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ()> {
         let mut db = DiagnosticBuilder::new(self, Note, msg);
@@ -1091,22 +1097,22 @@ impl Handler {
 
     #[rustc_lint_diagnostics]
     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        DiagnosticBuilder::<FatalError>::new(self, Fatal, msg).emit().raise()
+        self.struct_fatal(msg).emit()
     }
 
     #[rustc_lint_diagnostics]
     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        DiagnosticBuilder::<ErrorGuaranteed>::new(self, Error { lint: false }, msg).emit()
+        self.struct_err(msg).emit()
     }
 
     #[rustc_lint_diagnostics]
     pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
-        DiagnosticBuilder::<()>::new(self, Warning(None), msg).emit();
+        self.struct_warn(msg).emit()
     }
 
     #[rustc_lint_diagnostics]
     pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
-        DiagnosticBuilder::<()>::new(self, Note, msg).emit();
+        self.struct_note(msg).emit()
     }
 
     pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
@@ -1181,10 +1187,10 @@ impl Handler {
                 DiagnosticMessage::Str(warnings),
             )),
             (_, 0) => {
-                inner.emit_diagnostic(&mut Diagnostic::new(Fatal, errors));
+                inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
             }
             (_, _) => {
-                inner.emit_diagnostic(&mut Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
+                inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
             }
         }
 
@@ -1251,8 +1257,17 @@ impl Handler {
         self.inner.borrow_mut().emitter.emit_diagnostic(&db);
     }
 
-    pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
-        self.inner.borrow_mut().emit_diagnostic(diagnostic)
+    pub fn emit_diagnostic(&self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
+        self.emit_diagnostic_without_consuming(&mut diagnostic)
+    }
+
+    // It's unfortunate this exists. `emit_diagnostic` is preferred, because it
+    // consumes the diagnostic, thus ensuring it is emitted just once.
+    pub(crate) fn emit_diagnostic_without_consuming(
+        &self,
+        diagnostic: &mut Diagnostic,
+    ) -> Option<ErrorGuaranteed> {
+        self.inner.borrow_mut().emit_diagnostic_without_consuming(diagnostic)
     }
 
     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
@@ -1327,14 +1342,6 @@ impl Handler {
         note.into_diagnostic(self)
     }
 
-    fn emit_diag_at_span(
-        &self,
-        mut diag: Diagnostic,
-        sp: impl Into<MultiSpan>,
-    ) -> Option<ErrorGuaranteed> {
-        self.emit_diagnostic(diag.set_span(sp))
-    }
-
     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
         self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
     }
@@ -1374,7 +1381,7 @@ impl Handler {
                 // Here the diagnostic is given back to `emit_diagnostic` where it was first
                 // intercepted. Now it should be processed as usual, since the unstable expectation
                 // id is now stable.
-                inner.emit_diagnostic(&mut diag);
+                inner.emit_diagnostic(diag);
             }
         }
 
@@ -1416,7 +1423,7 @@ impl HandlerInner {
         let has_errors = self.has_errors();
         let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
         let mut reported = None;
-        for mut diag in diags {
+        for diag in diags {
             // Decrement the count tracking the stash; emitting will increment it.
             if diag.is_error() {
                 if matches!(diag.level, Level::Error { lint: true }) {
@@ -1436,14 +1443,20 @@ impl HandlerInner {
                     }
                 }
             }
-            let reported_this = self.emit_diagnostic(&mut diag);
+            let reported_this = self.emit_diagnostic(diag);
             reported = reported.or(reported_this);
         }
         reported
     }
 
-    // FIXME(eddyb) this should ideally take `diagnostic` by value.
-    fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
+    fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
+        self.emit_diagnostic_without_consuming(&mut diagnostic)
+    }
+
+    fn emit_diagnostic_without_consuming(
+        &mut self,
+        diagnostic: &mut Diagnostic,
+    ) -> Option<ErrorGuaranteed> {
         if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug()
         {
             diagnostic.level = Level::Bug;
@@ -1579,17 +1592,15 @@ impl HandlerInner {
     }
 
     #[track_caller]
-    fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<String>) -> ! {
-        self.emit_diag_at_span(Diagnostic::new(Bug, msg.into()), sp);
+    fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
+        let mut diag = Diagnostic::new(Bug, msg);
+        diag.set_span(sp);
+        self.emit_diagnostic(diag);
         panic::panic_any(ExplicitBug);
     }
 
-    fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
-        self.emit_diagnostic(diag.set_span(sp));
-    }
-
     fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
-        self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
+        self.emit_diagnostic(Diagnostic::new(FailureNote, msg));
     }
 
     fn flush_delayed(
@@ -1621,7 +1632,7 @@ impl HandlerInner {
             if no_bugs {
                 // Put the overall explanation before the `DelayedBug`s, to
                 // frame them better (e.g. separate warnings from them).
-                self.emit_diagnostic(&mut Diagnostic::new(Bug, explanation));
+                self.emit_diagnostic(Diagnostic::new(Bug, explanation));
                 no_bugs = false;
             }
 
@@ -1636,7 +1647,7 @@ impl HandlerInner {
             }
             bug.level = Level::Bug;
 
-            self.emit_diagnostic(&mut bug);
+            self.emit_diagnostic(bug);
         }
 
         // Panic with `DelayedBugPanic` to avoid "unexpected panic" messages.
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 11db4bb4017..d75556ac7c4 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1145,7 +1145,7 @@ impl<'a> ExtCtxt<'a> {
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
         self.sess.diagnostic().span_err(sp, msg);
     }
-    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! {
+    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
         self.sess.diagnostic().span_bug(sp, msg);
     }
     pub fn trace_macros_diag(&mut self) {
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5308e338d7f..d2c26668ea8 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -502,7 +502,7 @@ impl server::FreeFunctions for Rustc<'_, '_> {
                 None,
             );
         }
-        self.sess().span_diagnostic.emit_diagnostic(&mut diag);
+        self.sess().span_diagnostic.emit_diagnostic(diag);
     }
 }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 1609c036fbd..5e562d9453f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -504,8 +504,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
             if !errors_buffer.is_empty() {
                 errors_buffer.sort_by_key(|diag| diag.span.primary_span());
-                for mut diag in errors_buffer {
-                    self.tcx().sess.diagnostic().emit_diagnostic(&mut diag);
+                for diag in errors_buffer {
+                    self.tcx().sess.diagnostic().emit_diagnostic(diag);
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 50a1b85b169..297a0be6a27 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -15,7 +15,9 @@ use hir::def::DefKind;
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
-use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan};
+use rustc_errors::{
+    DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
@@ -2005,7 +2007,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn new_error_with_message<S: Into<MultiSpan>>(
         tcx: TyCtxt<'tcx>,
         span: S,
-        msg: impl Into<String>,
+        msg: impl Into<DiagnosticMessage>,
     ) -> Ty<'tcx> {
         let reported = tcx.sess.span_delayed_bug(span, msg);
         Ty::new(tcx, Error(reported))
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 2358661738a..dbf27ea60f8 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -65,7 +65,7 @@ pub(crate) struct RequiresUnsafe {
 impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe {
     #[track_caller]
     fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> {
-        let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe);
+        let mut diag = handler.struct_err(fluent::mir_transform_requires_unsafe);
         diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
         diag.set_span(self.span);
         diag.span_label(self.span, self.details.label());
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index bc53ab83439..c51a5c095ee 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1046,7 +1046,7 @@ impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let token_descr = TokenDescription::from_token(&self.token);
 
-        let mut diag = handler.struct_diagnostic(match token_descr {
+        let mut diag = handler.struct_err(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_identifier_found_reserved_identifier_str
             }
@@ -1103,7 +1103,7 @@ impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let token_descr = TokenDescription::from_token(&self.token);
 
-        let mut diag = handler.struct_diagnostic(match token_descr {
+        let mut diag = handler.struct_err(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_semi_found_reserved_identifier_str
             }
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index bbfb160ebf7..0dc60688955 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -350,8 +350,7 @@ pub(super) fn check_for_substitution(
 
     let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
         let msg = format!("substitution character not found for '{ch}'");
-        reader.sess.span_diagnostic.span_bug_no_panic(span, msg);
-        return (None, None);
+        reader.sess.span_diagnostic.span_bug(span, msg);
     };
 
     // special help suggestion for "directed" double quotes
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 95352dbdc13..9887a85e6a4 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -51,8 +51,8 @@ macro_rules! panictry_buffer {
         match $e {
             Ok(e) => e,
             Err(errs) => {
-                for mut e in errs {
-                    $handler.emit_diagnostic(&mut e);
+                for e in errs {
+                    $handler.emit_diagnostic(e);
                 }
                 FatalError.raise()
             }
@@ -165,8 +165,8 @@ fn try_file_to_source_file(
 fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>) -> Lrc<SourceFile> {
     match try_file_to_source_file(sess, path, spanopt) {
         Ok(source_file) => source_file,
-        Err(mut d) => {
-            sess.span_diagnostic.emit_diagnostic(&mut d);
+        Err(d) => {
+            sess.span_diagnostic.emit_diagnostic(d);
             FatalError.raise();
         }
     }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 5295172b25e..221fc70d9ff 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -249,8 +249,8 @@ impl<'a> Parser<'a> {
         self.diagnostic().struct_span_err(sp, m)
     }
 
-    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: impl Into<String>) -> ! {
-        self.diagnostic().span_bug(sp, m)
+    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.diagnostic().span_bug(sp, msg)
     }
 
     pub(super) fn diagnostic(&self) -> &'a Handler {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index bc09972185a..3b8ccb67bbe 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -926,8 +926,8 @@ impl<D: Deps> DepGraphData<D> {
 
             let handle = qcx.dep_context().sess().diagnostic();
 
-            for mut diagnostic in side_effects.diagnostics {
-                handle.emit_diagnostic(&mut diagnostic);
+            for diagnostic in side_effects.diagnostics {
+                handle.emit_diagnostic(diagnostic);
             }
         }
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 6fda18d87e3..d46a309df55 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1486,10 +1486,12 @@ impl CheckCfg {
         ins!(sym::sanitizer_cfi_generalize_pointers, no_values);
         ins!(sym::sanitizer_cfi_normalize_integers, no_values);
 
-        // rustc_codegen_ssa has a list of known target features and their
-        // stability, but we should allow any target feature as a new target or
-        // rustc version may introduce new target features.
-        ins!(sym::target_feature, || ExpectedValues::Any);
+        ins!(sym::target_feature, empty_values).extend(
+            rustc_target::target_features::all_known_features()
+                .map(|(f, _sb)| f)
+                .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned())
+                .map(Symbol::intern),
+        );
 
         // sym::target_*
         {
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 7eed59709c8..aab7595ef6e 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -19,7 +19,7 @@ impl<'a> IntoDiagnostic<'a> for FeatureGateError {
         self,
         handler: &'a rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag = handler.struct_diagnostic(self.explain);
+        let mut diag = handler.struct_err(self.explain);
         diag.set_span(self.span);
         diag.code(error_code!(E0658));
         diag
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 881e1de6755..525f00f5cd0 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, Handler};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
+    ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
@@ -390,13 +390,4 @@ impl ParseSess {
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.span_diagnostic.struct_fatal(msg)
     }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_diagnostic<G: EmissionGuarantee>(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, G> {
-        self.span_diagnostic.struct_diagnostic(msg)
-    }
 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 69b861ea380..08a9b3d9fa0 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -632,7 +632,7 @@ impl Session {
     pub fn span_delayed_bug<S: Into<MultiSpan>>(
         &self,
         sp: S,
-        msg: impl Into<String>,
+        msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
         self.diagnostic().span_delayed_bug(sp, msg)
     }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index e17b81d4652..257c6777996 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -35,6 +35,7 @@ pub mod abi;
 pub mod asm;
 pub mod json;
 pub mod spec;
+pub mod target_features;
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
new file mode 100644
index 00000000000..5f5de57dd1d
--- /dev/null
+++ b/compiler/rustc_target/src/target_features.rs
@@ -0,0 +1,429 @@
+use rustc_span::symbol::sym;
+use rustc_span::symbol::Symbol;
+
+/// Features that control behaviour of rustc, rather than the codegen.
+pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
+
+/// Stability information for target features.
+#[derive(Debug, Clone, Copy)]
+pub enum Stability {
+    /// This target feature is stable, it can be used in `#[target_feature]` and
+    /// `#[cfg(target_feature)]`.
+    Stable,
+    /// This target feature is unstable; using it in `#[target_feature]` or `#[cfg(target_feature)]`
+    /// requires enabling the given nightly feature.
+    Unstable(Symbol),
+}
+use Stability::*;
+
+impl Stability {
+    pub fn as_feature_name(self) -> Option<Symbol> {
+        match self {
+            Stable => None,
+            Unstable(s) => Some(s),
+        }
+    }
+
+    pub fn is_stable(self) -> bool {
+        matches!(self, Stable)
+    }
+}
+
+// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
+// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with
+// `-Ctarget-feature`.
+//
+// When adding features to the below lists
+// check whether they're named already elsewhere in rust
+// e.g. in stdarch and whether the given name matches LLVM's
+// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted.
+//
+// Also note that all target features listed here must be purely additive: for target_feature 1.1 to
+// be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a
+// per-function level, since we would then allow safe calls from functions with `+soft-float` to
+// functions without that feature!
+//
+// When adding a new feature, be particularly mindful of features that affect function ABIs. Those
+// need to be treated very carefully to avoid introducing unsoundness! This often affects features
+// that enable/disable hardfloat support (see https://github.com/rust-lang/rust/issues/116344 for an
+// example of this going wrong), but features enabling new SIMD registers are also a concern (see
+// https://github.com/rust-lang/rust/issues/116558 for an example of this going wrong).
+//
+// Stabilizing a target feature requires t-lang approval.
+
+const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("aclass", Unstable(sym::arm_target_feature)),
+    ("aes", Unstable(sym::arm_target_feature)),
+    ("crc", Unstable(sym::arm_target_feature)),
+    ("d32", Unstable(sym::arm_target_feature)),
+    ("dotprod", Unstable(sym::arm_target_feature)),
+    ("dsp", Unstable(sym::arm_target_feature)),
+    ("fp-armv8", Unstable(sym::arm_target_feature)),
+    ("i8mm", Unstable(sym::arm_target_feature)),
+    ("mclass", Unstable(sym::arm_target_feature)),
+    ("neon", Unstable(sym::arm_target_feature)),
+    ("rclass", Unstable(sym::arm_target_feature)),
+    ("sha2", Unstable(sym::arm_target_feature)),
+    // This is needed for inline assembly, but shouldn't be stabilized as-is
+    // since it should be enabled per-function using #[instruction_set], not
+    // #[target_feature].
+    ("thumb-mode", Unstable(sym::arm_target_feature)),
+    ("thumb2", Unstable(sym::arm_target_feature)),
+    ("trustzone", Unstable(sym::arm_target_feature)),
+    ("v5te", Unstable(sym::arm_target_feature)),
+    ("v6", Unstable(sym::arm_target_feature)),
+    ("v6k", Unstable(sym::arm_target_feature)),
+    ("v6t2", Unstable(sym::arm_target_feature)),
+    ("v7", Unstable(sym::arm_target_feature)),
+    ("v8", Unstable(sym::arm_target_feature)),
+    ("vfp2", Unstable(sym::arm_target_feature)),
+    ("vfp3", Unstable(sym::arm_target_feature)),
+    ("vfp4", Unstable(sym::arm_target_feature)),
+    ("virtualization", Unstable(sym::arm_target_feature)),
+    // tidy-alphabetical-end
+];
+
+const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    // FEAT_AES
+    ("aes", Stable),
+    // FEAT_BF16
+    ("bf16", Stable),
+    // FEAT_BTI
+    ("bti", Stable),
+    // FEAT_CRC
+    ("crc", Stable),
+    // FEAT_DIT
+    ("dit", Stable),
+    // FEAT_DotProd
+    ("dotprod", Stable),
+    // FEAT_DPB
+    ("dpb", Stable),
+    // FEAT_DPB2
+    ("dpb2", Stable),
+    // FEAT_F32MM
+    ("f32mm", Stable),
+    // FEAT_F64MM
+    ("f64mm", Stable),
+    // FEAT_FCMA
+    ("fcma", Stable),
+    // FEAT_FHM
+    ("fhm", Stable),
+    // FEAT_FLAGM
+    ("flagm", Stable),
+    // FEAT_FP16
+    ("fp16", Stable),
+    // FEAT_FRINTTS
+    ("frintts", Stable),
+    // FEAT_I8MM
+    ("i8mm", Stable),
+    // FEAT_JSCVT
+    ("jsconv", Stable),
+    // FEAT_LOR
+    ("lor", Stable),
+    // FEAT_LSE
+    ("lse", Stable),
+    // FEAT_MTE
+    ("mte", Stable),
+    // FEAT_AdvSimd & FEAT_FP
+    ("neon", Stable),
+    // FEAT_PAUTH (address authentication)
+    ("paca", Stable),
+    // FEAT_PAUTH (generic authentication)
+    ("pacg", Stable),
+    // FEAT_PAN
+    ("pan", Stable),
+    // FEAT_PMUv3
+    ("pmuv3", Stable),
+    // FEAT_RAND
+    ("rand", Stable),
+    // FEAT_RAS
+    ("ras", Stable),
+    // FEAT_RCPC
+    ("rcpc", Stable),
+    // FEAT_RCPC2
+    ("rcpc2", Stable),
+    // FEAT_RDM
+    ("rdm", Stable),
+    // FEAT_SB
+    ("sb", Stable),
+    // FEAT_SHA1 & FEAT_SHA256
+    ("sha2", Stable),
+    // FEAT_SHA512 & FEAT_SHA3
+    ("sha3", Stable),
+    // FEAT_SM3 & FEAT_SM4
+    ("sm4", Stable),
+    // FEAT_SPE
+    ("spe", Stable),
+    // FEAT_SSBS
+    ("ssbs", Stable),
+    // FEAT_SVE
+    ("sve", Stable),
+    // FEAT_SVE2
+    ("sve2", Stable),
+    // FEAT_SVE2_AES
+    ("sve2-aes", Stable),
+    // FEAT_SVE2_BitPerm
+    ("sve2-bitperm", Stable),
+    // FEAT_SVE2_SHA3
+    ("sve2-sha3", Stable),
+    // FEAT_SVE2_SM4
+    ("sve2-sm4", Stable),
+    // FEAT_TME
+    ("tme", Stable),
+    ("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
+    ("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
+    // FEAT_VHE
+    ("vh", Stable),
+    // tidy-alphabetical-end
+];
+
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[
+    &["paca", "pacg"], // Together these represent `pauth` in LLVM
+];
+
+const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("adx", Stable),
+    ("aes", Stable),
+    ("avx", Stable),
+    ("avx2", Stable),
+    ("avx512bf16", Unstable(sym::avx512_target_feature)),
+    ("avx512bitalg", Unstable(sym::avx512_target_feature)),
+    ("avx512bw", Unstable(sym::avx512_target_feature)),
+    ("avx512cd", Unstable(sym::avx512_target_feature)),
+    ("avx512dq", Unstable(sym::avx512_target_feature)),
+    ("avx512er", Unstable(sym::avx512_target_feature)),
+    ("avx512f", Unstable(sym::avx512_target_feature)),
+    ("avx512ifma", Unstable(sym::avx512_target_feature)),
+    ("avx512pf", Unstable(sym::avx512_target_feature)),
+    ("avx512vbmi", Unstable(sym::avx512_target_feature)),
+    ("avx512vbmi2", Unstable(sym::avx512_target_feature)),
+    ("avx512vl", Unstable(sym::avx512_target_feature)),
+    ("avx512vnni", Unstable(sym::avx512_target_feature)),
+    ("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
+    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
+    ("bmi1", Stable),
+    ("bmi2", Stable),
+    ("cmpxchg16b", Stable),
+    ("ermsb", Unstable(sym::ermsb_target_feature)),
+    ("f16c", Stable),
+    ("fma", Stable),
+    ("fxsr", Stable),
+    ("gfni", Unstable(sym::avx512_target_feature)),
+    ("lzcnt", Stable),
+    ("movbe", Stable),
+    ("pclmulqdq", Stable),
+    ("popcnt", Stable),
+    ("rdrand", Stable),
+    ("rdseed", Stable),
+    ("rtm", Unstable(sym::rtm_target_feature)),
+    ("sha", Stable),
+    ("sse", Stable),
+    ("sse2", Stable),
+    ("sse3", Stable),
+    ("sse4.1", Stable),
+    ("sse4.2", Stable),
+    ("sse4a", Unstable(sym::sse4a_target_feature)),
+    ("ssse3", Stable),
+    ("tbm", Unstable(sym::tbm_target_feature)),
+    ("vaes", Unstable(sym::avx512_target_feature)),
+    ("vpclmulqdq", Unstable(sym::avx512_target_feature)),
+    ("xsave", Stable),
+    ("xsavec", Stable),
+    ("xsaveopt", Stable),
+    ("xsaves", Stable),
+    // tidy-alphabetical-end
+];
+
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("hvx", Unstable(sym::hexagon_target_feature)),
+    ("hvx-length128b", Unstable(sym::hexagon_target_feature)),
+    // tidy-alphabetical-end
+];
+
+const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("altivec", Unstable(sym::powerpc_target_feature)),
+    ("power10-vector", Unstable(sym::powerpc_target_feature)),
+    ("power8-altivec", Unstable(sym::powerpc_target_feature)),
+    ("power8-vector", Unstable(sym::powerpc_target_feature)),
+    ("power9-altivec", Unstable(sym::powerpc_target_feature)),
+    ("power9-vector", Unstable(sym::powerpc_target_feature)),
+    ("vsx", Unstable(sym::powerpc_target_feature)),
+    // tidy-alphabetical-end
+];
+
+const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("fp64", Unstable(sym::mips_target_feature)),
+    ("msa", Unstable(sym::mips_target_feature)),
+    ("virt", Unstable(sym::mips_target_feature)),
+    // tidy-alphabetical-end
+];
+
+const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("a", Stable),
+    ("c", Stable),
+    ("d", Unstable(sym::riscv_target_feature)),
+    ("e", Unstable(sym::riscv_target_feature)),
+    ("f", Unstable(sym::riscv_target_feature)),
+    ("fast-unaligned-access", Unstable(sym::riscv_target_feature)),
+    ("m", Stable),
+    ("relax", Unstable(sym::riscv_target_feature)),
+    ("v", Unstable(sym::riscv_target_feature)),
+    ("zba", Stable),
+    ("zbb", Stable),
+    ("zbc", Stable),
+    ("zbkb", Stable),
+    ("zbkc", Stable),
+    ("zbkx", Stable),
+    ("zbs", Stable),
+    ("zdinx", Unstable(sym::riscv_target_feature)),
+    ("zfh", Unstable(sym::riscv_target_feature)),
+    ("zfhmin", Unstable(sym::riscv_target_feature)),
+    ("zfinx", Unstable(sym::riscv_target_feature)),
+    ("zhinx", Unstable(sym::riscv_target_feature)),
+    ("zhinxmin", Unstable(sym::riscv_target_feature)),
+    ("zk", Stable),
+    ("zkn", Stable),
+    ("zknd", Stable),
+    ("zkne", Stable),
+    ("zknh", Stable),
+    ("zkr", Stable),
+    ("zks", Stable),
+    ("zksed", Stable),
+    ("zksh", Stable),
+    ("zkt", Stable),
+    // tidy-alphabetical-end
+];
+
+const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("atomics", Unstable(sym::wasm_target_feature)),
+    ("bulk-memory", Unstable(sym::wasm_target_feature)),
+    ("exception-handling", Unstable(sym::wasm_target_feature)),
+    ("multivalue", Unstable(sym::wasm_target_feature)),
+    ("mutable-globals", Unstable(sym::wasm_target_feature)),
+    ("nontrapping-fptoint", Unstable(sym::wasm_target_feature)),
+    ("reference-types", Unstable(sym::wasm_target_feature)),
+    ("relaxed-simd", Unstable(sym::wasm_target_feature)),
+    ("sign-ext", Unstable(sym::wasm_target_feature)),
+    ("simd128", Stable),
+    // tidy-alphabetical-end
+];
+
+const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
+
+const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("10e60", Unstable(sym::csky_target_feature)),
+    ("2e3", Unstable(sym::csky_target_feature)),
+    ("3e3r1", Unstable(sym::csky_target_feature)),
+    ("3e3r2", Unstable(sym::csky_target_feature)),
+    ("3e3r3", Unstable(sym::csky_target_feature)),
+    ("3e7", Unstable(sym::csky_target_feature)),
+    ("7e10", Unstable(sym::csky_target_feature)),
+    ("cache", Unstable(sym::csky_target_feature)),
+    ("doloop", Unstable(sym::csky_target_feature)),
+    ("dsp1e2", Unstable(sym::csky_target_feature)),
+    ("dspe60", Unstable(sym::csky_target_feature)),
+    ("e1", Unstable(sym::csky_target_feature)),
+    ("e2", Unstable(sym::csky_target_feature)),
+    ("edsp", Unstable(sym::csky_target_feature)),
+    ("elrw", Unstable(sym::csky_target_feature)),
+    ("float1e2", Unstable(sym::csky_target_feature)),
+    ("float1e3", Unstable(sym::csky_target_feature)),
+    ("float3e4", Unstable(sym::csky_target_feature)),
+    ("float7e60", Unstable(sym::csky_target_feature)),
+    ("floate1", Unstable(sym::csky_target_feature)),
+    ("hard-tp", Unstable(sym::csky_target_feature)),
+    ("high-registers", Unstable(sym::csky_target_feature)),
+    ("hwdiv", Unstable(sym::csky_target_feature)),
+    ("mp", Unstable(sym::csky_target_feature)),
+    ("mp1e2", Unstable(sym::csky_target_feature)),
+    ("nvic", Unstable(sym::csky_target_feature)),
+    ("trust", Unstable(sym::csky_target_feature)),
+    ("vdsp2e60f", Unstable(sym::csky_target_feature)),
+    ("vdspv1", Unstable(sym::csky_target_feature)),
+    ("vdspv2", Unstable(sym::csky_target_feature)),
+    // tidy-alphabetical-end
+    //fpu
+    // tidy-alphabetical-start
+    ("fdivdu", Unstable(sym::csky_target_feature)),
+    ("fpuv2_df", Unstable(sym::csky_target_feature)),
+    ("fpuv2_sf", Unstable(sym::csky_target_feature)),
+    ("fpuv3_df", Unstable(sym::csky_target_feature)),
+    ("fpuv3_hf", Unstable(sym::csky_target_feature)),
+    ("fpuv3_hi", Unstable(sym::csky_target_feature)),
+    ("fpuv3_sf", Unstable(sym::csky_target_feature)),
+    ("hard-float", Unstable(sym::csky_target_feature)),
+    ("hard-float-abi", Unstable(sym::csky_target_feature)),
+    // tidy-alphabetical-end
+];
+
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+    // tidy-alphabetical-start
+    ("d", Unstable(sym::loongarch_target_feature)),
+    ("f", Unstable(sym::loongarch_target_feature)),
+    ("lasx", Unstable(sym::loongarch_target_feature)),
+    ("lbt", Unstable(sym::loongarch_target_feature)),
+    ("lsx", Unstable(sym::loongarch_target_feature)),
+    ("lvz", Unstable(sym::loongarch_target_feature)),
+    ("ual", Unstable(sym::loongarch_target_feature)),
+    // tidy-alphabetical-end
+];
+
+/// When rustdoc is running, provide a list of all known features so that all their respective
+/// primitives may be documented.
+///
+/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
+pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
+    std::iter::empty()
+        .chain(ARM_ALLOWED_FEATURES.iter())
+        .chain(AARCH64_ALLOWED_FEATURES.iter())
+        .chain(X86_ALLOWED_FEATURES.iter())
+        .chain(HEXAGON_ALLOWED_FEATURES.iter())
+        .chain(POWERPC_ALLOWED_FEATURES.iter())
+        .chain(MIPS_ALLOWED_FEATURES.iter())
+        .chain(RISCV_ALLOWED_FEATURES.iter())
+        .chain(WASM_ALLOWED_FEATURES.iter())
+        .chain(BPF_ALLOWED_FEATURES.iter())
+        .chain(CSKY_ALLOWED_FEATURES)
+        .chain(LOONGARCH_ALLOWED_FEATURES)
+        .cloned()
+}
+
+impl super::spec::Target {
+    pub fn supported_target_features(&self) -> &'static [(&'static str, Stability)] {
+        match &*self.arch {
+            "arm" => ARM_ALLOWED_FEATURES,
+            "aarch64" => AARCH64_ALLOWED_FEATURES,
+            "x86" | "x86_64" => X86_ALLOWED_FEATURES,
+            "hexagon" => HEXAGON_ALLOWED_FEATURES,
+            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_ALLOWED_FEATURES,
+            "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
+            "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
+            "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
+            "bpf" => BPF_ALLOWED_FEATURES,
+            "csky" => CSKY_ALLOWED_FEATURES,
+            "loongarch64" => LOONGARCH_ALLOWED_FEATURES,
+            _ => &[],
+        }
+    }
+
+    pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] {
+        match &*self.arch {
+            "aarch64" => AARCH64_TIED_FEATURES,
+            _ => &[],
+        }
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
index bd8a38e350d..dac013cc98d 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
@@ -55,7 +55,7 @@ where
                 16 => transize(vqtbl1q_u8, self, idxs),
                 #[cfg(all(target_feature = "avx2", not(target_feature = "avx512vbmi")))]
                 32 => transize_raw(avx2_pshufb, self, idxs),
-                #[cfg(target_feature = "avx512vl,avx512vbmi")]
+                #[cfg(all(target_feature = "avx512vl", target_feature = "avx512vbmi"))]
                 32 => transize(x86::_mm256_permutexvar_epi8, self, idxs),
                 // Notable absence: avx512bw shuffle
                 // If avx512bw is available, odds of avx512vbmi are good
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index ef394b16310..e0f59144975 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -512,7 +512,7 @@ pub fn report_msg<'tcx>(
         }
     }
 
-    handler.emit_diagnostic(&mut err);
+    handler.emit_diagnostic(err);
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 0573df9de2f..06f9c4c6243 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -284,10 +284,8 @@ impl ParseSess {
 // Methods that should be restricted within the parse module.
 impl ParseSess {
     pub(super) fn emit_diagnostics(&self, diagnostics: Vec<Diagnostic>) {
-        for mut diagnostic in diagnostics {
-            self.parse_sess
-                .span_diagnostic
-                .emit_diagnostic(&mut diagnostic);
+        for diagnostic in diagnostics {
+            self.parse_sess.span_diagnostic.emit_diagnostic(diagnostic);
         }
     }
 
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 2081d1b3b07..3bfe811b58e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -254,7 +254,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "icu_provider_macros",
     "ident_case",
     "indexmap",
-    "instant",
     "intl-memoizer",
     "intl_pluralrules",
     "is-terminal",
diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
index c8fd2d8f6c2..491dfcc6ae0 100644
--- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
+++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs
@@ -1,6 +1,7 @@
 // run-pass
 // edition:2021
 
+#![feature(noop_waker)]
 
 use std::future::Future;
 
@@ -32,33 +33,18 @@ async fn async_main() {
 // ------------------------------------------------------------------------- //
 // Implementation Details Below...
 
-use std::pin::Pin;
+use std::pin::pin;
 use std::task::*;
 
-pub fn noop_waker() -> Waker {
-    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
-
-    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
-    unsafe { Waker::from_raw(raw) }
-}
-
-const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
-
-unsafe fn noop_clone(_p: *const ()) -> RawWaker {
-    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
-}
-
-unsafe fn noop(_p: *const ()) {}
-
 fn main() {
-    let mut fut = async_main();
+    let mut fut = pin!(async_main());
 
     // Poll loop, just to test the future...
-    let waker = noop_waker();
+    let waker = Waker::noop();
     let ctx = &mut Context::from_waker(&waker);
 
     loop {
-        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+        match fut.as_mut().poll(ctx) {
             Poll::Pending => {}
             Poll::Ready(()) => break,
         }
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
index 18b0fa4856d..f21abf012ba 100644
--- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
@@ -2,6 +2,7 @@
 // known-bug: #108309
 
 #![feature(min_specialization)]
+#![feature(noop_waker)]
 
 struct MyStruct;
 
@@ -35,34 +36,18 @@ async fn indirection<T>(x: T) -> &'static str {
 // ------------------------------------------------------------------------- //
 // Implementation Details Below...
 
-use std::future::Future;
-use std::pin::Pin;
+use std::pin::{pin, Pin};
 use std::task::*;
 
-pub fn noop_waker() -> Waker {
-    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
-
-    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
-    unsafe { Waker::from_raw(raw) }
-}
-
-const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
-
-unsafe fn noop_clone(_p: *const ()) -> RawWaker {
-    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
-}
-
-unsafe fn noop(_p: *const ()) {}
-
 fn main() {
-    let mut fut = async_main();
+    let mut fut = pin!(async_main());
 
     // Poll loop, just to test the future...
-    let waker = noop_waker();
+    let waker = Waker::noop();
     let ctx = &mut Context::from_waker(&waker);
 
     loop {
-        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+        match fut.as_mut().poll(ctx) {
             Poll::Pending => {}
             Poll::Ready(()) => break,
         }
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
index 5e2be08623b..0560cd9c5fe 100644
--- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
@@ -1,11 +1,11 @@
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/dont-project-to-specializable-projection.rs:13:5
+  --> $DIR/dont-project-to-specializable-projection.rs:14:5
    |
 LL |     default async fn foo(_: T) -> &'static str {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found future
    |
 note: type in trait
-  --> $DIR/dont-project-to-specializable-projection.rs:9:5
+  --> $DIR/dont-project-to-specializable-projection.rs:10:5
    |
 LL |     async fn foo(_: T) -> &'static str;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,13 +13,29 @@ LL |     async fn foo(_: T) -> &'static str;
               found signature `fn(_) -> impl Future<Output = &'static str>`
 
 error: async associated function in trait cannot be specialized
-  --> $DIR/dont-project-to-specializable-projection.rs:13:5
+  --> $DIR/dont-project-to-specializable-projection.rs:14:5
    |
 LL |     default async fn foo(_: T) -> &'static str {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: specialization behaves in inconsistent and surprising ways with async functions in traits, and for now is disallowed
 
-error: aborting due to 2 previous errors
+error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future<Output = ()>>` in the current scope
+  --> $DIR/dont-project-to-specializable-projection.rs:50:28
+   |
+LL |         match fut.as_mut().poll(ctx) {
+   |                            ^^^^ method not found in `Pin<&mut impl Future<Output = ()>>`
+  --> $SRC_DIR/core/src/future/future.rs:LL:COL
+   |
+   = note: the method is available for `Pin<&mut impl Future<Output = ()>>` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL + use std::future::Future;
+   |
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0053, E0599.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs
index 39a470c202f..21268bf10d5 100644
--- a/tests/ui/check-cfg/well-known-values.rs
+++ b/tests/ui/check-cfg/well-known-values.rs
@@ -51,7 +51,8 @@
     //~^ WARN unexpected `cfg` condition value
     target_family = "_UNEXPECTED_VALUE",
     //~^ WARN unexpected `cfg` condition value
-    target_feature = "_UNEXPECTED_VALUE", // currently *any* values are "expected"
+    target_feature = "_UNEXPECTED_VALUE",
+    //~^ WARN unexpected `cfg` condition value
     target_has_atomic = "_UNEXPECTED_VALUE",
     //~^ WARN unexpected `cfg` condition value
     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
@@ -90,6 +91,9 @@ fn target_os_linux_misspell() {}
 #[cfg(target_os = "linux")]
 fn target_os_linux() {}
 
+#[cfg(target_feature = "crt-static")] // pure rustc feature
+fn target_feature() {}
+
 #[cfg(target_has_atomic = "8")]
 fn target_has_atomic_8() {}
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 1e92639fd11..4f708e62cd3 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -152,7 +152,17 @@ LL |     target_family = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:55:5
+  --> $DIR/well-known-values.rs:54:5
+   |
+LL |     target_feature = "_UNEXPECTED_VALUE",
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt`
+   = help: to expect this configuration use `--check-cfg=cfg(target_feature, values("_UNEXPECTED_VALUE"))`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+
+warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
+  --> $DIR/well-known-values.rs:56:5
    |
 LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +172,7 @@ LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:57:5
+  --> $DIR/well-known-values.rs:58:5
    |
 LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,7 +182,7 @@ LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:59:5
+  --> $DIR/well-known-values.rs:60:5
    |
 LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -182,7 +192,7 @@ LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:61:5
+  --> $DIR/well-known-values.rs:62:5
    |
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -192,7 +202,7 @@ LL |     target_os = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:63:5
+  --> $DIR/well-known-values.rs:64:5
    |
 LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +212,7 @@ LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:65:5
+  --> $DIR/well-known-values.rs:66:5
    |
 LL |     target_thread_local = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^----------------------
@@ -214,7 +224,7 @@ LL |     target_thread_local = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:67:5
+  --> $DIR/well-known-values.rs:68:5
    |
 LL |     target_vendor = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,7 +234,7 @@ LL |     target_vendor = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:69:5
+  --> $DIR/well-known-values.rs:70:5
    |
 LL |     test = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -236,7 +246,7 @@ LL |     test = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:71:5
+  --> $DIR/well-known-values.rs:72:5
    |
 LL |     unix = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -248,7 +258,7 @@ LL |     unix = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:73:5
+  --> $DIR/well-known-values.rs:74:5
    |
 LL |     windows = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -260,7 +270,7 @@ LL |     windows = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `linuz`
-  --> $DIR/well-known-values.rs:79:7
+  --> $DIR/well-known-values.rs:80:7
    |
 LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |       ^^^^^^^^^^^^-------
@@ -271,5 +281,5 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    = help: to expect this configuration use `--check-cfg=cfg(target_os, values("linuz"))`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
-warning: 25 warnings emitted
+warning: 26 warnings emitted
 
diff --git a/tests/ui/coroutine/async_gen_fn_iter.rs b/tests/ui/coroutine/async_gen_fn_iter.rs
index 4fa29e1095a..ec6464d0048 100644
--- a/tests/ui/coroutine/async_gen_fn_iter.rs
+++ b/tests/ui/coroutine/async_gen_fn_iter.rs
@@ -3,6 +3,7 @@
 // run-pass
 
 #![feature(gen_blocks, async_iterator)]
+#![feature(noop_waker)]
 
 // make sure that a ridiculously simple async gen fn works as an iterator.
 
@@ -42,7 +43,7 @@ async fn async_main() {
 // ------------------------------------------------------------------------- //
 // Implementation Details Below...
 
-use std::pin::Pin;
+use std::pin::{Pin, pin};
 use std::task::*;
 use std::async_iter::AsyncIterator;
 use std::future::Future;
@@ -69,30 +70,15 @@ impl<'s, S: AsyncIterator> Future for Next<'s, S> where S: Unpin {
     }
 }
 
-pub fn noop_waker() -> Waker {
-    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
-
-    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
-    unsafe { Waker::from_raw(raw) }
-}
-
-const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
-
-unsafe fn noop_clone(_p: *const ()) -> RawWaker {
-    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
-}
-
-unsafe fn noop(_p: *const ()) {}
-
 fn main() {
-    let mut fut = async_main();
+    let mut fut = pin!(async_main());
 
     // Poll loop, just to test the future...
-    let waker = noop_waker();
+    let waker = Waker::noop();
     let ctx = &mut Context::from_waker(&waker);
 
     loop {
-        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+        match fut.as_mut().poll(ctx) {
             Poll::Pending => {}
             Poll::Ready(()) => break,
         }
diff --git a/tests/ui/dyn-star/dispatch-on-pin-mut.rs b/tests/ui/dyn-star/dispatch-on-pin-mut.rs
index 5774c8b2a67..c4ae279e6c1 100644
--- a/tests/ui/dyn-star/dispatch-on-pin-mut.rs
+++ b/tests/ui/dyn-star/dispatch-on-pin-mut.rs
@@ -4,6 +4,7 @@
 
 #![feature(dyn_star)]
 //~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+#![feature(noop_waker)]
 
 use std::future::Future;
 
@@ -18,33 +19,18 @@ async fn async_main() {
 // ------------------------------------------------------------------------- //
 // Implementation Details Below...
 
-use std::pin::Pin;
 use std::task::*;
-
-pub fn noop_waker() -> Waker {
-    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
-
-    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
-    unsafe { Waker::from_raw(raw) }
-}
-
-const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
-
-unsafe fn noop_clone(_p: *const ()) -> RawWaker {
-    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
-}
-
-unsafe fn noop(_p: *const ()) {}
+use std::pin::pin;
 
 fn main() {
-    let mut fut = async_main();
+    let mut fut = pin!(async_main());
 
     // Poll loop, just to test the future...
-    let waker = noop_waker();
+    let waker = Waker::noop();
     let ctx = &mut Context::from_waker(&waker);
 
     loop {
-        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+        match fut.as_mut().poll(ctx) {
             Poll::Pending => {}
             Poll::Ready(()) => break,
         }