about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock48
-rw-r--r--compiler/rustc_attr/src/builtin.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs38
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs17
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs30
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs11
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs34
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--compiler/rustc_session/src/options.rs24
-rw-r--r--compiler/rustc_session/src/session.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/asm/mod.rs29
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs111
-rw-r--r--compiler/rustc_target/src/spec/mod.rs69
-rw-r--r--compiler/rustc_target/src/target_features.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs90
-rw-r--r--library/alloc/src/boxed.rs1
-rw-r--r--library/alloc/src/ffi/c_str.rs1
-rw-r--r--library/alloc/src/sync.rs1
-rw-r--r--library/core/src/char/methods.rs3
-rw-r--r--library/core/src/fmt/num.rs212
-rw-r--r--library/core/src/intrinsics.rs7
-rw-r--r--library/core/src/ptr/const_ptr.rs57
-rw-r--r--library/core/src/ptr/metadata.rs6
-rw-r--r--library/core/src/ptr/mod.rs3
-rw-r--r--library/core/src/ptr/mut_ptr.rs58
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/slice/mod.rs1
-rw-r--r--library/std/build.rs9
-rw-r--r--library/std/src/collections/hash/map/tests.rs5
-rw-r--r--library/std/src/collections/hash/set/tests.rs2
-rw-r--r--library/std/src/env/tests.rs2
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--library/std/src/io/buffered/tests.rs3
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs1
-rw-r--r--library/std/src/io/stdio/tests.rs8
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/std/src/net/ip_addr.rs2
-rw-r--r--library/std/src/net/socket_addr.rs2
-rw-r--r--library/std/src/net/tcp.rs9
-rw-r--r--library/std/src/net/tcp/tests.rs29
-rw-r--r--library/std/src/net/udp.rs10
-rw-r--r--library/std/src/net/udp/tests.rs9
-rw-r--r--library/std/src/path/tests.rs16
-rw-r--r--library/std/src/process.rs10
-rw-r--r--library/std/src/sync/barrier/tests.rs2
-rw-r--r--library/std/src/sync/condvar/tests.rs16
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs6
-rw-r--r--library/std/src/sync/mod.rs9
-rw-r--r--library/std/src/sync/mpmc/error.rs5
-rw-r--r--library/std/src/sync/mpmc/mod.rs1035
-rw-r--r--library/std/src/sync/mpmc/tests.rs728
-rw-r--r--library/std/src/sync/mpsc/mod.rs4
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sync/once_lock/tests.rs7
-rw-r--r--library/std/src/sync/reentrant_lock.rs2
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasip2/net.rs379
-rw-r--r--library/std/src/sys_common/io.rs2
-rw-r--r--library/std/src/sys_common/mod.rs3
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/src/thread/mod.rs2
-rw-r--r--library/std/tests/create_dir_all_bare.rs2
-rw-r--r--library/std/tests/process_spawning.rs2
-rw-r--r--library/std/tests/thread.rs2
-rw-r--r--src/bootstrap/Cargo.lock100
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs1
-rw-r--r--src/bootstrap/src/core/builder.rs5
-rw-r--r--src/bootstrap/src/lib.rs9
-rw-r--r--src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/default-visibility.md44
-rw-r--r--src/doc/unstable-book/src/compiler-flags/print-check-cfg.md27
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md7
-rw-r--r--src/librustdoc/clean/auto_trait.rs1
-rw-r--r--src/librustdoc/clean/blanket_impl.rs1
-rw-r--r--src/librustdoc/clean/inline.rs1
-rw-r--r--src/librustdoc/clean/types.rs60
-rw-r--r--src/librustdoc/html/render/print_item.rs31
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css7
-rw-r--r--src/librustdoc/html/static/js/main.js14
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs95
-rw-r--r--src/librustdoc/passes/mod.rs5
-rw-r--r--src/librustdoc/passes/propagate_stability.rs72
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
-rw-r--r--tests/codegen/asm-s390x-clobbers.rs50
-rw-r--r--tests/codegen/default-visibility.rs (renamed from tests/codegen/default-hidden-visibility.rs)18
-rw-r--r--tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs18
-rw-r--r--tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr50
-rw-r--r--tests/rustdoc-ui/intra-doc/field-ice.rs4
-rw-r--r--tests/rustdoc-ui/intra-doc/field-ice.stderr7
-rw-r--r--tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr6
-rw-r--r--tests/rustdoc-ui/issues/issue-91713.stdout2
-rw-r--r--tests/rustdoc/intra-doc/field.rs20
-rw-r--r--tests/rustdoc/stability.rs49
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr18
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.full.stderr8
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.min.stderr90
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.rs5
-rw-r--r--tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr4
-rw-r--r--tests/ui/const-generics/default-ty-closure.stderr2
-rw-r--r--tests/ui/const-generics/float-generic.simple.stderr2
-rw-r--r--tests/ui/const-generics/fn-const-param-call.min.stderr4
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.min.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr2
-rw-r--r--tests/ui/const-generics/ice-118285-fn-ptr-value.stderr2
-rw-r--r--tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.min.stderr18
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-62878.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68366.full.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68366.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68615-adt.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68615-array.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71169.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71381.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-71382.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71611.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-72352.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-73491.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-74101.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-74255.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-74950.min.stderr8
-rw-r--r--tests/ui/const-generics/issues/issue-75047.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-82956.stderr2
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.rs1
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.stderr14
-rw-r--r--tests/ui/const-generics/min_const_generics/complex-types.stderr14
-rw-r--r--tests/ui/const-generics/nested-type.min.stderr2
-rw-r--r--tests/ui/const-generics/not_wf_param_in_rpitit.rs1
-rw-r--r--tests/ui/const-generics/not_wf_param_in_rpitit.stderr16
-rw-r--r--tests/ui/const-generics/opaque_types.stderr2
-rw-r--r--tests/ui/const-generics/projection-as-arg-const.stderr2
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.min.stderr2
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.min.stderr4
-rw-r--r--tests/ui/const-generics/std/const-generics-range.min.stderr12
-rw-r--r--tests/ui/const-generics/transmute-const-param-static-reference.min.stderr2
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.min.stderr4
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71382.stderr2
-rw-r--r--tests/ui/consts/auxiliary/unstable_but_const_stable.rs13
-rw-r--r--tests/ui/consts/issue-103790.rs1
-rw-r--r--tests/ui/consts/issue-103790.stderr16
-rw-r--r--tests/ui/consts/unstable-const-stable.rs14
-rw-r--r--tests/ui/consts/unstable-const-stable.stderr43
-rw-r--r--tests/ui/drop/lint-if-let-rescope.fixed30
-rw-r--r--tests/ui/drop/lint-if-let-rescope.rs30
-rw-r--r--tests/ui/drop/lint-if-let-rescope.stderr62
-rw-r--r--tests/ui/feature-gates/feature-gate-adt_const_params.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-unsized-const-params.stderr2
-rw-r--r--tests/ui/generic-const-items/elided-lifetimes.rs1
-rw-r--r--tests/ui/generic-const-items/elided-lifetimes.stderr20
-rw-r--r--tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs7
-rw-r--r--tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr11
-rw-r--r--tests/ui/issues/issue-12041.stderr2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.rs2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr32
-rw-r--r--tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr2
-rw-r--r--tests/ui/lint/use_suggestion_json.stderr25
-rw-r--r--tests/ui/macros/expr_2021.rs14
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.fixed2
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.rs2
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.stderr6
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr8
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr4
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs3
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr8
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.rs3
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs11
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr13
-rw-r--r--tests/ui/macros/invalid-fragment-specifier.stderr4
-rw-r--r--tests/ui/macros/issue-21356.stderr2
-rw-r--r--tests/ui/macros/macro-missing-fragment.e2024.stderr6
-rw-r--r--tests/ui/macros/metavar_cross_edition_recursive_macros.rs1
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr6
-rw-r--r--tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr2
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr4
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs15
-rw-r--r--tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr2
-rw-r--r--tests/ui/typeck/ice-unexpected-region-123863.stderr4
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs2
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr44
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr4
206 files changed, 3797 insertions, 1049 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 70731b198fc..5b0b0368c93 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5771,16 +5771,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
 
 [[package]]
 name = "wasm-component-ld"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb17cdbc91766d4ea0bcd6026c36ba77a21b5c8199aeb1f0993461fe6a6bec2b"
+checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f"
 dependencies = [
  "anyhow",
  "clap",
  "lexopt",
  "tempfile",
  "wasi-preview1-component-adapter-provider",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
  "wat",
  "wit-component",
  "wit-parser",
@@ -5804,19 +5804,19 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760"
+checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a"
 dependencies = [
  "leb128",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65a146bf9a60e9264f0548a2599aa9656dba9a641eff9ab88299dc2a637e483c"
+checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91"
 dependencies = [
  "anyhow",
  "indexmap",
@@ -5824,8 +5824,8 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.217.0",
- "wasmparser 0.217.0",
+ "wasm-encoder 0.218.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
@@ -5840,9 +5840,9 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca917a21307d3adf2b9857b94dd05ebf8496bdcff4437a9b9fb3899d3e6c74e7"
+checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc"
 dependencies = [
  "ahash",
  "bitflags 2.6.0",
@@ -5854,22 +5854,22 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "217.0.0"
+version = "218.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7"
+checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7"
 dependencies = [
  "bumpalo",
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder 0.217.0",
+ "wasm-encoder 0.218.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.217.0"
+version = "1.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088"
+checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391"
 dependencies = [
  "wast",
 ]
@@ -6146,9 +6146,9 @@ dependencies = [
 
 [[package]]
 name = "wit-component"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7117809905e49db716d81e794f79590c052bf2fdbbcda1731ca0fb28f6f3ddf"
+checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406"
 dependencies = [
  "anyhow",
  "bitflags 2.6.0",
@@ -6157,17 +6157,17 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.217.0",
+ "wasm-encoder 0.218.0",
  "wasm-metadata",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb893dcd6d370cfdf19a0d9adfcd403efb8e544e1a0ea3a8b81a21fe392eaa78"
+checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55"
 dependencies = [
  "anyhow",
  "id-arena",
@@ -6178,7 +6178,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 762ebc47ca9..28d73fbe9f3 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -80,6 +80,10 @@ impl Stability {
     pub fn is_stable(&self) -> bool {
         self.level.is_stable()
     }
+
+    pub fn stable_since(&self) -> Option<StableSince> {
+        self.level.stable_since()
+    }
 }
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
@@ -170,6 +174,12 @@ impl StabilityLevel {
     pub fn is_stable(&self) -> bool {
         matches!(self, StabilityLevel::Stable { .. })
     }
+    pub fn stable_since(&self) -> Option<StableSince> {
+        match *self {
+            StabilityLevel::Stable { since, .. } => Some(since),
+            StabilityLevel::Unstable { .. } => None,
+        }
+    }
 }
 
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index e9498857fb9..f13a75648ae 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -104,10 +104,17 @@ fn create_wrapper_function(
         false,
     );
 
-    if tcx.sess.default_hidden_visibility() {
-        #[cfg(feature = "master")]
-        func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+    #[cfg(feature = "master")]
+    match tcx.sess.default_visibility() {
+        rustc_target::spec::SymbolVisibility::Hidden => {
+            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden))
+        }
+        rustc_target::spec::SymbolVisibility::Protected => {
+            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected))
+        }
+        rustc_target::spec::SymbolVisibility::Interposable => {}
     }
+
     if tcx.sess.must_emit_unwind_tables() {
         // TODO(antoyo): emit unwind tables.
     }
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 13a00f7e08d..a04cd4735f4 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -682,6 +682,11 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+            InlineAsmRegClass::S390x(
+                S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
+            ) => {
+                unreachable!("clobber-only")
+            }
             InlineAsmRegClass::Err => unreachable!(),
         },
     };
@@ -757,6 +762,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
         ) => cx.type_i32(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+            unreachable!("clobber-only")
+        }
         InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 2adac278c62..89f5305840b 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -77,18 +77,20 @@ pub(crate) unsafe fn codegen(
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            ll_g,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::LLVMSetInitializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            ll_g,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::LLVMSetInitializer(ll_g, llval);
     }
@@ -132,9 +134,11 @@ fn create_wrapper_function(
             None
         };
 
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            llfn,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
+
         if tcx.sess.must_emit_unwind_tables() {
             let uwtable =
                 attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 7621f111fe2..82ca3f519f7 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -708,6 +708,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             S390x(S390xInlineAsmRegClass::reg) => "r",
             S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             S390x(S390xInlineAsmRegClass::freg) => "f",
+            S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+                unreachable!("clobber-only")
+            }
             Msp430(Msp430InlineAsmRegClass::reg) => "r",
             M68k(M68kInlineAsmRegClass::reg) => "r",
             M68k(M68kInlineAsmRegClass::reg_addr) => "a",
@@ -866,6 +869,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
         S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
         S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+            unreachable!("clobber-only")
+        }
         Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index b0b29ca1280..7be44dd51b5 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -22,6 +22,7 @@ use tracing::debug;
 use crate::abi::{FnAbi, FnAbiLlvmExt};
 use crate::context::CodegenCx;
 use crate::llvm::AttributePlace::Function;
+use crate::llvm::Visibility;
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, llvm};
@@ -84,11 +85,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         fn_type: &'ll Type,
     ) -> &'ll Value {
         // Declare C ABI functions with the visibility used by C by default.
-        let visibility = if self.tcx.sess.default_hidden_visibility() {
-            llvm::Visibility::Hidden
-        } else {
-            llvm::Visibility::Default
-        };
+        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
 
         declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
     }
@@ -107,11 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         unnamed: llvm::UnnamedAddr,
         fn_type: &'ll Type,
     ) -> &'ll Value {
-        let visibility = if self.tcx.sess.default_hidden_visibility() {
-            llvm::Visibility::Hidden
-        } else {
-            llvm::Visibility::Default
-        };
+        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
         declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 9aabfd794ba..d3950df91fb 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -4,6 +4,7 @@
 use std::marker::PhantomData;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
 use super::debuginfo::{
@@ -133,6 +134,16 @@ pub enum Visibility {
     Protected = 2,
 }
 
+impl Visibility {
+    pub fn from_generic(visibility: SymbolVisibility) -> Self {
+        match visibility {
+            SymbolVisibility::Hidden => Visibility::Hidden,
+            SymbolVisibility::Protected => Visibility::Protected,
+            SymbolVisibility::Interposable => Visibility::Default,
+        }
+    }
+}
+
 /// LLVMUnnamedAddr
 #[repr(C)]
 pub enum UnnamedAddr {
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 201cfbb1918..bd847cd0068 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -264,6 +264,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
             Some(LLVMFeature::new("fast-unaligned-access"))
         }
+        // Filter out features that are not supported by the current LLVM version
+        ("riscv32" | "riscv64", "zaamo") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None,
         // Enable the evex512 target feature if an avx512 target feature is enabled.
         ("x86", s) if s.starts_with("avx512") => {
             Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")))
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index b1d898b6949..1498b9cbd5d 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -119,7 +119,7 @@ use rustc_span::symbol::{MacroRulesNormalizedIdent, kw};
 use rustc_span::{ErrorGuaranteed, Span};
 use smallvec::SmallVec;
 
-use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021;
+use super::quoted::VALID_FRAGMENT_NAMES_MSG;
 use crate::errors;
 use crate::mbe::{KleeneToken, TokenTree};
 
@@ -274,7 +274,7 @@ fn check_binders(
                     psess.dcx().emit_err(errors::MissingFragmentSpecifier {
                         span,
                         add_span: span.shrink_to_hi(),
-                        valid: VALID_FRAGMENT_NAMES_MSG_2021,
+                        valid: VALID_FRAGMENT_NAMES_MSG,
                     });
                 } else {
                     psess.buffer_lint(
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index f0a6c841f31..2edd289625e 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -1,4 +1,3 @@
-use rustc_ast::token::NtExprKind::*;
 use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token};
 use rustc_ast::{NodeId, tokenstream};
 use rustc_ast_pretty::pprust;
@@ -13,12 +12,9 @@ use crate::errors;
 use crate::mbe::macro_parser::count_metavar_decls;
 use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
-const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
-    `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
-    `item` and `vis`";
-pub(crate) const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
-    `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, \
-    `meta`, `tt`, `item` and `vis`";
+pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
+    `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, \
+    `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility";
 
 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -92,39 +88,13 @@ pub(super) fn parse(
                                     };
                                     let kind = NonterminalKind::from_symbol(fragment.name, edition)
                                         .unwrap_or_else(|| {
-                                            let help = match fragment.name {
-                                                sym::expr_2021 => {
-                                                    format!(
-                                                        "fragment specifier `expr_2021` \
-                                                         requires Rust 2021 or later\n\
-                                                         {VALID_FRAGMENT_NAMES_MSG}"
-                                                    )
-                                                }
-                                                _ if edition().at_least_rust_2021()
-                                                    && features.expr_fragment_specifier_2024 =>
-                                                {
-                                                    VALID_FRAGMENT_NAMES_MSG_2021.into()
-                                                }
-                                                _ => VALID_FRAGMENT_NAMES_MSG.into(),
-                                            };
                                             sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
                                                 span,
                                                 fragment,
-                                                help,
+                                                help: VALID_FRAGMENT_NAMES_MSG.into(),
                                             });
                                             NonterminalKind::Ident
                                         });
-                                    if kind == NonterminalKind::Expr(Expr2021 { inferred: false })
-                                        && !features.expr_fragment_specifier_2024
-                                    {
-                                        rustc_session::parse::feature_err(
-                                            sess,
-                                            sym::expr_fragment_specifier_2024,
-                                            span,
-                                            "fragment specifier `expr_2021` is unstable",
-                                        )
-                                        .emit();
-                                    }
                                     result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
                                     continue;
                                 }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 5ff002dd7d2..a850eb95620 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -189,6 +189,8 @@ declare_features! (
     (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)),
     /// Allows explicit generic arguments specification with `impl Trait` present.
     (accepted, explicit_generic_args_with_impl_trait, "1.63.0", Some(83701)),
+    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
+    (accepted, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
     /// Allows arbitrary expressions in key-value attributes at parse time.
     (accepted, extended_key_value_attributes, "1.54.0", Some(78835)),
     /// Allows resolving absolute paths as paths from other crates.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1ffd35dbf91..c5530097e96 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -450,8 +450,6 @@ declare_features! (
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
-    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
-    (incomplete, expr_fragment_specifier_2024, "1.80.0", Some(123742)),
     /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
     /// for functions with varargs.
     (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a71e14ce463..70b0b3f5788 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -961,13 +961,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         hir_ty.span,
                         "using raw pointers as const generic parameters is forbidden",
                     ),
-                    _ => tcx.dcx().struct_span_err(
-                        hir_ty.span,
-                        format!("`{}` is forbidden as the type of a const generic parameter", ty),
-                    ),
+                    _ => {
+                        // Avoid showing "{type error}" to users. See #118179.
+                        ty.error_reported()?;
+
+                        tcx.dcx().struct_span_err(
+                            hir_ty.span,
+                            format!(
+                                "`{ty}` is forbidden as the type of a const generic parameter",
+                            ),
+                        )
+                    }
                 };
 
-                diag.note("the only supported types are integers, `bool` and `char`");
+                diag.note("the only supported types are integers, `bool`, and `char`");
 
                 let cause = ObligationCause::misc(hir_ty.span, param.def_id);
                 let adt_const_params_feature_string =
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 57aa3deae80..895897eca6b 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -770,7 +770,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
-    tracked!(default_hidden_visibility, Some(true));
+    tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden));
     tracked!(dep_info_omit_d_target, true);
     tracked!(direct_access_external_data, Some(true));
     tracked!(dual_proc_macros, true);
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index c6218fe1e74..cdd0e80c458 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -122,7 +122,11 @@ impl IfLetRescope {
         }
         let tcx = cx.tcx;
         let source_map = tcx.sess.source_map();
-        let expr_end = expr.span.shrink_to_hi();
+        let expr_end = match expr.kind {
+            hir::ExprKind::If(_cond, conseq, None) => conseq.span.shrink_to_hi(),
+            hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
+            _ => return,
+        };
         let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
         let mut significant_droppers = vec![];
         let mut lifetime_ends = vec![];
@@ -145,7 +149,10 @@ impl IfLetRescope {
                 recovered: Recovered::No,
             }) = cond.kind
             {
-                let if_let_pat = expr.span.shrink_to_lo().between(init.span);
+                // Peel off round braces
+                let if_let_pat = source_map
+                    .span_take_while(expr.span, |&ch| ch == '(' || ch.is_whitespace())
+                    .between(init.span);
                 // The consequent fragment is always a block.
                 let before_conseq = conseq.span.shrink_to_lo();
                 let lifetime_end = source_map.end_point(conseq.span);
@@ -159,6 +166,8 @@ impl IfLetRescope {
                     if ty_ascription.is_some()
                         || !expr.span.can_be_used_for_suggestions()
                         || !pat.span.can_be_used_for_suggestions()
+                        || !if_let_pat.can_be_used_for_suggestions()
+                        || !before_conseq.can_be_used_for_suggestions()
                     {
                         // Our `match` rewrites does not support type ascription,
                         // so we just bail.
@@ -240,6 +249,23 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
         if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
             return;
         }
+        if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
+            && let Some(value) = block.expr
+            && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
+            && let hir::ExprKind::Let(..) = cond.kind
+        {
+            // Recall that `while let` is lowered into this:
+            // ```
+            // loop {
+            //     if let .. { body } else { break; }
+            // }
+            // ```
+            // There is no observable change in drop order on the overall `if let` expression
+            // given that the `{ break; }` block is trivial so the edition change
+            // means nothing substantial to this `while` statement.
+            self.skip.insert(value.hir_id);
+            return;
+        }
         if expr_parent_is_stmt(cx.tcx, expr.hir_id)
             && matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None))
         {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 954f746ce5b..56ca9167d4d 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -15,6 +15,7 @@ use rustc_query_system::ich::StableHashingContext;
 use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
+use rustc_target::spec::SymbolVisibility;
 use tracing::debug;
 
 use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
@@ -305,6 +306,16 @@ pub enum Visibility {
     Protected,
 }
 
+impl From<SymbolVisibility> for Visibility {
+    fn from(value: SymbolVisibility) -> Self {
+        match value {
+            SymbolVisibility::Hidden => Visibility::Hidden,
+            SymbolVisibility::Protected => Visibility::Protected,
+            SymbolVisibility::Interposable => Visibility::Default,
+        }
+    }
+}
+
 impl<'tcx> CodegenUnit<'tcx> {
     #[inline]
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index ad05cca66ca..5bd484d7bb0 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -904,26 +904,22 @@ fn mono_item_visibility<'tcx>(
 }
 
 fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
-    if !tcx.sess.default_hidden_visibility() {
-        return Visibility::Default;
-    }
-
-    // Generic functions never have export-level C.
-    if is_generic {
-        return Visibility::Hidden;
-    }
-
-    // Things with export level C don't get instantiated in
-    // downstream crates.
-    if !id.is_local() {
-        return Visibility::Hidden;
-    }
+    let export_level = if is_generic {
+        // Generic functions never have export-level C.
+        SymbolExportLevel::Rust
+    } else {
+        match tcx.reachable_non_generics(id.krate).get(&id) {
+            Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => SymbolExportLevel::C,
+            _ => SymbolExportLevel::Rust,
+        }
+    };
+    match export_level {
+        // C-export level items remain at `Default` to allow C code to
+        // access and interpose them.
+        SymbolExportLevel::C => Visibility::Default,
 
-    // C-export level items remain at `Default`, all other internal
-    // items become `Hidden`.
-    match tcx.reachable_non_generics(id.krate).get(&id) {
-        Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default,
-        _ => Visibility::Hidden,
+        // For all other symbols, `default_visibility` determines which visibility to use.
+        SymbolExportLevel::Rust => tcx.sess.default_visibility().into(),
     }
 }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b052d8d72c7..0d293415aa9 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3008,7 +3008,8 @@ pub(crate) mod dep_tracking {
     use rustc_span::edition::Edition;
     use rustc_target::spec::{
         CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
-        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi,
+        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple,
+        TlsModel, WasmCAbi,
     };
 
     use super::{
@@ -3101,6 +3102,7 @@ pub(crate) mod dep_tracking {
         StackProtector,
         SwitchWithOptPath,
         SymbolManglingVersion,
+        SymbolVisibility,
         RemapPathScopeComponents,
         SourceFileHashAlgorithm,
         OutFileName,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index aac776d2919..1de09b8be4d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -13,8 +13,8 @@ use rustc_span::edition::Edition;
 use rustc_span::{RealFileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{
     CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
-    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
-    WasmCAbi,
+    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
+    TargetTriple, TlsModel, WasmCAbi,
 };
 
 use crate::config::*;
@@ -416,6 +416,8 @@ mod desc {
         "one of: `disabled`, `trampolines`, or `aliases`";
     pub(crate) const parse_symbol_mangling_version: &str =
         "one of: `legacy`, `v0` (RFC 2603), or `hashed`";
+    pub(crate) const parse_opt_symbol_visibility: &str =
+        "one of: `hidden`, `protected`, or `interposable`";
     pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`";
     pub(crate) const parse_relocation_model: &str =
         "one of supported relocation models (`rustc --print relocation-models`)";
@@ -922,6 +924,20 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_opt_symbol_visibility(
+        slot: &mut Option<SymbolVisibility>,
+        v: Option<&str>,
+    ) -> bool {
+        if let Some(v) = v {
+            if let Ok(vis) = SymbolVisibility::from_str(v) {
+                *slot = Some(vis);
+            } else {
+                return false;
+            }
+        }
+        true
+    }
+
     pub(crate) fn parse_optimization_fuel(
         slot: &mut Option<(String, u64)>,
         v: Option<&str>,
@@ -1688,8 +1704,8 @@ options! {
         "compress debug info sections (none, zlib, zstd, default: none)"),
     deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
         "deduplicate identical diagnostics (default: yes)"),
-    default_hidden_visibility: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "overrides the `default_hidden_visibility` setting of the target"),
+    default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
+        "overrides the `default_visibility` setting of the target"),
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
         themselves (default: no)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index adc28e38462..d67e69fe0fb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -31,7 +31,8 @@ use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{
     CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
-    SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+    SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
+    TargetTriple, TlsModel,
 };
 
 use crate::code_stats::CodeStats;
@@ -617,12 +618,13 @@ impl Session {
         }
     }
 
-    /// Whether the default visibility of symbols should be "hidden" rather than "default".
-    pub fn default_hidden_visibility(&self) -> bool {
+    /// Returns the default symbol visibility.
+    pub fn default_visibility(&self) -> SymbolVisibility {
         self.opts
             .unstable_opts
-            .default_hidden_visibility
-            .unwrap_or(self.target.options.default_hidden_visibility)
+            .default_visibility
+            .or(self.target.options.default_visibility)
+            .unwrap_or(SymbolVisibility::Interposable)
     }
 }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8f226b26bef..e8aa129c6cd 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -411,6 +411,7 @@ symbols! {
         arbitrary_enum_discriminant,
         arbitrary_self_types,
         arbitrary_self_types_pointers,
+        areg,
         args,
         arith_offset,
         arm,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 4d8c5cea8a8..df13d24cb9e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -439,7 +439,7 @@ impl InlineAsmReg {
             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
             Self::LoongArch(_) => cb(self),
             Self::Mips(_) => cb(self),
-            Self::S390x(_) => cb(self),
+            Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))),
             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
             Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
             Self::Msp430(_) => cb(self),
@@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi {
     AArch64NoX18,
     RiscV,
     LoongArch,
+    S390x,
 }
 
 impl InlineAsmClobberAbi {
@@ -941,6 +942,10 @@ impl InlineAsmClobberAbi {
                 "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
                 _ => Err(&["C", "system"]),
             },
+            InlineAsmArch::S390x => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::S390x),
+                _ => Err(&["C", "system"]),
+            },
             _ => Err(&[]),
         }
     }
@@ -1098,6 +1103,28 @@ impl InlineAsmClobberAbi {
                     f16, f17, f18, f19, f20, f21, f22, f23,
                 }
             },
+            InlineAsmClobberAbi::S390x => clobbered_regs! {
+                S390x S390xInlineAsmReg {
+                    r0, r1, r2, r3, r4, r5,
+                    r14,
+
+                    // f0-f7, v0-v7
+                    f0, f1, f2, f3, f4, f5, f6, f7,
+                    v0, v1, v2, v3, v4, v5, v6, v7,
+
+                    // Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but
+                    // we have no way of expressing this using clobbers.
+                    v8, v9, v10, v11, v12, v13, v14, v15,
+
+                    // Other vector registers are volatile
+                    v16, v17, v18, v19, v20, v21, v22, v23,
+                    v24, v25, v26, v27, v28, v29, v30, v31,
+
+                    // a0-a1 are reserved, other access registers are volatile
+                    a2, a3, a4, a5, a6, a7,
+                    a8, a9, a10, a11, a12, a13, a14, a15,
+                }
+            },
         }
     }
 }
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index 4258b23ac57..9b31190a72b 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -9,6 +9,8 @@ def_reg_class! {
         reg,
         reg_addr,
         freg,
+        vreg,
+        areg,
     }
 }
 
@@ -35,11 +37,13 @@ impl S390xInlineAsmRegClass {
 
     pub fn supported_types(
         self,
-        arch: InlineAsmArch,
+        _arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
-        match (self, arch) {
-            (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; },
-            (Self::freg, _) => types! { _: F32, F64; },
+        match self {
+            Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
+            Self::freg => types! { _: F32, F64; },
+            Self::vreg => &[],
+            Self::areg => &[],
         }
     }
 }
@@ -76,6 +80,52 @@ def_regs! {
         f13: freg = ["f13"],
         f14: freg = ["f14"],
         f15: freg = ["f15"],
+        v0: vreg = ["v0"],
+        v1: vreg = ["v1"],
+        v2: vreg = ["v2"],
+        v3: vreg = ["v3"],
+        v4: vreg = ["v4"],
+        v5: vreg = ["v5"],
+        v6: vreg = ["v6"],
+        v7: vreg = ["v7"],
+        v8: vreg = ["v8"],
+        v9: vreg = ["v9"],
+        v10: vreg = ["v10"],
+        v11: vreg = ["v11"],
+        v12: vreg = ["v12"],
+        v13: vreg = ["v13"],
+        v14: vreg = ["v14"],
+        v15: vreg = ["v15"],
+        v16: vreg = ["v16"],
+        v17: vreg = ["v17"],
+        v18: vreg = ["v18"],
+        v19: vreg = ["v19"],
+        v20: vreg = ["v20"],
+        v21: vreg = ["v21"],
+        v22: vreg = ["v22"],
+        v23: vreg = ["v23"],
+        v24: vreg = ["v24"],
+        v25: vreg = ["v25"],
+        v26: vreg = ["v26"],
+        v27: vreg = ["v27"],
+        v28: vreg = ["v28"],
+        v29: vreg = ["v29"],
+        v30: vreg = ["v30"],
+        v31: vreg = ["v31"],
+        a2: areg = ["a2"],
+        a3: areg = ["a3"],
+        a4: areg = ["a4"],
+        a5: areg = ["a5"],
+        a6: areg = ["a6"],
+        a7: areg = ["a7"],
+        a8: areg = ["a8"],
+        a9: areg = ["a9"],
+        a10: areg = ["a10"],
+        a11: areg = ["a11"],
+        a12: areg = ["a12"],
+        a13: areg = ["a13"],
+        a14: areg = ["a14"],
+        a15: areg = ["a15"],
         #error = ["r11"] =>
             "The frame pointer cannot be used as an operand for inline asm",
         #error = ["r15"] =>
@@ -87,13 +137,8 @@ def_regs! {
             "c12", "c13", "c14", "c15"
         ] =>
             "control registers are reserved by the kernel and cannot be used as operands for inline asm",
-        #error = [
-            "a0", "a1", "a2", "a3",
-            "a4", "a5", "a6", "a7",
-            "a8", "a9", "a10", "a11",
-            "a12", "a13", "a14", "a15"
-        ] =>
-            "access registers are not supported and cannot be used as operands for inline asm",
+        #error = ["a0", "a1"] =>
+            "a0 and a1 are reserved for system use and cannot be used as operands for inline asm",
     }
 }
 
@@ -106,4 +151,48 @@ impl S390xInlineAsmReg {
     ) -> fmt::Result {
         write!(out, "%{}", self.name())
     }
+
+    pub fn overlapping_regs(self, mut cb: impl FnMut(S390xInlineAsmReg)) {
+        macro_rules! reg_conflicts {
+            (
+                $(
+                    $full:ident : $($field:ident)*
+                ),*;
+            ) => {
+                match self {
+                    $(
+                        Self::$full => {
+                            cb(Self::$full);
+                            $(cb(Self::$field);)*
+                        }
+                        $(Self::$field)|* => {
+                            cb(Self::$full);
+                            cb(self);
+                        }
+                    )*
+                    r => cb(r),
+                }
+            };
+        }
+
+        // The left halves of v0-v15 are aliased to f0-f15.
+        reg_conflicts! {
+            v0 : f0,
+            v1 : f1,
+            v2 : f2,
+            v3 : f3,
+            v4 : f4,
+            v5 : f5,
+            v6 : f6,
+            v7 : f7,
+            v8 : f8,
+            v9 : f9,
+            v10 : f10,
+            v11 : f11,
+            v12 : f12,
+            v13 : f13,
+            v14 : f14,
+            v15 : f15;
+        }
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f327c1fd179..d1fcfe4adef 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -830,6 +830,46 @@ impl RelroLevel {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SymbolVisibility {
+    Hidden,
+    Protected,
+    Interposable,
+}
+
+impl SymbolVisibility {
+    pub fn desc(&self) -> &str {
+        match *self {
+            SymbolVisibility::Hidden => "hidden",
+            SymbolVisibility::Protected => "protected",
+            SymbolVisibility::Interposable => "interposable",
+        }
+    }
+}
+
+impl FromStr for SymbolVisibility {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<SymbolVisibility, ()> {
+        match s {
+            "hidden" => Ok(SymbolVisibility::Hidden),
+            "protected" => Ok(SymbolVisibility::Protected),
+            "interposable" => Ok(SymbolVisibility::Interposable),
+            _ => Err(()),
+        }
+    }
+}
+
+impl ToJson for SymbolVisibility {
+    fn to_json(&self) -> Json {
+        match *self {
+            SymbolVisibility::Hidden => "hidden".to_json(),
+            SymbolVisibility::Protected => "protected".to_json(),
+            SymbolVisibility::Interposable => "interposable".to_json(),
+        }
+    }
+}
+
 impl FromStr for RelroLevel {
     type Err = ();
 
@@ -2326,13 +2366,12 @@ pub struct TargetOptions {
     /// for this target unconditionally.
     pub no_builtins: bool,
 
-    /// The default visibility for symbols in this target should be "hidden"
-    /// rather than "default".
+    /// The default visibility for symbols in this target.
     ///
-    /// This value typically shouldn't be accessed directly, but through
-    /// the `rustc_session::Session::default_hidden_visibility` method, which
-    /// allows `rustc` users to override this setting using cmdline flags.
-    pub default_hidden_visibility: bool,
+    /// This value typically shouldn't be accessed directly, but through the
+    /// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override
+    /// this setting using cmdline flags.
+    pub default_visibility: Option<SymbolVisibility>,
 
     /// Whether a .debug_gdb_scripts section will be added to the output object file
     pub emit_debug_gdb_scripts: bool,
@@ -2623,7 +2662,7 @@ impl Default for TargetOptions {
             requires_lto: false,
             singlethread: false,
             no_builtins: false,
-            default_hidden_visibility: false,
+            default_visibility: None,
             emit_debug_gdb_scripts: true,
             requires_uwtable: false,
             default_uwtable: false,
@@ -2963,6 +3002,18 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, Option<SymbolVisibility>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
+                    match s.parse::<SymbolVisibility>() {
+                        Ok(level) => base.$key_name = Some(level),
+                        _ => return Some(Err(format!("'{}' is not a valid value for \
+                                                      symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
+                                                      s))),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, DebuginfoKind) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@@ -3353,7 +3404,7 @@ impl Target {
         key!(requires_lto, bool);
         key!(singlethread, bool);
         key!(no_builtins, bool);
-        key!(default_hidden_visibility, bool);
+        key!(default_visibility, Option<SymbolVisibility>)?;
         key!(emit_debug_gdb_scripts, bool);
         key!(requires_uwtable, bool);
         key!(default_uwtable, bool);
@@ -3633,7 +3684,7 @@ impl ToJson for Target {
         target_option_val!(requires_lto);
         target_option_val!(singlethread);
         target_option_val!(no_builtins);
-        target_option_val!(default_hidden_visibility);
+        target_option_val!(default_visibility);
         target_option_val!(emit_debug_gdb_scripts);
         target_option_val!(requires_uwtable);
         target_option_val!(default_uwtable);
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index be14107baa9..0a98b363b1a 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -373,7 +373,7 @@ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 
 const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("a", Stable, &[]),
+    ("a", Stable, &["zaamo", "zalrsc"]),
     ("c", Stable, &[]),
     ("d", Unstable(sym::riscv_target_feature), &["f"]),
     ("e", Unstable(sym::riscv_target_feature), &[]),
@@ -382,6 +382,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("relax", Unstable(sym::riscv_target_feature), &[]),
     ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
     ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("zaamo", Unstable(sym::riscv_target_feature), &[]),
+    ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
+    ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
     ("zba", Stable, &[]),
     ("zbb", Stable, &[]),
     ("zbc", Stable, &[]),
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index de1d4ef15ac..d562692c1a8 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError};
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
+use rustc_type_ir::relate::Relate;
 
 use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
 use crate::error_reporting::InferCtxtErrorExt;
@@ -133,6 +134,20 @@ where
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
+    pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        trace: TypeTrace<'tcx>,
+        expected: T,
+        actual: T,
+    ) -> Result<(), TypeError<'tcx>> {
+        self.infcx
+            .at(cause, param_env)
+            .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+    }
+
     /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
     pub fn sub<T: ToTrace<'tcx>>(
         &self,
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index a2760fe6049..6e6f948a2cd 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -2,6 +2,9 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::at::ToTrace;
+use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
@@ -13,7 +16,7 @@ use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
 use crate::errors::DumpVTableEntries;
-use crate::traits::{impossible_predicates, is_vtable_safe_method};
+use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
 
 #[derive(Clone, Debug)]
 pub enum VtblSegment<'tcx> {
@@ -22,6 +25,8 @@ pub enum VtblSegment<'tcx> {
 }
 
 /// Prepare the segments for a vtable
+// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
+// about our `Self` type here.
 pub fn prepare_vtable_segments<'tcx, T>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
@@ -327,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
     let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
         bug!();
     };
-    let source_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal =
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
 
-    let target_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key)
-        // We don't care about the self type, since it will always be the same thing.
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key));
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -343,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
                 VtblSegment::MetadataDSA => {
                     vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    if tcx
-                        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref)
-                        == target_principal
-                    {
+                VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
+                    if trait_refs_are_compatible(
+                        tcx,
+                        vtable_principal
+                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
+                        target_principal,
+                    ) {
                         return ControlFlow::Break(vptr_offset);
                     }
 
-                    vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
+                    vptr_offset +=
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
 
                     if emit_vptr {
                         vptr_offset += 1;
@@ -383,17 +387,14 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     let ty::Dynamic(target, _, _) = *target.kind() else {
         bug!();
     };
-    let target_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?)
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let target_principal = target.principal()?;
 
     // Given that we have a target principal, it is a bug for there not to be a source principal.
     let ty::Dynamic(source, _, _) = *source.kind() else {
         bug!();
     };
-    let source_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal =
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -402,11 +403,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
                 VtblSegment::MetadataDSA => {
                     vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
-                    if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref)
-                        == target_principal
-                    {
+                VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
+                    vptr_offset +=
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
+                    if trait_refs_are_compatible(
+                        tcx,
+                        vtable_principal
+                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
+                        target_principal,
+                    ) {
                         if emit_vptr {
                             return ControlFlow::Break(Some(vptr_offset));
                         } else {
@@ -426,6 +431,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
 }
 
+fn trait_refs_are_compatible<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
+    hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
+) -> bool {
+    if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
+        return false;
+    }
+
+    let infcx = tcx.infer_ctxt().build();
+    let param_env = ty::ParamEnv::reveal_all();
+    let ocx = ObligationCtxt::new(&infcx);
+    let hr_source_principal =
+        ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
+    let hr_target_principal =
+        ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal);
+    infcx.enter_forall(hr_target_principal, |target_principal| {
+        let source_principal = infcx.instantiate_binder_with_fresh_vars(
+            DUMMY_SP,
+            BoundRegionConversionTime::HigherRankedType,
+            hr_source_principal,
+        );
+        let Ok(()) = ocx.eq_trace(
+            &ObligationCause::dummy(),
+            param_env,
+            ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal),
+            target_principal,
+            source_principal,
+        ) else {
+            return false;
+        };
+        ocx.select_all_or_error().is_empty()
+    })
+}
+
 pub(super) fn provide(providers: &mut Providers) {
     *providers = Providers {
         own_existential_vtable_entries,
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 6421504b896..5f207295683 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -228,6 +228,7 @@ mod thin;
 #[lang = "owned_box"]
 #[fundamental]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 // The declaration of the `Box` struct must be kept in sync with the
 // compiler or ICEs will happen.
 pub struct Box<
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 797d591a8b5..d496899e72b 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -696,6 +696,7 @@ impl CString {
 // memory-unsafe code from working by accident. Inline
 // to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
+#[rustc_insignificant_dtor]
 impl Drop for CString {
     #[inline]
     fn drop(&mut self) {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index ced789c4f92..5d099a49854 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -237,6 +237,7 @@ macro_rules! acquire {
 /// [rc_examples]: crate::rc#examples
 #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct Arc<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 55e67e5c255..7f3c998aaa5 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -69,7 +69,7 @@ impl char {
     /// assert_eq!(char::from_u32(value_at_max + 1), None);
     /// ```
     #[stable(feature = "assoc_char_consts", since = "1.52.0")]
-    pub const MAX: char = '\u{10ffff}';
+    pub const MAX: char = '\u{10FFFF}';
 
     /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
     /// decoding error.
@@ -1841,7 +1841,6 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] {
         }
         (2, [a, b, ..]) => {
             code -= 0x1_0000;
-
             *a = (code >> 10) as u16 | 0xD800;
             *b = (code & 0x3FF) as u16 | 0xDC00;
         }
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index e7726da8d91..aecd725eca5 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -208,75 +208,119 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
       8081828384858687888990919293949596979899";
 
 macro_rules! impl_Display {
-    ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
-        #[cfg(not(feature = "optimize_for_size"))]
-        fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            // 2^128 is about 3*10^38, so 39 gives an extra byte of space
-            let mut buf = [MaybeUninit::<u8>::uninit(); 39];
-            let mut curr = buf.len();
-            let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
-            let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+    ($($t:ident $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
 
-            // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
-            // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
-            // that it's OK to copy into `buf_ptr`, notice that at the beginning
-            // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
-            // each step this is kept the same as `n` is divided. Since `n` is always
-            // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
-            // is safe to access.
-            unsafe {
-                // need at least 16 bits for the 4-characters-at-a-time to work.
-                assert!(crate::mem::size_of::<$u>() >= 2);
+        $(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl fmt::Display for $t {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                // If it's a signed integer.
+                $(
+                    let is_nonnegative = *self >= 0;
 
-                // eagerly decode 4 characters at a time
-                while n >= 10000 {
-                    let rem = (n % 10000) as usize;
-                    n /= 10000;
+                    #[cfg(not(feature = "optimize_for_size"))]
+                    {
+                        if !is_nonnegative {
+                            // convert the negative num to positive by summing 1 to its 2s complement
+                            return (!self as $positive).wrapping_add(1)._fmt(false, f);
+                        }
+                    }
+                    #[cfg(feature = "optimize_for_size")]
+                    {
+                        if !is_nonnegative {
+                            // convert the negative num to positive by summing 1 to its 2s complement
+                            return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f);
+                        }
+                    }
+                )?
+                // If it's a positive integer.
+                #[cfg(not(feature = "optimize_for_size"))]
+                {
+                    self._fmt(true, f)
+                }
+                #[cfg(feature = "optimize_for_size")]
+                {
+                    $gen_name(self.$conv_fn(), true, f)
+                }
+            }
+        }
 
-                    let d1 = (rem / 100) << 1;
-                    let d2 = (rem % 100) << 1;
-                    curr -= 4;
+        #[cfg(not(feature = "optimize_for_size"))]
+        impl $t {
+            fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                const SIZE: usize = $t::MAX.ilog(10) as usize + 1;
+                let mut buf = [MaybeUninit::<u8>::uninit(); SIZE];
+                let mut curr = SIZE;
+                let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
+                let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+
+                // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
+                // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
+                // that it's OK to copy into `buf_ptr`, notice that at the beginning
+                // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
+                // each step this is kept the same as `n` is divided. Since `n` is always
+                // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
+                // is safe to access.
+                unsafe {
+                    // need at least 16 bits for the 4-characters-at-a-time to work.
+                    #[allow(overflowing_literals)]
+                    #[allow(unused_comparisons)]
+                    // This block will be removed for smaller types at compile time and in the worst
+                    // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`.
+                    if core::mem::size_of::<$t>() >= 2 {
+                        // eagerly decode 4 characters at a time
+                        while self >= 10000 {
+                            let rem = (self % 10000) as usize;
+                            self /= 10000;
+
+                            let d1 = (rem / 100) << 1;
+                            let d2 = (rem % 100) << 1;
+                            curr -= 4;
+
+                            // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
+                            // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
+                            // which is `10^40 > 2^128 > n`.
+                            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2);
+                            ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2);
+                        }
+                    }
 
-                    // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
-                    // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
-                    // which is `10^40 > 2^128 > n`.
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
-                    ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2);
-                }
+                    // if we reach here numbers are <= 9999, so at most 4 chars long
+                    let mut n = self as usize; // possibly reduce 64bit math
 
-                // if we reach here numbers are <= 9999, so at most 4 chars long
-                let mut n = n as usize; // possibly reduce 64bit math
+                    // decode 2 more chars, if > 2 chars
+                    if n >= 100 {
+                        let d1 = (n % 100) << 1;
+                        n /= 100;
+                        curr -= 2;
+                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    }
 
-                // decode 2 more chars, if > 2 chars
-                if n >= 100 {
-                    let d1 = (n % 100) << 1;
-                    n /= 100;
-                    curr -= 2;
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    // if we reach here numbers are <= 100, so at most 2 chars long
+                    // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
+                    // decode last 1 or 2 chars
+                    if n < 10 {
+                        curr -= 1;
+                        *buf_ptr.add(curr) = (n as u8) + b'0';
+                    } else {
+                        let d1 = n << 1;
+                        curr -= 2;
+                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    }
                 }
 
-                // decode last 1 or 2 chars
-                if n < 10 {
-                    curr -= 1;
-                    *buf_ptr.add(curr) = (n as u8) + b'0';
-                } else {
-                    let d1 = n << 1;
-                    curr -= 2;
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
-                }
+                // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
+                // UTF-8 since `DEC_DIGITS_LUT` is
+                let buf_slice = unsafe {
+                    str::from_utf8_unchecked(
+                        slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
+                };
+                f.pad_integral(is_nonnegative, "", buf_slice)
             }
-
-            // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
-            // UTF-8 since `DEC_DIGITS_LUT` is
-            let buf_slice = unsafe {
-                str::from_utf8_unchecked(
-                    slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
-            };
-            f.pad_integral(is_nonnegative, "", buf_slice)
-        }
+        })*
 
         #[cfg(feature = "optimize_for_size")]
-        fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             // 2^128 is about 3*10^38, so 39 gives an extra byte of space
             let mut buf = [MaybeUninit::<u8>::uninit(); 39];
             let mut curr = buf.len();
@@ -306,21 +350,6 @@ macro_rules! impl_Display {
             };
             f.pad_integral(is_nonnegative, "", buf_slice)
         }
-
-        $(#[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $t {
-            #[allow(unused_comparisons)]
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let is_nonnegative = *self >= 0;
-                let n = if is_nonnegative {
-                    self.$conv_fn()
-                } else {
-                    // convert the negative num to positive by summing 1 to it's 2 complement
-                    (!self.$conv_fn()).wrapping_add(1)
-                };
-                $name(n, is_nonnegative, f)
-            }
-        })*
     };
 }
 
@@ -374,7 +403,6 @@ macro_rules! impl_Exp {
                 (n, exponent, exponent, added_precision)
             };
 
-            // 39 digits (worst case u128) + . = 40
             // Since `curr` always decreases by the number of digits copied, this means
             // that `curr >= 0`.
             let mut buf = [MaybeUninit::<u8>::uninit(); 40];
@@ -469,7 +497,7 @@ macro_rules! impl_Exp {
                     let n = if is_nonnegative {
                         self.$conv_fn()
                     } else {
-                        // convert the negative num to positive by summing 1 to it's 2 complement
+                        // convert the negative num to positive by summing 1 to its 2s complement
                         (!self.$conv_fn()).wrapping_add(1)
                     };
                     $name(n, is_nonnegative, false, f)
@@ -484,7 +512,7 @@ macro_rules! impl_Exp {
                     let n = if is_nonnegative {
                         self.$conv_fn()
                     } else {
-                        // convert the negative num to positive by summing 1 to it's 2 complement
+                        // convert the negative num to positive by summing 1 to its 2s complement
                         (!self.$conv_fn()).wrapping_add(1)
                     };
                     $name(n, is_nonnegative, true, f)
@@ -499,8 +527,17 @@ macro_rules! impl_Exp {
 mod imp {
     use super::*;
     impl_Display!(
-        i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
-            as u64 via to_u64 named fmt_u64
+        i8 as u8 named fmt_i8,
+        u8 named fmt_u8,
+        i16 as u16  named fmt_i16,
+        u16 named fmt_u16,
+        i32 as u32 named fmt_i32,
+        u32 named fmt_u32,
+        i64 as u64 named fmt_i64,
+        u64 named fmt_u64,
+        isize as usize named fmt_isize,
+        usize named fmt_usize,
+        ; as u64 via to_u64 named fmt_u64
     );
     impl_Exp!(
         i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
@@ -511,8 +548,21 @@ mod imp {
 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
 mod imp {
     use super::*;
-    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
-    impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
+    impl_Display!(
+        i8 as u8 named fmt_i8,
+        u8 named fmt_u8,
+        i16 as u16  named fmt_i16,
+        u16 named fmt_u16,
+        i32 as u32 named fmt_i32,
+        u32 named fmt_u32,
+        isize as usize named fmt_isize,
+        usize named fmt_usize,
+        ; as u32 via to_u32 named fmt_u32);
+    impl_Display!(
+        i64 as u64 named fmt_i64,
+        u64 named fmt_u64,
+        ; as u64 via to_u64 named fmt_u64);
+
     impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
     impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
 }
@@ -619,7 +669,7 @@ impl fmt::Display for i128 {
         let n = if is_nonnegative {
             self.to_u128()
         } else {
-            // convert the negative num to positive by summing 1 to it's 2 complement
+            // convert the negative num to positive by summing 1 to its 2s complement
             (!self.to_u128()).wrapping_add(1)
         };
         fmt_u128(n, is_nonnegative, f)
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index dec67f9fe51..d7a2f1909ca 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1425,8 +1425,7 @@ extern "rust-intrinsic" {
     ///
     /// If the computed offset is non-zero, then both the starting and resulting pointer must be
     /// either in bounds or at the end of an allocated object. If either pointer is out
-    /// of bounds or arithmetic overflow occurs then any further use of the returned value will
-    /// result in undefined behavior.
+    /// of bounds or arithmetic overflow occurs then this operation is undefined behavior.
     ///
     /// The stabilized version of this intrinsic is [`pointer::offset`].
     #[must_use = "returns a new pointer rather than modifying its argument"]
@@ -3165,7 +3164,7 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 {
 /// change the possible layouts of pointers.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@@ -3190,7 +3189,7 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
 /// This is used to implement functions like `ptr::metadata`.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 1146ca6ef43..332c5e904d7 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -92,7 +92,7 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")]
+    #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
@@ -346,7 +346,7 @@ impl<T: ?Sized> *const T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Adds an offset to a pointer.
+    /// Adds a signed offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -355,7 +355,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -398,7 +399,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes.
+    /// Adds a signed offset in bytes to a pointer.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -412,14 +413,13 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         unsafe { self.cast::<u8>().offset(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
+    /// Adds a signed offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -481,7 +481,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::arith_offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
+    /// Adds a signed offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -495,7 +495,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_offset(self, count: isize) -> Self {
         self.cast::<u8>().wrapping_offset(count).with_metadata_of(self)
     }
@@ -645,7 +644,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
@@ -807,7 +805,11 @@ impl<T: ?Sized> *const T {
         }
     }
 
-    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an unsigned offset to a pointer.
+    ///
+    /// This can only move the pointer forward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -816,7 +818,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -859,7 +862,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
+    /// Adds an unsigned offset in bytes to a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -873,15 +876,17 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Subtracts an offset from a pointer (convenience for
-    /// `.offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset from a pointer.
+    ///
+    /// This can only move the pointer backward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -890,7 +895,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -941,8 +947,7 @@ impl<T: ?Sized> *const T {
         }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for
-    /// `.byte_offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset in bytes from a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -956,15 +961,13 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         unsafe { self.cast::<u8>().sub(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset(count as isize)`)
+    /// Adds an unsigned offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1025,8 +1028,7 @@ impl<T: ?Sized> *const T {
         self.wrapping_offset(count as isize)
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_byte_offset(count as isize)`)
+    /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1039,13 +1041,11 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_add(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_add(count).with_metadata_of(self)
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1106,8 +1106,7 @@ impl<T: ?Sized> *const T {
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1120,7 +1119,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_sub(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_sub(count).with_metadata_of(self)
     }
@@ -1554,7 +1552,6 @@ impl<T> *const [T] {
     #[inline]
     #[stable(feature = "slice_ptr_len", since = "1.79.0")]
     #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 76a0e2ba774..feeaf78d3e7 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -92,7 +92,7 @@ pub trait Thin = Pointee<Metadata = ()>;
 ///
 /// assert_eq!(std::ptr::metadata("foo"), 3_usize);
 /// ```
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
     ptr_metadata(ptr)
@@ -106,7 +106,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
 ///
 /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn from_raw_parts<T: ?Sized>(
     data_pointer: *const impl Thin,
@@ -120,7 +120,7 @@ pub const fn from_raw_parts<T: ?Sized>(
 ///
 /// See the documentation of [`from_raw_parts`] for more details.
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn from_raw_parts_mut<T: ?Sized>(
     data_pointer: *mut impl Thin,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 4f97048eab1..b6df780fe2f 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -599,7 +599,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null"]
 pub const fn null<T: ?Sized + Thin>() -> *const T {
     from_raw_parts(without_provenance::<()>(0), ())
@@ -625,7 +624,6 @@ pub const fn null<T: ?Sized + Thin>() -> *const T {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null_mut"]
 pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
     from_raw_parts_mut(without_provenance_mut::<()>(0), ())
@@ -949,7 +947,6 @@ pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
 #[inline]
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
 #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"]
 pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
     from_raw_parts(data, len)
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 8e33cf081ba..287073497f8 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -74,7 +74,7 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")]
+    #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
@@ -344,7 +344,7 @@ impl<T: ?Sized> *mut T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Adds an offset to a pointer.
+    /// Adds a signed offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -353,7 +353,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -398,7 +399,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes.
+    /// Adds a signed offset in bytes to a pointer.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -412,14 +413,14 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         unsafe { self.cast::<u8>().offset(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
+    /// Adds a signed offset to a pointer using wrapping arithmetic.
+    ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
@@ -478,7 +479,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::arith_offset(self, count) as *mut T }
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
+    /// Adds a signed offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -492,7 +493,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_offset(self, count: isize) -> Self {
         self.cast::<u8>().wrapping_offset(count).with_metadata_of(self)
     }
@@ -808,7 +808,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
@@ -888,7 +887,11 @@ impl<T: ?Sized> *mut T {
         unsafe { (self as *const T).sub_ptr(origin) }
     }
 
-    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an unsigned offset to a pointer.
+    ///
+    /// This can only move the pointer forward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -897,7 +900,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -940,7 +944,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
+    /// Adds an unsigned offset in bytes to a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -954,15 +958,17 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Subtracts an offset from a pointer (convenience for
-    /// `.offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset from a pointer.
+    ///
+    /// This can only move the pointer backward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -971,7 +977,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -1022,8 +1029,7 @@ impl<T: ?Sized> *mut T {
         }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for
-    /// `.byte_offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset in bytes from a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1037,15 +1043,13 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         unsafe { self.cast::<u8>().sub(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset(count as isize)`)
+    /// Adds an unsigned offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1104,8 +1108,7 @@ impl<T: ?Sized> *mut T {
         self.wrapping_offset(count as isize)
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_byte_offset(count as isize)`)
+    /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1118,13 +1121,11 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_add(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_add(count).with_metadata_of(self)
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1183,8 +1184,7 @@ impl<T: ?Sized> *mut T {
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1197,7 +1197,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_sub(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_sub(count).with_metadata_of(self)
     }
@@ -1804,7 +1803,6 @@ impl<T> *mut [T] {
     #[inline(always)]
     #[stable(feature = "slice_ptr_len", since = "1.79.0")]
     #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index daa40b3c9d2..e7a265f7e2b 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -567,7 +567,6 @@ impl<T: ?Sized> NonNull<T> {
     #[must_use]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
     #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
     pub const unsafe fn byte_add(self, count: usize) -> Self {
@@ -651,7 +650,6 @@ impl<T: ?Sized> NonNull<T> {
     #[must_use]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
     #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dd8fa1ae343..922168b9e8e 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -111,7 +111,6 @@ impl<T> [T] {
     #[lang = "slice_len_fn"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     #[inline]
     #[must_use]
     pub const fn len(&self) -> usize {
diff --git a/library/std/build.rs b/library/std/build.rs
index c5d0af469a8..7d37d4e9d7d 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -101,10 +101,7 @@ fn main() {
         // Unsupported <https://github.com/llvm/llvm-project/issues/94434>
         ("arm64ec", _) => false,
         // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
-        ("x86_64", "windows") => false,
-        // Apple has a special ABI for `f16` that we do not yet support
-        // FIXME(builtins): fixed by <https://github.com/rust-lang/compiler-builtins/pull/675>
-        ("x86" | "x86_64", _) if target_vendor == "apple" => false,
+        ("x86_64", "windows") if target_env == "gnu" => false,
         // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
         ("csky", _) => false,
         ("hexagon", _) => false,
@@ -132,10 +129,10 @@ fn main() {
         // ABI unsupported  <https://github.com/llvm/llvm-project/issues/41838>
         ("sparc", _) => false,
         // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
-        ("x86_64", "windows") => false,
+        ("x86_64", "windows") if target_env == "gnu" => false,
         // 64-bit Linux is about the only platform to have f128 symbols by default
         (_, "linux") if target_pointer_width == 64 => true,
-        // Same as for f16, except MacOS is also missing f128 symbols.
+        // Almost all OSs are missing symbol. compiler-builtins will have to add them.
         _ => false,
     };
 
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index c28dd7b6b50..fa8ea95b891 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -274,7 +274,7 @@ fn test_lots_of_insertions() {
     for _ in 0..loops {
         assert!(m.is_empty());
 
-        let count = if cfg!(miri) { 101 } else { 1001 };
+        let count = if cfg!(miri) { 66 } else { 1001 };
 
         for i in 1..count {
             assert!(m.insert(i, i).is_none());
@@ -1018,6 +1018,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn drop_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1047,6 +1048,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1076,6 +1078,7 @@ mod test_extract_if {
 
     // Same as above, but attempt to use the iterator again after the panic in the predicate
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_reuse() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 7aa2167e213..8ee8a3e8bf6 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -429,6 +429,7 @@ fn test_extract_if() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_drop_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -459,6 +460,7 @@ fn test_extract_if_drop_panic_leak() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_pred_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
index fc7aee29733..d0217261068 100644
--- a/library/std/src/env/tests.rs
+++ b/library/std/src/env/tests.rs
@@ -1,7 +1,7 @@
 use super::*;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)]
 fn test_self_exe_path() {
     let path = current_exe();
     assert!(path.is_ok());
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index db7867337dd..124ef121b18 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -8,7 +8,15 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::ffi::OsString;
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index d89ecd317d6..bff0f823c4b 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -164,6 +164,7 @@ fn test_buffered_reader_stream_position() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_buffered_reader_stream_position_panic() {
     let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
     let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner));
@@ -487,7 +488,7 @@ fn dont_panic_in_drop_on_panicked_flush() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_in_write_doesnt_flush_in_drop() {
     static WRITES: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 80ba8455df3..a839a2fbac1 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -124,6 +124,7 @@ const TAG_SIMPLE: usize = 0b11;
 /// is_unwind_safe::<std::io::Error>();
 /// ```
 #[repr(transparent)]
+#[rustc_insignificant_dtor]
 pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
 
 // All the types `Repr` stores internally are Send + Sync, and so is it.
diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs
index ea76a271d12..bf8f3a5adfb 100644
--- a/library/std/src/io/stdio/tests.rs
+++ b/library/std/src/io/stdio/tests.rs
@@ -25,7 +25,7 @@ fn stderrlock_unwind_safe() {
 fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_doesnt_poison() {
     thread::spawn(|| {
         let _a = stdin();
@@ -48,17 +48,17 @@ fn panic_doesnt_poison() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stderr() {
     test_lock(stderr, || stderr().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdin() {
     test_lock(stdin, || stdin().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdout() {
     test_lock(stdout, || stdout().lock());
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b81e7c18abb..65a9aa66c7c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -153,7 +153,7 @@
 //! the [`io`], [`fs`], and [`net`] modules.
 //!
 //! The [`thread`] module contains Rust's threading abstractions. [`sync`]
-//! contains further primitive shared memory types, including [`atomic`] and
+//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and
 //! [`mpsc`], which contains the channel types for message passing.
 //!
 //! # Use before and after `main()`
@@ -177,6 +177,7 @@
 //! - after-main use of thread-locals, which also affects additional features:
 //!   - [`thread::current()`]
 //!   - [`thread::scope()`]
+//!   - [`sync::mpmc`]
 //!   - [`sync::mpsc`]
 //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms
 //!
@@ -202,6 +203,7 @@
 //! [`atomic`]: sync::atomic
 //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
 //! [`str`]: prim@str
+//! [`mpmc`]: sync::mpmc
 //! [`mpsc`]: sync::mpsc
 //! [`std::cmp`]: cmp
 //! [`std::slice`]: mod@slice
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 8a9426b61f9..4d673a1d66d 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "ip_addr", since = "1.7.0")]
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 84922aabdb5..ba9c948a2e9 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index f81a13d4c44..67a0f7e439d 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -1,6 +1,13 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index d26517d74e4..a7b5cdf4ec0 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -57,6 +57,7 @@ fn connect_timeout_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn listen_localhost() {
     let socket_addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&socket_addr));
@@ -73,6 +74,7 @@ fn listen_localhost() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn connect_loopback() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -94,6 +96,7 @@ fn connect_loopback() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn smoke_test() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -114,6 +117,7 @@ fn smoke_test() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_eof() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -133,6 +137,7 @@ fn read_eof() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn write_close() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -161,6 +166,7 @@ fn write_close() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_serial() {
     each_ip(&mut |addr| {
         let max = 10;
@@ -183,6 +189,7 @@ fn multiple_connect_serial() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_greedy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -220,6 +227,7 @@ fn multiple_connect_interleaved_greedy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_lazy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -255,6 +263,7 @@ fn multiple_connect_interleaved_lazy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_and_peer_name() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -270,6 +279,7 @@ fn socket_and_peer_name() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn partial_read() {
     each_ip(&mut |addr| {
         let (tx, rx) = channel();
@@ -291,6 +301,7 @@ fn partial_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_buf() {
     each_ip(&mut |addr| {
         let srv = t!(TcpListener::bind(&addr));
@@ -389,6 +400,7 @@ fn double_bind() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_smoke() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -420,6 +432,7 @@ fn tcp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_read() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -454,6 +467,7 @@ fn tcp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_write() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -483,6 +497,7 @@ fn tcp_clone_two_write() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn shutdown_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -505,6 +520,7 @@ fn shutdown_smoke() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_readwrite_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -547,6 +563,7 @@ fn close_readwrite_smoke() {
 #[cfg_attr(target_env = "sgx", ignore)]
 // On windows, shutdown will not wake up blocking I/O operations.
 #[cfg_attr(windows, ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_read_wakes_up() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -574,6 +591,7 @@ fn close_read_wakes_up() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_while_reading() {
     each_ip(&mut |addr| {
         let accept = t!(TcpListener::bind(&addr));
@@ -614,6 +632,7 @@ fn clone_while_reading() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -632,6 +651,7 @@ fn clone_accept_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_concurrent() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -670,10 +690,10 @@ fn debug() {
         addr.to_string()
     }
 
+    #[cfg(any(unix, target_os = "wasi"))]
+    use crate::os::fd::AsRawFd;
     #[cfg(target_env = "sgx")]
     use crate::os::fortanix_sgx::io::AsRawFd;
-    #[cfg(unix)]
-    use crate::os::unix::io::AsRawFd;
     #[cfg(not(windows))]
     fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
         addr.as_raw_fd()
@@ -714,6 +734,7 @@ fn debug() {
     ignore
 )]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -742,6 +763,7 @@ fn timeouts() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -763,6 +785,7 @@ fn test_read_timeout() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -810,6 +833,7 @@ fn test_timeout_zero_duration() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // linger not supported
 fn linger() {
     let addr = next_test_ip4();
     let _listener = t!(TcpListener::bind(&addr));
@@ -879,6 +903,7 @@ fn set_nonblocking() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn peek() {
     each_ip(&mut |addr| {
         let (txdone, rxdone) = channel();
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index b78e52023b3..6df47d7b0e0 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -1,4 +1,12 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index 0cf99366452..1c8c58d1879 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -27,6 +27,7 @@ fn bind_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_smoke_test_ip4() {
     each_ip(&mut |server_ip, client_ip| {
         let (tx1, rx1) = channel();
@@ -69,6 +70,7 @@ fn socket_peer() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_smoke() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -98,6 +100,7 @@ fn udp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_read() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -130,6 +133,7 @@ fn udp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_write() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -183,6 +187,7 @@ fn debug() {
     any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"),
     ignore
 )]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -208,6 +213,7 @@ fn timeouts() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
 
@@ -232,6 +238,7 @@ fn test_read_timeout() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
 
@@ -291,6 +298,7 @@ fn connect_send_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek not supported
 fn connect_send_peek_recv() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
@@ -313,6 +321,7 @@ fn connect_send_peek_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek_from not supported
 fn peek_from() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 6436872087d..b75793d2bc9 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -139,7 +139,7 @@ fn test_pathbuf_leak() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 pub fn test_decompositions_unix() {
     t!("",
     iter: [],
@@ -1201,7 +1201,10 @@ pub fn test_push() {
         });
     );
 
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tp!("", "foo", "foo");
         tp!("foo", "bar", "foo/bar");
         tp!("foo/", "bar", "foo/bar");
@@ -1358,7 +1361,10 @@ pub fn test_set_file_name() {
     tfn!("foo", "bar", "bar");
     tfn!("foo", "", "");
     tfn!("", "foo", "foo");
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tfn!(".", "foo", "./foo");
         tfn!("foo/", "bar", "bar");
         tfn!("foo/.", "bar", "bar");
@@ -1758,7 +1764,7 @@ fn test_components_debug() {
     assert_eq!(expected, actual);
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 #[test]
 fn test_iter_debug() {
     let path = Path::new("/tmp");
@@ -1859,7 +1865,7 @@ fn test_ord() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 fn test_unix_absolute() {
     use crate::path::absolute;
 
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index c84a5c65263..f24fe353e55 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -148,7 +148,15 @@
 #![stable(feature = "process", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::convert::Infallible;
diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs
index c5620cd91d8..0fbcd998812 100644
--- a/library/std/src/sync/barrier/tests.rs
+++ b/library/std/src/sync/barrier/tests.rs
@@ -3,7 +3,7 @@ use crate::sync::{Arc, Barrier};
 use crate::thread;
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_barrier() {
     const N: usize = 10;
 
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
index 12d13a6b20b..f9e9066bc92 100644
--- a/library/std/src/sync/condvar/tests.rs
+++ b/library/std/src/sync/condvar/tests.rs
@@ -12,7 +12,7 @@ fn smoke() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_one() {
     let m = Arc::new(Mutex::new(()));
     let m2 = m.clone();
@@ -29,7 +29,7 @@ fn notify_one() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_all() {
     const N: usize = 10;
 
@@ -66,7 +66,7 @@ fn notify_all() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_while() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair2 = pair.clone();
@@ -87,7 +87,7 @@ fn wait_while() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -106,7 +106,7 @@ fn wait_timeout_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -118,7 +118,7 @@ fn wait_timeout_while_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_instant_satisfy() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -130,7 +130,7 @@ fn wait_timeout_while_instant_satisfy() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_while_wake() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair_copy = pair.clone();
@@ -153,7 +153,7 @@ fn wait_timeout_while_wake() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_wake() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs
index 94044368305..7d7dde54349 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/src/sync/lazy_lock/tests.rs
@@ -34,6 +34,7 @@ fn lazy_default() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn lazy_poisoning() {
     let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
     for _ in 0..2 {
@@ -43,7 +44,7 @@ fn lazy_poisoning() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_lazy_new() {
     static CALLED: AtomicUsize = AtomicUsize::new(0);
     static SYNC_LAZY: LazyLock<i32> = LazyLock::new(|| {
@@ -90,7 +91,7 @@ fn sync_lazy_default() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn static_sync_lazy() {
     static XS: LazyLock<Vec<i32>> = LazyLock::new(|| {
         let mut xs = Vec::new();
@@ -123,6 +124,7 @@ fn static_sync_lazy_via_fn() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn sync_lazy_poisoning() {
     let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom"));
     for _ in 0..2 {
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index 0fb8e669bf8..0fb77331293 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -133,6 +133,11 @@
 //!   inter-thread synchronisation mechanism, at the cost of some
 //!   extra memory.
 //!
+//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for
+//!   message-based communication. Can provide a lightweight
+//!   inter-thread synchronisation mechanism, at the cost of some
+//!   extra memory.
+//!
 //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
 //!   most one thread at a time is able to access some data.
 //!
@@ -153,6 +158,7 @@
 //! [`Arc`]: crate::sync::Arc
 //! [`Barrier`]: crate::sync::Barrier
 //! [`Condvar`]: crate::sync::Condvar
+//! [`mpmc`]: crate::sync::mpmc
 //! [`mpsc`]: crate::sync::mpsc
 //! [`Mutex`]: crate::sync::Mutex
 //! [`Once`]: crate::sync::Once
@@ -193,12 +199,13 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+pub mod mpmc;
 pub mod mpsc;
 
 mod barrier;
 mod condvar;
 mod lazy_lock;
-mod mpmc;
 mod mutex;
 pub(crate) mod once;
 mod once_lock;
diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs
index e3aec7e7623..e34b56d0831 100644
--- a/library/std/src/sync/mpmc/error.rs
+++ b/library/std/src/sync/mpmc/error.rs
@@ -7,6 +7,7 @@ use crate::{error, fmt};
 ///
 /// [`send_timeout`]: super::Sender::send_timeout
 #[derive(PartialEq, Eq, Clone, Copy)]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub enum SendTimeoutError<T> {
     /// The message could not be sent because the channel is full and the operation timed out.
     ///
@@ -18,12 +19,14 @@ pub enum SendTimeoutError<T> {
     Disconnected(T),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         "SendTimeoutError(..)".fmt(f)
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Display for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -33,8 +36,10 @@ impl<T> fmt::Display for SendTimeoutError<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> error::Error for SendTimeoutError<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> From<SendError<T>> for SendTimeoutError<T> {
     fn from(err: SendError<T>) -> SendTimeoutError<T> {
         match err {
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index c640e07348e..77a67f4fd38 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -1,8 +1,112 @@
-//! Multi-producer multi-consumer channels.
+//! Multi-producer, multi-consumer FIFO queue communication primitives.
+//!
+//! This module provides message-based communication over channels, concretely
+//! defined by two types:
+//!
+//! * [`Sender`]
+//! * [`Receiver`]
+//!
+//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both
+//! sender and receiver are cloneable (multi-producer) such that many threads can send
+//! simultaneously to receivers (multi-consumer).
+//!
+//! These channels come in two flavors:
+//!
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
+//!    will return a `(Sender, Receiver)` tuple where all sends will be
+//!    **asynchronous** (they never block). The channel conceptually has an
+//!    infinite buffer.
+//!
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//!    return a `(SyncSender, Receiver)` tuple where the storage for pending
+//!    messages is a pre-allocated buffer of a fixed size. All sends will be
+//!    **synchronous** by blocking until there is buffer space available. Note
+//!    that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//!    channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`send`]: Sender::send
+//!
+//! ## Disconnection
+//!
+//! The send and receive operations on channels will all return a [`Result`]
+//! indicating whether the operation succeeded or not. An unsuccessful operation
+//! is normally indicative of the other half of a channel having "hung up" by
+//! being dropped in its corresponding thread.
+//!
+//! Once half of a channel has been deallocated, most operations can no longer
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`unwrap`]: Result::unwrap
+//!
+//! # Examples
+//!
+//! Simple usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! // Create a simple streaming channel
+//! let (tx, rx) = channel();
+//! thread::spawn(move || {
+//!     tx.send(10).unwrap();
+//! });
+//! assert_eq!(rx.recv().unwrap(), 10);
+//! ```
+//!
+//! Shared usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! // Create a shared channel that can be sent along from many threads
+//! // where tx is the sending half (tx for transmission), and rx is the receiving
+//! // half (rx for receiving).
+//! let (tx, rx) = channel();
+//! for i in 0..10 {
+//!     let tx = tx.clone();
+//!     thread::spawn(move || {
+//!         tx.send(i).unwrap();
+//!     });
+//! }
+//!
+//! for _ in 0..5 {
+//!     let rx1 = rx.clone();
+//!     let rx2 = rx.clone();
+//!     thread::spawn(move || {
+//!         let j = rx1.recv().unwrap();
+//!         assert!(0 <= j && j < 10);
+//!     });
+//!     thread::spawn(move || {
+//!         let j = rx2.recv().unwrap();
+//!         assert!(0 <= j && j < 10);
+//!     });
+//! }
+//! ```
+//!
+//! Propagating panics:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::sync::mpmc::channel;
+//!
+//! // The call to recv() will return an error because the channel has already
+//! // hung up (or been deallocated)
+//! let (tx, rx) = channel::<i32>();
+//! drop(tx);
+//! assert!(rx.recv().is_err());
+//! ```
 
-// This module is not currently exposed publicly, but is used
-// as the implementation for the channels in `sync::mpsc`. The
-// implementation comes from the crossbeam-channel crate:
+// This module is used as the implementation for the channels in `sync::mpsc`.
+// The implementation comes from the crossbeam-channel crate:
 //
 // Copyright (c) 2019 The Crossbeam Project Developers
 //
@@ -46,9 +150,47 @@ use crate::fmt;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
 
-/// Creates a channel of unbounded capacity.
+/// Creates a new asynchronous channel, returning the sender/receiver halves.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available while there is at least one [`Sender`] alive (including clones).
 ///
-/// This channel has a growable buffer that can hold any number of messages at a time.
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times.
+/// The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// If the [`Receiver`] is disconnected while trying to [`send`] with the
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Spawn off an expensive computation
+/// thread::spawn(move || {
+/// #   fn expensive_computation() {}
+///     sender.send(expensive_computation()).unwrap();
+/// });
+///
+/// // Do some useful work for awhile
+///
+/// // Let's see what that answer was
+/// println!("{:?}", receiver.recv().unwrap());
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     let (s, r) = counter::new(list::Channel::new());
     let s = Sender { flavor: SenderFlavor::List(s) };
@@ -56,12 +198,50 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     (s, r)
 }
 
-/// Creates a channel of bounded capacity.
+/// Creates a new synchronous, bounded channel.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
+///
+/// This channel has an internal buffer on which messages will be queued.
+/// `bound` specifies the buffer size. When the internal buffer becomes full,
+/// future sends will *block* waiting for the buffer to open up. Note that a
+/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple
+/// times. The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`Sender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`Sender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = sync_channel(1);
 ///
-/// This channel has a buffer that can hold at most `cap` messages at a time.
+/// // this returns immediately
+/// sender.send(1).unwrap();
 ///
-/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and
-/// receive operations must appear at the same time in order to pair up and pass the message over.
+/// thread::spawn(move || {
+///     // this will block until the previous message has been received
+///     sender.send(2).unwrap();
+/// });
+///
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     if cap == 0 {
         let (s, r) = counter::new(zero::Channel::new());
@@ -76,7 +256,42 @@ pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     }
 }
 
-/// The sending side of a channel.
+/// The sending-half of Rust's synchronous [`channel`] type.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// Note: all senders (the original and its clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
+/// [`send`]: Sender::send
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+///     sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Sender<T> {
     flavor: SenderFlavor<T>,
 }
@@ -93,10 +308,14 @@ enum SenderFlavor<T> {
     Zero(counter::Sender<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Sender<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Sender<T> {}
 
 impl<T> Sender<T> {
@@ -107,6 +326,19 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will send the message only if there
     /// happens to be a receive operation on the other side of the channel at the same time.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{channel, Receiver, Sender};
+    ///
+    /// let (sender, _receiver): (Sender<i32>, Receiver<i32>) = channel();
+    ///
+    /// assert!(sender.try_send(1).is_ok());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.try_send(msg),
@@ -115,14 +347,36 @@ impl<T> Sender<T> {
         }
     }
 
-    /// Blocks the current thread until a message is sent or the channel is disconnected.
+    /// Attempts to send a value on this channel, returning it back if it could
+    /// not be sent.
     ///
-    /// If the channel is full and not disconnected, this call will block until the send operation
-    /// can proceed. If the channel becomes disconnected, this call will wake up and return an
-    /// error. The returned error contains the original message.
+    /// A successful send occurs when it is determined that the other end of
+    /// the channel has not hung up already. An unsuccessful send would be one
+    /// where the corresponding receiver has already been deallocated. Note
+    /// that a return value of [`Err`] means that the data will never be
+    /// received, but a return value of [`Ok`] does *not* mean that the data
+    /// will be received. It is possible for the corresponding receiver to
+    /// hang up immediately after this function returns [`Ok`].
     ///
-    /// If called on a zero-capacity channel, this method will wait for a receive operation to
-    /// appear on the other side of the channel.
+    /// This method will never block the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// // This send is always successful
+    /// tx.send(1).unwrap();
+    ///
+    /// // This send will fail because the receiver is gone
+    /// drop(rx);
+    /// assert!(tx.send(1).is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, None),
@@ -136,10 +390,6 @@ impl<T> Sender<T> {
     }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Sender<T> {
     /// Waits for a message to be sent into the channel, but only for a limited time.
     ///
@@ -149,6 +399,20 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::Duration;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// tx.send_timeout(1, Duration::from_millis(400)).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError<T>> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.send_deadline(msg, deadline),
@@ -165,6 +429,21 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::{Duration, Instant};
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// let t = Instant::now() + Duration::from_millis(400);
+    /// tx.send_deadline(1, t).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)),
@@ -176,6 +455,31 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    ///
+    /// let tx1 = send.clone();
+    /// let tx2 = send.clone();
+    ///
+    /// assert!(tx1.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!tx1.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_empty(),
@@ -187,6 +491,29 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(1);
+    ///
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    /// assert!(!tx1.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(tx1.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_full(),
@@ -196,6 +523,29 @@ impl<T> Sender<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.len(),
@@ -205,6 +555,29 @@ impl<T> Sender<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(3);
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.capacity(),
@@ -214,6 +587,21 @@ impl<T> Sender<T> {
     }
 
     /// Returns `true` if senders belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (tx1, _) = mpmc::channel::<i32>();
+    /// let (tx2, _) = mpmc::channel::<i32>();
+    ///
+    /// assert!(tx1.same_channel(&tx1));
+    /// assert!(!tx1.same_channel(&tx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Sender<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b,
@@ -224,6 +612,7 @@ impl<T> Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
         unsafe {
@@ -236,6 +625,7 @@ impl<T> Drop for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Sender<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -248,17 +638,216 @@ impl<T> Clone for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Sender { .. }")
     }
 }
 
-/// The receiving side of a channel.
+/// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type.
+/// Different threads can share this [`Sender`] by cloning it.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// let tx_thread = thread::spawn(move || {
+///     send.send("Hello world!").unwrap();
+///     thread::sleep(Duration::from_secs(2)); // block for two seconds
+///     send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// let (rx1, rx2) = (recv.clone(), recv.clone());
+/// let rx_thread_1 = thread::spawn(move || {
+///     println!("{}", rx1.recv().unwrap()); // Received immediately
+/// });
+/// let rx_thread_2 = thread::spawn(move || {
+///     println!("{}", rx2.recv().unwrap()); // Received after 2 seconds
+/// });
+///
+/// tx_thread.join().unwrap();
+/// rx_thread_1.join().unwrap();
+/// rx_thread_2.join().unwrap();
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Receiver<T> {
     flavor: ReceiverFlavor<T>,
 }
 
+/// An iterator over messages on a [`Receiver`], created by [`iter`].
+///
+/// This iterator will block whenever [`next`] is called,
+/// waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`iter`]: Receiver::iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct Iter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An iterator that attempts to yield all pending values for a [`Receiver`],
+/// created by [`try_iter`].
+///
+/// [`None`] will be returned when there are no pending values remaining or
+/// if the corresponding channel has hung up.
+///
+/// This iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return [`None`].
+///
+/// [`try_iter`]: Receiver::try_iter
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Nothing is in the buffer yet
+/// assert!(receiver.try_iter().next().is_none());
+/// println!("Nothing in the buffer...");
+///
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+///     sender.send(2).unwrap();
+///     sender.send(3).unwrap();
+/// });
+///
+/// println!("Going to sleep...");
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+///
+/// for x in receiver.try_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct TryIter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An owning iterator over messages on a [`Receiver`],
+/// created by [`into_iter`].
+///
+/// This iterator will block whenever [`next`]
+/// is called, waiting for a new message, and [`None`] will be
+/// returned if the corresponding channel has hung up.
+///
+/// [`into_iter`]: Receiver::into_iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.into_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct IntoIter<T> {
+    rx: Receiver<T>,
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for TryIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.try_recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> IntoIterator for &'a Receiver<T> {
+    type Item = T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> Iterator for IntoIter<T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> IntoIterator for Receiver<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;
+
+    fn into_iter(self) -> IntoIter<T> {
+        IntoIter { rx: self }
+    }
+}
+
 /// Receiver flavors.
 enum ReceiverFlavor<T> {
     /// Bounded channel based on a preallocated array.
@@ -271,20 +860,46 @@ enum ReceiverFlavor<T> {
     Zero(counter::Receiver<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Receiver<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Receiver<T> {}
 
 impl<T> Receiver<T> {
     /// Attempts to receive a message from the channel without blocking.
     ///
-    /// This method will either receive a message from the channel immediately or return an error
-    /// if the channel is empty.
+    /// This method will never block the caller in order to wait for data to
+    /// become available. Instead, this will always return immediately with a
+    /// possible option of pending data on the channel.
     ///
     /// If called on a zero-capacity channel, this method will receive a message only if there
     /// happens to be a send operation on the other side of the channel at the same time.
+    ///
+    /// This is useful for a flavor of "optimistic check" before deciding to
+    /// block on a receiver.
+    ///
+    /// Compared with [`recv`], this function has two failure cases instead of one
+    /// (one for disconnection, one for an empty buffer).
+    ///
+    /// [`recv`]: Self::recv
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{Receiver, channel};
+    ///
+    /// let (_, receiver): (_, Receiver<i32>) = channel();
+    ///
+    /// assert!(receiver.try_recv().is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_recv(&self) -> Result<T, TryRecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.try_recv(),
@@ -293,15 +908,64 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Blocks the current thread until a message is received or the channel is empty and
-    /// disconnected.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up.
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed. If the channel is empty and becomes disconnected, this call will
-    /// wake up and return an error.
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// ```
+    ///
+    /// Buffering behavior:
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    /// use std::sync::mpmc::RecvError;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    ///     drop(send);
+    /// });
+    ///
+    /// // wait for the thread to join so we ensure the sender is dropped
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// assert_eq!(Ok(2), recv.recv());
+    /// assert_eq!(Ok(3), recv.recv());
+    /// assert_eq!(Err(RecvError), recv.recv());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv(&self) -> Result<T, RecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(None),
@@ -311,14 +975,65 @@ impl<T> Receiver<T> {
         .map_err(|_| RecvError)
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if it waits more than `timeout`.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before encountering timeout:
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching timeout:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.recv_deadline(deadline),
@@ -327,14 +1042,65 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if `deadline` is reached.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent. Once a message is
+    /// sent to the corresponding [`Sender`], then this receiver will wake up
+    /// and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// let (send, recv) = mpmc::channel();
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)),
@@ -342,16 +1108,77 @@ impl<T> Receiver<T> {
             ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)),
         }
     }
+
+    /// Returns an iterator that will attempt to yield all pending values.
+    /// It will return `None` if there are no more pending values or if the
+    /// channel has hung up. The iterator will never [`panic!`] or block the
+    /// user by waiting for values.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let (sender, receiver) = channel();
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_secs(1));
+    ///     sender.send(1).unwrap();
+    ///     sender.send(2).unwrap();
+    ///     sender.send(3).unwrap();
+    /// });
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// // block for two seconds
+    /// thread::sleep(Duration::from_secs(2));
+    ///
+    /// let mut iter = receiver.try_iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn try_iter(&self) -> TryIter<'_, T> {
+        TryIter { rx: self }
+    }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Receiver<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert!(recv.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!recv.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_empty(),
@@ -363,6 +1190,28 @@ impl<T> Receiver<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(1);
+    ///
+    /// assert!(!recv.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(recv.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_full(),
@@ -372,6 +1221,28 @@ impl<T> Receiver<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert_eq!(recv.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.len(),
@@ -381,6 +1252,28 @@ impl<T> Receiver<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(3);
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.capacity(),
@@ -390,6 +1283,21 @@ impl<T> Receiver<T> {
     }
 
     /// Returns `true` if receivers belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (_, rx1) = mpmc::channel::<i32>();
+    /// let (_, rx2) = mpmc::channel::<i32>();
+    ///
+    /// assert!(rx1.same_channel(&rx1));
+    /// assert!(!rx1.same_channel(&rx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Receiver<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b,
@@ -398,8 +1306,39 @@ impl<T> Receiver<T> {
             _ => false,
         }
     }
+
+    /// Returns an iterator that will block waiting for messages, but never
+    /// [`panic!`]. It will return [`None`] when the channel has hung up.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send(1).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    /// });
+    ///
+    /// let mut iter = recv.iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn iter(&self) -> Iter<'_, T> {
+        Iter { rx: self }
+    }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
         unsafe {
@@ -412,6 +1351,7 @@ impl<T> Drop for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Receiver<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -424,6 +1364,7 @@ impl<T> Clone for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Receiver { .. }")
diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs
new file mode 100644
index 00000000000..ab14050df6c
--- /dev/null
+++ b/library/std/src/sync/mpmc/tests.rs
@@ -0,0 +1,728 @@
+use super::*;
+use crate::{env, thread};
+
+pub fn stress_factor() -> usize {
+    match env::var("RUST_TEST_STRESS") {
+        Ok(val) => val.parse().unwrap(),
+        Err(..) => 1,
+    }
+}
+
+#[test]
+fn smoke() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn drop_full() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn drop_full_shared() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    drop(tx.clone());
+    drop(tx.clone());
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn smoke_shared() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+    let tx = tx.clone();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_threads() {
+    let (tx, rx) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        for i in 0..2 {
+            tx.send(i).unwrap();
+        }
+    });
+    let t2 = thread::spawn(move || {
+        assert_eq!(rx.recv().unwrap(), 0);
+        assert_eq!(rx.recv().unwrap(), 1);
+    });
+    t1.join().unwrap();
+    t2.join().unwrap();
+}
+
+#[test]
+fn smoke_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn smoke_shared_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err())
+}
+
+#[test]
+fn smoke_shared_port_gone2() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    let tx2 = tx.clone();
+    drop(tx);
+    assert!(tx2.send(1).is_err());
+}
+
+#[test]
+fn port_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() {}
+}
+
+#[test]
+fn port_gone_concurrent_shared() {
+    let (tx, rx) = channel::<i32>();
+    let tx2 = tx.clone();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+}
+
+#[test]
+fn smoke_chan_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn smoke_chan_gone_shared() {
+    let (tx, rx) = channel::<()>();
+    let tx2 = tx.clone();
+    drop(tx);
+    drop(tx2);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn chan_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+        tx.send(1).unwrap();
+    });
+    while rx.recv().is_ok() {}
+}
+
+#[test]
+fn stress() {
+    let count = if cfg!(miri) { 100 } else { 10000 };
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..count {
+            tx.send(1).unwrap();
+        }
+    });
+    for _ in 0..count {
+        assert_eq!(rx.recv().unwrap(), 1);
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn stress_shared() {
+    const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = channel::<i32>();
+
+    let t = thread::spawn(move || {
+        for _ in 0..AMT * NTHREADS {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+        match rx.try_recv() {
+            Ok(..) => panic!(),
+            _ => {}
+        }
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+    drop(tx);
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn send_from_outside_runtime() {
+    let (tx1, rx1) = channel::<()>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        tx1.send(()).unwrap();
+        for _ in 0..40 {
+            assert_eq!(rx2.recv().unwrap(), 1);
+        }
+    });
+    rx1.recv().unwrap();
+    let t2 = thread::spawn(move || {
+        for _ in 0..40 {
+            tx2.send(1).unwrap();
+        }
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn recv_from_outside_runtime() {
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..40 {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+    });
+    for _ in 0..40 {
+        tx.send(1).unwrap();
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn no_runtime() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        assert_eq!(rx1.recv().unwrap(), 1);
+        tx2.send(2).unwrap();
+    });
+    let t2 = thread::spawn(move || {
+        tx1.send(1).unwrap();
+        assert_eq!(rx2.recv().unwrap(), 2);
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn oneshot_single_thread_close_port_first() {
+    // Simple test of closing without sending
+    let (_tx, rx) = channel::<i32>();
+    drop(rx);
+}
+
+#[test]
+fn oneshot_single_thread_close_chan_first() {
+    // Simple test of closing without sending
+    let (tx, _rx) = channel::<i32>();
+    drop(tx);
+}
+
+#[test]
+fn oneshot_single_thread_send_port_close() {
+    // Testing that the sender cleans up the payload if receiver is closed
+    let (tx, rx) = channel::<Box<i32>>();
+    drop(rx);
+    assert!(tx.send(Box::new(0)).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_recv_chan_close() {
+    // Receiving on a closed chan will panic
+    let res = thread::spawn(move || {
+        let (tx, rx) = channel::<i32>();
+        drop(tx);
+        rx.recv().unwrap();
+    })
+    .join();
+    // What is our res?
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_single_thread_send_then_recv() {
+    let (tx, rx) = channel::<Box<i32>>();
+    tx.send(Box::new(10)).unwrap();
+    assert!(*rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_open() {
+    let (tx, rx) = channel::<i32>();
+    assert!(tx.send(10).is_ok());
+    assert!(rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(10).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_open() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(10).unwrap();
+    assert!(rx.recv() == Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn oneshot_single_thread_peek_data() {
+    let (tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+    tx.send(10).unwrap();
+    assert_eq!(rx.try_recv(), Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_peek_close() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_open() {
+    let (_tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_send() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    });
+
+    tx.send(Box::new(10)).unwrap();
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_close() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        drop(tx);
+    });
+    let res = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    })
+    .join();
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_multi_thread_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        drop(tx);
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        let _ = thread::spawn(move || {
+            tx.send(1).unwrap();
+        })
+        .join();
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_recv_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        thread::spawn(move || {
+            let res = thread::spawn(move || {
+                rx.recv().unwrap();
+            })
+            .join();
+            assert!(res.is_err());
+        });
+        let _t = thread::spawn(move || {
+            thread::spawn(move || {
+                drop(tx);
+            });
+        });
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<Box<isize>>();
+        let _t = thread::spawn(move || {
+            tx.send(Box::new(10)).unwrap();
+        });
+        assert!(*rx.recv().unwrap() == 10);
+    }
+}
+
+#[test]
+fn stream_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel();
+
+        send(tx, 0);
+        recv(rx, 0);
+
+        fn send(tx: Sender<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                tx.send(Box::new(i)).unwrap();
+                send(tx, i + 1);
+            });
+        }
+
+        fn recv(rx: Receiver<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                assert!(*rx.recv().unwrap() == i);
+                recv(rx, i + 1);
+            });
+        }
+    }
+}
+
+#[test]
+fn oneshot_single_thread_recv_timeout() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn stress_recv_timeout_two_threads() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+    let timeout = Duration::from_millis(100);
+
+    thread::spawn(move || {
+        for i in 0..stress {
+            if i % 2 == 0 {
+                thread::sleep(timeout * 2);
+            }
+            tx.send(1usize).unwrap();
+        }
+    });
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(timeout) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn recv_timeout_upgrade() {
+    let (tx, rx) = channel::<()>();
+    let timeout = Duration::from_millis(1);
+    let _tx_clone = tx.clone();
+
+    let start = Instant::now();
+    assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+    assert!(Instant::now() >= start + timeout);
+}
+
+#[test]
+fn stress_recv_timeout_shared() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+
+    for i in 0..stress {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            thread::sleep(Duration::from_millis(i as u64 * 10));
+            tx.send(1usize).unwrap();
+        });
+    }
+
+    drop(tx);
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(Duration::from_millis(10)) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn very_long_recv_timeout_wont_panic() {
+    let (tx, rx) = channel::<()>();
+    let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
+    thread::sleep(Duration::from_secs(1));
+    assert!(tx.send(()).is_ok());
+    assert_eq!(join_handle.join().unwrap(), Ok(()));
+}
+
+#[test]
+fn recv_a_lot() {
+    let count = if cfg!(miri) { 1000 } else { 10000 };
+    // Regression test that we don't run out of stack in scheduler context
+    let (tx, rx) = channel();
+    for _ in 0..count {
+        tx.send(()).unwrap();
+    }
+    for _ in 0..count {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn shared_recv_timeout() {
+    let (tx, rx) = channel();
+    let total = 5;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn shared_chan_stress() {
+    let (tx, rx) = channel();
+    let total = stress_factor() + 100;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn test_nested_recv_iter() {
+    let (tx, rx) = channel::<i32>();
+    let (total_tx, total_rx) = channel::<i32>();
+
+    let _t = thread::spawn(move || {
+        let mut acc = 0;
+        for x in rx.iter() {
+            acc += x;
+        }
+        total_tx.send(acc).unwrap();
+    });
+
+    tx.send(3).unwrap();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    assert_eq!(total_rx.recv().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_iter_break() {
+    let (tx, rx) = channel::<i32>();
+    let (count_tx, count_rx) = channel();
+
+    let _t = thread::spawn(move || {
+        let mut count = 0;
+        for x in rx.iter() {
+            if count >= 3 {
+                break;
+            } else {
+                count += x;
+            }
+        }
+        count_tx.send(count).unwrap();
+    });
+
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    let _ = tx.send(2);
+    drop(tx);
+    assert_eq!(count_rx.recv().unwrap(), 4);
+}
+
+#[test]
+fn test_recv_try_iter() {
+    let (request_tx, request_rx) = channel();
+    let (response_tx, response_rx) = channel();
+
+    // Request `x`s until we have `6`.
+    let t = thread::spawn(move || {
+        let mut count = 0;
+        loop {
+            for x in response_rx.try_iter() {
+                count += x;
+                if count == 6 {
+                    return count;
+                }
+            }
+            request_tx.send(()).unwrap();
+        }
+    });
+
+    for _ in request_rx.iter() {
+        if response_tx.send(2).is_err() {
+            break;
+        }
+    }
+
+    assert_eq!(t.join().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_into_iter_owned() {
+    let mut iter = {
+        let (tx, rx) = channel::<i32>();
+        tx.send(1).unwrap();
+        tx.send(2).unwrap();
+
+        rx.into_iter()
+    };
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn test_recv_into_iter_borrowed() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    let mut iter = (&rx).into_iter();
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn try_recv_states() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<()>();
+    let (tx3, rx3) = channel::<()>();
+    let _t = thread::spawn(move || {
+        rx2.recv().unwrap();
+        tx1.send(1).unwrap();
+        tx3.send(()).unwrap();
+        rx2.recv().unwrap();
+        drop(tx1);
+        tx3.send(()).unwrap();
+    });
+
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Ok(1));
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+// This bug used to end up in a livelock inside of the Receiver destructor
+// because the internal state of the Shared packet was corrupted
+#[test]
+fn destroy_upgraded_shared_port_when_sender_still_active() {
+    let (tx, rx) = channel();
+    let (tx2, rx2) = channel();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap(); // wait on a oneshot
+        drop(rx); // destroy a shared
+        tx2.send(()).unwrap();
+    });
+    // make sure the other thread has gone to sleep
+    for _ in 0..5000 {
+        thread::yield_now();
+    }
+
+    // upgrade to a shared chan and send a message
+    let t = tx.clone();
+    drop(tx);
+    t.send(()).unwrap();
+
+    // wait for the child thread to exit before we exit
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn issue_32114() {
+    let (tx, _) = channel();
+    let _ = tx.send(123);
+    assert_eq!(tx.send(123), Err(SendError(123)));
+}
+
+#[test]
+fn issue_39364() {
+    let (tx, rx) = channel::<()>();
+    let t = thread::spawn(move || {
+        thread::sleep(Duration::from_millis(300));
+        let _ = tx.clone();
+        // Don't drop; hand back to caller.
+        tx
+    });
+
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+    let _tx = t.join().unwrap(); // delay dropping until end of test
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+}
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 26d5b9515a2..83a93a06369 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -137,10 +137,10 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod sync_tests;
 
 // MPSC channels are built as a wrapper around MPMC channels, which
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index f3de1f7bf49..fe2aca031a2 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 5a1cd7d0b8b..993df9314fc 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -3,7 +3,7 @@
 //! This primitive is meant to be used to run one-time initialization. An
 //! example use case would be for initializing an FFI library.
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::fmt;
diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs
index 1fff3273d20..5113d436c3c 100644
--- a/library/std/src/sync/once_lock/tests.rs
+++ b/library/std/src/sync/once_lock/tests.rs
@@ -9,7 +9,7 @@ fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) ->
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell() {
     static ONCE_CELL: OnceLock<i32> = OnceLock::new();
 
@@ -43,7 +43,7 @@ fn sync_once_cell_get_unchecked() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_drop() {
     static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
     struct Dropper;
@@ -81,6 +81,7 @@ fn clone() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn get_or_try_init() {
     let cell: OnceLock<String> = OnceLock::new();
     assert!(cell.get().is_none());
@@ -154,7 +155,7 @@ fn eval_once_macro() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
     static ONCE_CELL: OnceLock<String> = OnceLock::new();
 
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 39f23a14441..0140e0d2129 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use cfg_if::cfg_if;
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 143bdef736d..da2da6f9dfc 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 17b26543bd7..320712fdcc9 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 #[path = "../wasi/io.rs"]
 pub mod io;
 
-#[path = "../wasi/net.rs"]
 pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs
new file mode 100644
index 00000000000..c40eb229ba9
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/net.rs
@@ -0,0 +1,379 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use libc::{c_int, c_void, size_t};
+
+use super::fd::WasiFd;
+use crate::ffi::CStr;
+use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Shutdown, SocketAddr};
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys::unsupported;
+use crate::sys_common::net::{TcpListener, getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::{Duration, Instant};
+use crate::{cmp, mem, str};
+
+pub extern crate libc as netc;
+
+#[allow(non_camel_case_types)]
+pub type wrlen_t = size_t;
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+    T: IsMinusOne,
+    F: FnMut() -> T,
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.is_interrupted() => {}
+            other => return other,
+        }
+    }
+}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 {
+        return Ok(());
+    }
+
+    if err == netc::EAI_SYSTEM {
+        return Err(io::Error::last_os_error());
+    }
+
+    let detail = unsafe {
+        str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
+    };
+
+    Err(io::Error::new(
+        io::ErrorKind::Uncategorized,
+        &format!("failed to lookup address information: {detail}")[..],
+    ))
+}
+
+pub fn init() {}
+
+pub struct Socket(WasiFd);
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
+    }
+
+    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+        let (addr, len) = addr.into_inner();
+        cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
+        Ok(())
+    }
+
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = self.connect(addr);
+        self.set_nonblocking(false)?;
+
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS
+            Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
+            Err(e) => return Err(e),
+        }
+
+        let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
+
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::Error::ZERO_TIMEOUT);
+        }
+
+        let start = Instant::now();
+
+        loop {
+            let elapsed = start.elapsed();
+            if elapsed >= timeout {
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
+            }
+
+            let timeout = timeout - elapsed;
+            let mut timeout = timeout
+                .as_secs()
+                .saturating_mul(1_000)
+                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+            if timeout == 0 {
+                timeout = 1;
+            }
+
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
+
+            match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if !err.is_interrupted() {
+                        return Err(err);
+                    }
+                }
+                0 => {}
+                _ => {
+                    // WASI poll does not return  POLLHUP or POLLERR in revents. Check if the
+                    // connnection actually succeeded and return ok only when the socket is
+                    // ready and no errors were found.
+                    if let Some(e) = self.take_error()? {
+                        return Err(e);
+                    }
+
+                    return Ok(());
+                }
+            }
+        }
+    }
+
+    pub fn accept(
+        &self,
+        storage: *mut netc::sockaddr,
+        len: *mut netc::socklen_t,
+    ) -> io::Result<Socket> {
+        let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        unsupported()
+    }
+
+    fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
+        let ret = cvt(unsafe {
+            netc::recv(
+                self.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut c_void,
+                buf.capacity(),
+                flags,
+            )
+        })?;
+        unsafe {
+            buf.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), 0)?;
+        Ok(buf.len())
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
+        Ok(buf.len())
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.recv_with_flags(buf, 0)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    fn recv_from_with_flags(
+        &self,
+        buf: &mut [u8],
+        flags: c_int,
+    ) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+
+        let n = cvt(unsafe {
+            netc::recvfrom(
+                self.as_raw_fd(),
+                buf.as_mut_ptr() as *mut c_void,
+                buf.len(),
+                flags,
+                core::ptr::addr_of_mut!(storage) as *mut _,
+                &mut addrlen,
+            )
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, netc::MSG_PEEK)
+    }
+
+    fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::Error::ZERO_TIMEOUT);
+                }
+
+                let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX);
+                let mut timeout = netc::timeval {
+                    tv_sec: secs,
+                    tv_usec: dur.subsec_micros() as netc::suseconds_t,
+                };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+        };
+        setsockopt(self, netc::SOL_SOCKET, kind, timeout)
+    }
+
+    pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+        let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => netc::SHUT_WR,
+            Shutdown::Read => netc::SHUT_RD,
+            Shutdown::Both => netc::SHUT_RDWR,
+        };
+        cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
+        Ok(())
+    }
+
+    pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        unsupported()
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking = nonblocking as c_int;
+        cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
+    }
+
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+impl AsInner<WasiFd> for Socket {
+    #[inline]
+    fn as_inner(&self) -> &WasiFd {
+        &self.0
+    }
+}
+
+impl IntoInner<WasiFd> for Socket {
+    fn into_inner(self) -> WasiFd {
+        self.0
+    }
+}
+
+impl FromInner<WasiFd> for Socket {
+    fn from_inner(inner: WasiFd) -> Socket {
+        Socket(inner)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for Socket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
+
+impl AsInner<Socket> for TcpListener {
+    #[inline]
+    fn as_inner(&self) -> &Socket {
+        &self.socket()
+    }
+}
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index e386c955f37..6f6f282d432 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -3,7 +3,7 @@
 pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
 
 #[cfg(test)]
-#[allow(dead_code)] // not used on emscripten
+#[allow(dead_code)] // not used on emscripten and wasi
 pub mod test {
     use rand::RngCore;
 
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 1c884f107be..aa27886ff6f 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -32,7 +32,8 @@ cfg_if::cfg_if! {
         all(unix, not(target_os = "l4re")),
         windows,
         target_os = "hermit",
-        target_os = "solid_asp3"
+        target_os = "solid_asp3",
+        all(target_os = "wasi", target_env = "p2")
     ))] {
         pub mod net;
     } else {
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index f147c5fdcd1..88bf186700f 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -2,7 +2,7 @@
 
 #![unstable(feature = "thread_local_internals", issue = "none")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 #[cfg(test)]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 686f5055ac1..22d65583365 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -155,7 +155,7 @@
 // Under `test`, `__FastLocalKeyInner` seems unused.
 #![cfg_attr(test, allow(dead_code))]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::any::Any;
diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs
index 8becf713205..30f800c5aa2 100644
--- a/library/std/tests/create_dir_all_bare.rs
+++ b/library/std/tests/create_dir_all_bare.rs
@@ -1,4 +1,4 @@
-#![cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+#![cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"))))]
 
 //! Note that this test changes the current directory so
 //! should not be in the same process as other tests.
diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs
index d249eb7d50a..3e72e371ade 100644
--- a/library/std/tests/process_spawning.rs
+++ b/library/std/tests/process_spawning.rs
@@ -5,7 +5,7 @@ use std::{env, fs, process, str};
 mod common;
 
 #[test]
-#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri
+#[cfg_attr(any(miri, target_os = "wasi"), ignore)] // Process spawning not supported by Miri and wasi
 fn issue_15149() {
     // If we're the parent, copy our own binary to a new directory.
     let my_path = env::current_exe().unwrap();
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index fc9917178b2..83574176186 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -4,7 +4,7 @@ use std::thread;
 use std::time::Duration;
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 #[cfg_attr(miri, ignore)] // Miri does not like the thread leak
 fn sleep_very_long() {
     let finished = Arc::new(Mutex::new(false));
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 952db063636..efcac4f0953 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -84,9 +84,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.19"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
 dependencies = [
  "shlex",
 ]
@@ -99,9 +99,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clap"
-version = "4.5.16"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
+checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -109,9 +109,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.15"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
+checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
 dependencies = [
  "anstyle",
  "clap_lex",
@@ -119,18 +119,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.18"
+version = "4.5.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03"
+checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.13"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -161,9 +161,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
 dependencies = [
  "libc",
 ]
@@ -242,9 +242,9 @@ dependencies = [
 
 [[package]]
 name = "filetime"
-version = "0.2.24"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
 dependencies = [
  "cfg-if",
  "libc",
@@ -264,9 +264,9 @@ dependencies = [
 
 [[package]]
 name = "globset"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
+checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
 dependencies = [
  "aho-corasick",
  "bstr",
@@ -292,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "ignore"
-version = "0.4.22"
+version = "0.4.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
+checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
 dependencies = [
  "crossbeam-deque",
  "globset",
@@ -314,9 +314,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "junction"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa"
+checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16"
 dependencies = [
  "scopeguard",
  "windows-sys 0.52.0",
@@ -324,9 +324,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.157"
+version = "0.2.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
 
 [[package]]
 name = "libredox"
@@ -379,9 +379,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.3"
+version = "0.36.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
 dependencies = [
  "memchr",
 ]
@@ -398,15 +398,15 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "pretty_assertions"
-version = "1.4.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
+checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
 dependencies = [
  "diff",
  "yansi",
@@ -423,18 +423,18 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.3"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
 dependencies = [
  "bitflags",
 ]
@@ -458,9 +458,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "0.38.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
 dependencies = [
  "bitflags",
  "errno",
@@ -498,18 +498,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
 [[package]]
 name = "serde"
-version = "1.0.208"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.208"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -518,9 +518,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.125"
+version = "1.0.128"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
 dependencies = [
  "itoa",
  "memchr",
@@ -547,9 +547,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "syn"
-version = "2.0.75"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -558,9 +558,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.31.2"
+version = "0.31.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab"
+checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -571,9 +571,9 @@ dependencies = [
 
 [[package]]
 name = "tar"
-version = "0.4.41"
+version = "0.4.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909"
+checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020"
 dependencies = [
  "filetime",
  "libc",
@@ -606,9 +606,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
 
 [[package]]
 name = "version_check"
@@ -833,6 +833,6 @@ dependencies = [
 
 [[package]]
 name = "yansi"
-version = "0.5.1"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 1959d0a9662..ba505089a00 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -37,7 +37,7 @@ test = false
 # Most of the time updating these dependencies requires modifications to the
 # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
 # otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
-cc = "=1.1.19"
+cc = "=1.1.22"
 cmake = "=0.1.48"
 
 build_helper = { path = "../tools/build_helper" }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index e4011221286..30213584157 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -344,6 +344,7 @@ impl Step for Llvm {
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
             .define("LLVM_INCLUDE_TESTS", enable_tests)
+            // FIXME: remove this when minimal llvm is 19
             .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
             .define("LLVM_ENABLE_BINDINGS", "OFF")
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 77cfd404744..c35384ce3c0 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -2014,6 +2014,11 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
         }
 
+        if self.is_verbose() {
+            // This provides very useful logs especially when debugging build cache-related stuff.
+            cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
+        }
+
         cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
 
         // Downstream forks of the Rust compiler might want to use a custom libc to add support for
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 4805e598ce2..75659f46431 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1370,7 +1370,7 @@ Executed at: {executed_at}"#,
         }
 
         if target.starts_with("wasm") && target.contains("wasi") {
-            self.default_wasi_runner()
+            self.default_wasi_runner(target)
         } else {
             None
         }
@@ -1379,7 +1379,7 @@ Executed at: {executed_at}"#,
     /// When a `runner` configuration is not provided and a WASI-looking target
     /// is being tested this is consulted to prove the environment to see if
     /// there's a runtime already lying around that seems reasonable to use.
-    fn default_wasi_runner(&self) -> Option<String> {
+    fn default_wasi_runner(&self, target: TargetSelection) -> Option<String> {
         let mut finder = crate::core::sanity::Finder::new();
 
         // Look for Wasmtime, and for its default options be sure to disable
@@ -1395,6 +1395,11 @@ Executed at: {executed_at}"#,
                 // inherit the entire environment rather than just this single
                 // environment variable.
                 path.push_str(" --env RUSTC_BOOTSTRAP");
+
+                if target.contains("wasip2") {
+                    path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
+                }
+
                 return Some(path);
             }
         }
diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
index 1a367b8274b..5e785483402 100644
--- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
@@ -89,8 +89,8 @@ fn Foo() {}
 
 These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
 rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`,
-`mod`, `module`, `const`, `constant`, `fn`, `function`, `method`, `derive`, `type`, `value`,
-`macro`, `prim` or `primitive`.
+`mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`,
+`type`, `value`, `macro`, `prim` or `primitive`.
 
 You can also disambiguate for functions by adding `()` after the function name,
 or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`,
diff --git a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md
deleted file mode 100644
index 579add4a9d9..00000000000
--- a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# `default-hidden-visibility`
-
-The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/656
-
-------------------------
-
-This flag can be used to override the target's
-[`default_hidden_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_hidden_visibility)
-setting.
-Using `-Zdefault_hidden_visibility=yes` is roughly equivalent to Clang's
-[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
-cmdline flag.
diff --git a/src/doc/unstable-book/src/compiler-flags/default-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-visibility.md
new file mode 100644
index 00000000000..ad9e5d84bba
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/default-visibility.md
@@ -0,0 +1,44 @@
+# `default-visibility`
+
+The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090
+
+------------------------
+
+This flag can be used to override the target's
+[`default_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_visibility)
+setting.
+
+This option only affects building of shared objects and should have no effect on executables.
+
+Visibility an be set to one of three options:
+
+* protected
+* hidden
+* interposable
+
+## Hidden visibility
+
+Using `-Zdefault-visibility=hidden` is roughly equivalent to Clang's
+[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
+cmdline flag. Hidden symbols will not be exported from the created shared object, so cannot be
+referenced from other shared objects or from executables.
+
+## Protected visibility
+
+Using `-Zdefault-visibility=protected` will cause rust-mangled symbols to be emitted with
+"protected" visibility. This signals the compiler, the linker and the runtime linker that these
+symbols cannot be overridden by the executable or by other shared objects earlier in the load order.
+
+This will allow the compiler to emit direct references to symbols, which may improve performance. It
+also removes the need for these symbols to be resolved when a shared object built with this option
+is loaded.
+
+Using protected visibility when linking with GNU ld prior to 2.40 will result in linker errors when
+building for Linux. Other linkers such as LLD are not affected.
+
+## Interposable
+
+Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default"
+visibility. On platforms that support it, this makes it so that symbols can be interposed, which
+means that they can be overridden by symbols with the same name from the executable or by other
+shared objects earier in the load order.
diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
index ab63c986e85..8d314aa62d4 100644
--- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
@@ -4,23 +4,28 @@ The tracking issue for this feature is: [#125704](https://github.com/rust-lang/r
 
 ------------------------
 
-This option of the `--print` flag print the list of expected cfgs.
+This option of the `--print` flag print the list of all the expected cfgs.
 
-This is related to the `--check-cfg` flag which allows specifying arbitrary expected
+This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected
 names and values.
 
-This print option works similarly to `--print=cfg` (modulo check-cfg specifics):
- - *check_cfg syntax*: *output of --print=check-cfg*
- - `cfg(windows)`: `windows`
- - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"`
- - `cfg(feature, values(none(), ""))`: `feature` and `feature=""`
- - `cfg(feature, values(any()))`: `feature=any()`
- - `cfg(feature, values())`: `feature=`
- - `cfg(any())`: `any()`
- - *nothing*: `any()=any()`
+This print option works similarly to `--print=cfg` (modulo check-cfg specifics).
+
+| `--check-cfg`                     | `--print=check-cfg`         |
+|-----------------------------------|-----------------------------|
+| `cfg(foo)`                        | `foo`                       |
+| `cfg(foo, values("bar"))`         | `foo="bar"`                 |
+| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"`         |
+|                                   | *check-cfg specific syntax* |
+| `cfg(foo, values(any())`          | `foo=any()`                 |
+| `cfg(foo, values())`              | `foo=`                      |
+| `cfg(any())`                      | `any()`                     |
+| *none*                            | `any()=any()`               |
 
 To be used like this:
 
 ```bash
 rustc --print=check-cfg -Zunstable-options lib.rs
 ```
+
+[check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 43e11b6d57d..b1c429c7676 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -51,7 +51,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `reg`          | `r[0-31]`                          | `r`                  |
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
+| s390x        | `reg_addr`     | `r[1-10]`, `r[12-14]`              | `a`                  |
 | s390x        | `freg`         | `f[0-15]`                          | `f`                  |
+| s390x        | `vreg`         | `v[0-31]`                          | Only clobbers        |
+| s390x        | `areg`         | `a[2-15]`                          | Only clobbers        |
 | Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
 | Arm64EC      | `vreg`         | `v[0-15]`                          | `w`                  |
 | Arm64EC      | `vreg_low16`   | `v[0-15]`                          | `x`                  |
@@ -90,6 +93,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | s390x        | `reg`, `reg_addr`               | None           | `i8`, `i16`, `i32`, `i64`               |
 | s390x        | `freg`                          | None           | `f32`, `f64`                            |
+| s390x        | `vreg`                          | N/A            | Only clobbers                           |
+| s390x        | `areg`                          | N/A            | Only clobbers                           |
 | Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | Arm64EC      | `vreg`                          | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 
@@ -157,6 +162,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r15`                                   | This is the link register. |
 | CSKY         | `r[26-30]`                              | Reserved by its ABI.       |
 | CSKY         | `r31`                                   | This is the TLS register.  |
+| s390x        | `c[0-15]`                               | Reserved by the kernel. |
+| s390x        | `a[0-1]`                                | Reserved for system use. |
 | Arm64EC      | `xzr`                                   | This is a constant zero register which can't be modified. |
 | Arm64EC      | `x18`                                   | This is an OS-reserved register. |
 | Arm64EC      | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. |
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 08c88fc950d..d966f993104 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -117,6 +117,7 @@ fn synthesize_auto_trait_impl<'tcx>(
         name: None,
         inner: Box::new(clean::ItemInner {
             attrs: Default::default(),
+            stability: None,
             kind: clean::ImplItem(Box::new(clean::Impl {
                 safety: hir::Safety::Safe,
                 generics,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 36821294885..1f3cb4a61b8 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -87,6 +87,7 @@ pub(crate) fn synthesize_blanket_impls(
                 item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                 inner: Box::new(clean::ItemInner {
                     attrs: Default::default(),
+                    stability: None,
                     kind: clean::ImplItem(Box::new(clean::Impl {
                         safety: hir::Safety::Safe,
                         generics: clean_ty_generics(
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d3c4ef4dc90..e7f921eef7f 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -672,6 +672,7 @@ fn build_module_items(
                     item_id: ItemId::DefId(did),
                     inner: Box::new(clean::ItemInner {
                         attrs: Default::default(),
+                        stability: None,
                         kind: clean::ImportItem(clean::Import::new_simple(
                             item.ident.name,
                             clean::ImportSource {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index b9c5e8e787b..a3277e8ca92 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -6,7 +6,7 @@ use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
 use rustc_ast_pretty::pprust;
-use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince};
+use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -333,6 +333,8 @@ pub(crate) struct ItemInner {
     /// E.g., struct vs enum vs function.
     pub(crate) kind: ItemKind,
     pub(crate) attrs: Attributes,
+    /// The effective stability, filled out by the `propagate-stability` pass.
+    pub(crate) stability: Option<Stability>,
 }
 
 impl std::ops::Deref for Item {
@@ -381,46 +383,17 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 impl Item {
+    /// Returns the effective stability of the item.
+    ///
+    /// This method should only be called after the `propagate-stability` pass has been run.
     pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
-        let (mut def_id, mut stability) = if let Some(inlined) = self.inline_stmt_id {
-            let inlined_def_id = inlined.to_def_id();
-            if let Some(stability) = tcx.lookup_stability(inlined_def_id) {
-                (inlined_def_id, stability)
-            } else {
-                // For re-exports into crates without `staged_api`, reuse the original stability.
-                // This is necessary, because we always want to mark unstable items.
-                let def_id = self.def_id()?;
-                return tcx.lookup_stability(def_id);
-            }
-        } else {
-            let def_id = self.def_id()?;
-            let stability = tcx.lookup_stability(def_id)?;
-            (def_id, stability)
-        };
-
-        let StabilityLevel::Stable { mut since, allowed_through_unstable_modules: false } =
-            stability.level
-        else {
-            return Some(stability);
-        };
-
-        // If any of the item's ancestors was stabilized later or is still unstable,
-        // then report the ancestor's stability instead.
-        while let Some(parent_def_id) = tcx.opt_parent(def_id) {
-            if let Some(parent_stability) = tcx.lookup_stability(parent_def_id) {
-                match parent_stability.level {
-                    StabilityLevel::Unstable { .. } => return Some(parent_stability),
-                    StabilityLevel::Stable { since: parent_since, .. } => {
-                        if parent_since > since {
-                            stability = parent_stability;
-                            since = parent_since;
-                        }
-                    }
-                }
-            }
-            def_id = parent_def_id;
-        }
-        Some(stability)
+        let stability = self.inner.stability;
+        debug_assert!(
+            stability.is_some()
+                || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
+            "missing stability for cleaned item: {self:?}",
+        );
+        stability
     }
 
     pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
@@ -502,7 +475,7 @@ impl Item {
 
         Item {
             item_id: def_id.into(),
-            inner: Box::new(ItemInner { kind, attrs }),
+            inner: Box::new(ItemInner { kind, attrs, stability: None }),
             name,
             cfg,
             inline_stmt_id: None,
@@ -638,10 +611,7 @@ impl Item {
     }
 
     pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
-        match self.stability(tcx)?.level {
-            StabilityLevel::Stable { since, .. } => Some(since),
-            StabilityLevel::Unstable { .. } => None,
-        }
+        self.stability(tcx).and_then(|stability| stability.stable_since())
     }
 
     pub(crate) fn is_non_exhaustive(&self) -> bool {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d120e7f36eb..38276e4d20c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -436,16 +436,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
             }
 
             clean::ImportItem(ref import) => {
-                let stab_tags = if let Some(import_def_id) = import.source.did {
-                    // Just need an item with the correct def_id and attrs
-                    let import_item =
-                        clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() };
-
-                    let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
-                    stab_tags
-                } else {
-                    None
-                };
+                let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
+                    extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
+                });
 
                 w.write_str(ITEM_TABLE_ROW_OPEN);
                 let id = match import.kind {
@@ -454,7 +447,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                     }
                     clean::ImportKind::Glob => String::new(),
                 };
-                let stab_tags = stab_tags.unwrap_or_default();
                 let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() {
                     ("", "")
                 } else {
@@ -521,7 +513,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                      {docs_before}{docs}{docs_after}",
                     name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     visibility_and_hidden = visibility_and_hidden,
-                    stab_tags = extra_info_tags(myitem, item, tcx),
+                    stab_tags = extra_info_tags(tcx, myitem, item, None),
                     class = myitem.type_(),
                     unsafety_flag = unsafety_flag,
                     href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
@@ -544,9 +536,10 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
 /// Render the stability, deprecation and portability tags that are displayed in the item's summary
 /// at the module level.
 fn extra_info_tags<'a, 'tcx: 'a>(
+    tcx: TyCtxt<'tcx>,
     item: &'a clean::Item,
     parent: &'a clean::Item,
-    tcx: TyCtxt<'tcx>,
+    import_def_id: Option<DefId>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         fn tag_html<'a>(
@@ -564,18 +557,18 @@ fn extra_info_tags<'a, 'tcx: 'a>(
         }
 
         // The trailing space after each tag is to space it properly against the rest of the docs.
-        if let Some(depr) = &item.deprecation(tcx) {
+        let deprecation = import_def_id
+            .map_or_else(|| item.deprecation(tcx), |import_did| tcx.lookup_deprecation(import_did));
+        if let Some(depr) = deprecation {
             let message = if depr.is_in_effect() { "Deprecated" } else { "Deprecation planned" };
             write!(f, "{}", tag_html("deprecated", "", message))?;
         }
 
         // The "rustc_private" crates are permanently unstable so it makes no sense
         // to render "unstable" everywhere.
-        if item
-            .stability(tcx)
-            .as_ref()
-            .is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private)
-        {
+        let stability = import_def_id
+            .map_or_else(|| item.stability(tcx), |import_did| tcx.lookup_stability(import_did));
+        if stability.is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) {
             write!(f, "{}", tag_html("unstable", "", "Experimental"))?;
         }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 3367e863c6f..beac7e73c62 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -960,6 +960,13 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	display: inline-block;
 }
 
+.docblock li {
+	margin-bottom: .8em;
+}
+.docblock li p {
+	margin-bottom: .1em;
+}
+
 /* "where ..." clauses with block display are also smaller */
 div.where {
 	white-space: pre-wrap;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0d556e0a682..984b0877d8d 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1828,11 +1828,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         return;
     }
     but.onclick = () => {
-        const path = [];
-        onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => {
-            path.push(a.textContent);
-        });
-        path.push(document.querySelector("title").textContent.split(" ")[0]);
+        // Most page titles are '<Item> in <path::to::module> - Rust', except
+        // modules (which don't have the first part) and keywords/primitives
+        // (which don't have a module path)
+        const title = document.querySelector("title").textContent.replace(" - Rust", "");
+        const [item, module] = title.split(" in ");
+        const path = [item];
+        if (module !== undefined) {
+            path.unshift(module);
+        }
 
         copyContentToClipboard(path.join("::"));
         copyButtonAnimation(but);
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index e95e8762b1d..0dba16cbaf3 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -110,7 +110,6 @@ impl Res {
 
         let prefix = match kind {
             DefKind::Fn | DefKind::AssocFn => return Suggestion::Function,
-            DefKind::Field => return Suggestion::RemoveDisambiguator,
             DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro,
 
             DefKind::Macro(MacroKind::Derive) => "derive",
@@ -123,6 +122,8 @@ impl Res {
                 "const"
             }
             DefKind::Static { .. } => "static",
+            DefKind::Field => "field",
+            DefKind::Variant | DefKind::Ctor(..) => "variant",
             // Now handle things that don't have a specific disambiguator
             _ => match kind
                 .ns()
@@ -415,6 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &mut self,
         path_str: &'path str,
         ns: Namespace,
+        disambiguator: Option<Disambiguator>,
         item_id: DefId,
         module_id: DefId,
     ) -> Result<Vec<(Res, Option<DefId>)>, UnresolvedPath<'path>> {
@@ -454,7 +456,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         match resolve_primitive(path_root, TypeNS)
             .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id))
             .map(|ty_res| {
-                self.resolve_associated_item(ty_res, item_name, ns, module_id)
+                self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id)
                     .into_iter()
                     .map(|(res, def_id)| (res, Some(def_id)))
                     .collect::<Vec<_>>()
@@ -557,6 +559,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         root_res: Res,
         item_name: Symbol,
         ns: Namespace,
+        disambiguator: Option<Disambiguator>,
         module_id: DefId,
     ) -> Vec<(Res, DefId)> {
         let tcx = self.cx.tcx;
@@ -583,7 +586,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 // FIXME: if the associated item is defined directly on the type alias,
                 // it will show up on its documentation page, we should link there instead.
                 let Some(res) = self.def_id_to_res(did) else { return Vec::new() };
-                self.resolve_associated_item(res, item_name, ns, module_id)
+                self.resolve_associated_item(res, item_name, ns, disambiguator, module_id)
             }
             Res::Def(
                 def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
@@ -604,6 +607,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     }
                 }
 
+                let search_for_field = || {
+                    let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] };
+                    debug!("looking for fields named {item_name} for {did:?}");
+                    // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
+                    // NOTE: it's different from variant_field because it only resolves struct fields,
+                    // not variant fields (2 path segments, not 3).
+                    //
+                    // We need to handle struct (and union) fields in this code because
+                    // syntactically their paths are identical to associated item paths:
+                    // `module::Type::field` and `module::Type::Assoc`.
+                    //
+                    // On the other hand, variant fields can't be mistaken for associated
+                    // items because they look like this: `module::Type::Variant::field`.
+                    //
+                    // Variants themselves don't need to be handled here, even though
+                    // they also look like associated items (`module::Type::Variant`),
+                    // because they are real Rust syntax (unlike the intra-doc links
+                    // field syntax) and are handled by the compiler's resolver.
+                    let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else {
+                        unreachable!()
+                    };
+                    def.non_enum_variant()
+                        .fields
+                        .iter()
+                        .filter(|field| field.name == item_name)
+                        .map(|field| (root_res, field.did))
+                        .collect::<Vec<_>>()
+                };
+
+                if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator {
+                    return search_for_field();
+                }
+
                 // Checks if item_name belongs to `impl SomeItem`
                 let mut assoc_items: Vec<_> = tcx
                     .inherent_impls(did)
@@ -646,32 +682,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 if ns != Namespace::ValueNS {
                     return Vec::new();
                 }
-                debug!("looking for fields named {item_name} for {did:?}");
-                // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
-                // NOTE: it's different from variant_field because it only resolves struct fields,
-                // not variant fields (2 path segments, not 3).
-                //
-                // We need to handle struct (and union) fields in this code because
-                // syntactically their paths are identical to associated item paths:
-                // `module::Type::field` and `module::Type::Assoc`.
-                //
-                // On the other hand, variant fields can't be mistaken for associated
-                // items because they look like this: `module::Type::Variant::field`.
-                //
-                // Variants themselves don't need to be handled here, even though
-                // they also look like associated items (`module::Type::Variant`),
-                // because they are real Rust syntax (unlike the intra-doc links
-                // field syntax) and are handled by the compiler's resolver.
-                let def = match tcx.type_of(did).instantiate_identity().kind() {
-                    ty::Adt(def, _) if !def.is_enum() => def,
-                    _ => return Vec::new(),
-                };
-                def.non_enum_variant()
-                    .fields
-                    .iter()
-                    .filter(|field| field.name == item_name)
-                    .map(|field| (root_res, field.did))
-                    .collect::<Vec<_>>()
+
+                search_for_field()
             }
             Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
                 tcx,
@@ -1297,7 +1309,7 @@ impl LinkCollector<'_, '_> {
 
         match disambiguator.map(Disambiguator::ns) {
             Some(expected_ns) => {
-                match self.resolve(path_str, expected_ns, item_id, module_id) {
+                match self.resolve(path_str, expected_ns, disambiguator, item_id, module_id) {
                     Ok(candidates) => candidates,
                     Err(err) => {
                         // We only looked in one namespace. Try to give a better error if possible.
@@ -1306,8 +1318,9 @@ impl LinkCollector<'_, '_> {
                         let mut err = ResolutionFailure::NotResolved(err);
                         for other_ns in [TypeNS, ValueNS, MacroNS] {
                             if other_ns != expected_ns {
-                                if let Ok(&[res, ..]) =
-                                    self.resolve(path_str, other_ns, item_id, module_id).as_deref()
+                                if let Ok(&[res, ..]) = self
+                                    .resolve(path_str, other_ns, None, item_id, module_id)
+                                    .as_deref()
                                 {
                                     err = ResolutionFailure::WrongNamespace {
                                         res: full_res(self.cx.tcx, res),
@@ -1327,7 +1340,7 @@ impl LinkCollector<'_, '_> {
             None => {
                 // Try everything!
                 let mut candidate = |ns| {
-                    self.resolve(path_str, ns, item_id, module_id)
+                    self.resolve(path_str, ns, None, item_id, module_id)
                         .map_err(ResolutionFailure::NotResolved)
                 };
 
@@ -1531,6 +1544,8 @@ impl Disambiguator {
                 }),
                 "function" | "fn" | "method" => Kind(DefKind::Fn),
                 "derive" => Kind(DefKind::Macro(MacroKind::Derive)),
+                "field" => Kind(DefKind::Field),
+                "variant" => Kind(DefKind::Variant),
                 "type" => NS(Namespace::TypeNS),
                 "value" => NS(Namespace::ValueNS),
                 "macro" => NS(Namespace::MacroNS),
@@ -1569,6 +1584,8 @@ impl Disambiguator {
     fn ns(self) -> Namespace {
         match self {
             Self::Namespace(n) => n,
+            // for purposes of link resolution, fields are in the value namespace.
+            Self::Kind(DefKind::Field) => ValueNS,
             Self::Kind(k) => {
                 k.ns().expect("only DefKinds with a valid namespace can be disambiguators")
             }
@@ -1603,8 +1620,6 @@ enum Suggestion {
     Function,
     /// `m!`
     Macro,
-    /// `foo` without any disambiguator
-    RemoveDisambiguator,
 }
 
 impl Suggestion {
@@ -1613,7 +1628,6 @@ impl Suggestion {
             Self::Prefix(x) => format!("prefix with `{x}@`").into(),
             Self::Function => "add parentheses".into(),
             Self::Macro => "add an exclamation mark".into(),
-            Self::RemoveDisambiguator => "remove the disambiguator".into(),
         }
     }
 
@@ -1623,13 +1637,11 @@ impl Suggestion {
             Self::Prefix(prefix) => format!("{prefix}@{path_str}"),
             Self::Function => format!("{path_str}()"),
             Self::Macro => format!("{path_str}!"),
-            Self::RemoveDisambiguator => path_str.into(),
         }
     }
 
     fn as_help_span(
         &self,
-        path_str: &str,
         ori_link: &str,
         sp: rustc_span::Span,
     ) -> Vec<(rustc_span::Span, String)> {
@@ -1677,7 +1689,6 @@ impl Suggestion {
                 }
                 sugg
             }
-            Self::RemoveDisambiguator => vec![(sp, path_str.into())],
         }
     }
 }
@@ -1826,7 +1837,9 @@ fn resolution_failure(
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
+                            if let Ok(v_res) =
+                                collector.resolve(start, ns, None, item_id, module_id)
+                            {
                                 debug!("found partial_res={v_res:?}");
                                 if let Some(&res) = v_res.first() {
                                     *partial_res = Some(full_res(tcx, res));
@@ -2164,7 +2177,7 @@ fn suggest_disambiguator(
     };
 
     if let (Some(sp), Some(ori_link)) = (sp, ori_link) {
-        let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
+        let mut spans = suggestion.as_help_span(ori_link, sp);
         if spans.len() > 1 {
             diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect);
         } else {
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index b1dc766049d..f5b78023721 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -23,6 +23,9 @@ pub(crate) use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
 mod propagate_doc_cfg;
 pub(crate) use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
 
+mod propagate_stability;
+pub(crate) use self::propagate_stability::PROPAGATE_STABILITY;
+
 pub(crate) mod collect_intra_doc_links;
 pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
 
@@ -75,6 +78,7 @@ pub(crate) const PASSES: &[Pass] = &[
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
     PROPAGATE_DOC_CFG,
+    PROPAGATE_STABILITY,
     COLLECT_INTRA_DOC_LINKS,
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
@@ -91,6 +95,7 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
     ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
+    ConditionalPass::always(PROPAGATE_STABILITY),
     ConditionalPass::always(RUN_LINTS),
 ];
 
diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs
new file mode 100644
index 00000000000..f51e993bfa5
--- /dev/null
+++ b/src/librustdoc/passes/propagate_stability.rs
@@ -0,0 +1,72 @@
+//! Propagates stability to child items.
+//!
+//! The purpose of this pass is to make items whose parents are "more unstable"
+//! than the item itself inherit the parent's stability.
+//! For example, [`core::error::Error`] is marked as stable since 1.0.0, but the
+//! [`core::error`] module is marked as stable since 1.81.0, so we want to show
+//! [`core::error::Error`] as stable since 1.81.0 as well.
+
+use rustc_attr::{Stability, StabilityLevel};
+use rustc_hir::def_id::CRATE_DEF_ID;
+
+use crate::clean::{Crate, Item, ItemId};
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::passes::Pass;
+
+pub(crate) const PROPAGATE_STABILITY: Pass = Pass {
+    name: "propagate-stability",
+    run: propagate_stability,
+    description: "propagates stability to child items",
+};
+
+pub(crate) fn propagate_stability(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let crate_stability = cx.tcx.lookup_stability(CRATE_DEF_ID);
+    StabilityPropagator { parent_stability: crate_stability, cx }.fold_crate(cr)
+}
+
+struct StabilityPropagator<'a, 'tcx> {
+    parent_stability: Option<Stability>,
+    cx: &'a mut DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> {
+    fn fold_item(&mut self, mut item: Item) -> Option<Item> {
+        let parent_stability = self.parent_stability;
+
+        let stability = match item.item_id {
+            ItemId::DefId(def_id) => {
+                let own_stability = self.cx.tcx.lookup_stability(def_id);
+
+                // If any of the item's parents was stabilized later or is still unstable,
+                // then use the parent's stability instead.
+                if let Some(own_stab) = own_stability
+                    && let StabilityLevel::Stable {
+                        since: own_since,
+                        allowed_through_unstable_modules: false,
+                    } = own_stab.level
+                    && let Some(parent_stab) = parent_stability
+                    && (parent_stab.is_unstable()
+                        || parent_stab
+                            .stable_since()
+                            .is_some_and(|parent_since| parent_since > own_since))
+                {
+                    parent_stability
+                } else {
+                    own_stability
+                }
+            }
+            ItemId::Auto { .. } | ItemId::Blanket { .. } => {
+                // For now, we do now show stability for synthesized impls.
+                None
+            }
+        };
+
+        item.inner.stability = stability;
+        self.parent_stability = stability;
+        let item = self.fold_item_recur(item);
+        self.parent_stability = parent_stability;
+
+        Some(item)
+    }
+}
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index 91ff19ad9fc..49f4e59650e 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.4"
+wasm-component-ld = "0.5.9"
diff --git a/tests/codegen/asm-s390x-clobbers.rs b/tests/codegen/asm-s390x-clobbers.rs
new file mode 100644
index 00000000000..45f72206bdf
--- /dev/null
+++ b/tests/codegen/asm-s390x-clobbers.rs
@@ -0,0 +1,50 @@
+//@ revisions: s390x
+//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//@[s390x] needs-llvm-components: systemz
+
+#![crate_type = "rlib"]
+#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+
+// CHECK-LABEL: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @a2_clobber
+// CHECK: call void asm sideeffect "", "~{a2}"()
+#[no_mangle]
+pub unsafe fn a2_clobber() {
+    asm!("", out("a2") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @v0_clobber
+// CHECK: call void asm sideeffect "", "~{v0}"()
+#[no_mangle]
+pub unsafe fn v0_clobber() {
+    asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/default-hidden-visibility.rs b/tests/codegen/default-visibility.rs
index 2bea8f62a40..884d386ec20 100644
--- a/tests/codegen/default-hidden-visibility.rs
+++ b/tests/codegen/default-visibility.rs
@@ -1,11 +1,12 @@
-// Verifies that `Session::default_hidden_visibility` is affected when using the related cmdline
-// flag.  This is a regression test for https://github.com/rust-lang/compiler-team/issues/656.  See
+// Verifies that `Session::default_visibility` is affected when using the related cmdline
+// flag.  This is a regression test for https://github.com/rust-lang/compiler-team/issues/782.  See
 // also https://github.com/rust-lang/rust/issues/73295 and
 // https://github.com/rust-lang/rust/issues/37530.
 
-//@ revisions:DEFAULT YES NO
-//@[YES] compile-flags: -Zdefault-hidden-visibility=yes
-//@[NO]  compile-flags: -Zdefault-hidden-visibility=no
+//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE
+//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden
+//@[PROTECTED] compile-flags: -Zdefault-visibility=protected
+//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable
 
 // The test scenario is specifically about visibility of symbols exported out of dynamically linked
 // libraries.
@@ -26,6 +27,7 @@ pub static tested_symbol: [u8; 6] = *b"foobar";
 //
 //@     only-x86_64-unknown-linux-gnu
 
-// DEFAULT: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
-// YES:     @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = hidden constant
-// NO:      @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
+// HIDDEN:       @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant
+// PROTECTED:    @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant
+// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
+// DEFAULT:      @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
index 2d66566119b..8142bd83877 100644
--- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
+++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
@@ -1,6 +1,8 @@
 #![deny(rustdoc::broken_intra_doc_links)]
 //~^ NOTE lint level is defined
-pub enum S {}
+pub enum S {
+    A,
+}
 fn S() {}
 
 #[macro_export]
@@ -13,6 +15,10 @@ const c: usize = 0;
 
 trait T {}
 
+struct X {
+    y: usize,
+}
+
 /// Link to [struct@S]
 //~^ ERROR incompatible link kind for `S`
 //~| NOTE this link resolved
@@ -78,4 +84,14 @@ trait T {}
 //~^ ERROR unresolved link to `std`
 //~| NOTE this link resolves to the crate `std`
 //~| HELP to link to the crate, prefix with `mod@`
+
+/// Link to [method@X::y]
+//~^ ERROR incompatible link kind for `X::y`
+//~| NOTE this link resolved
+//~| HELP prefix with `field@`
+
+/// Link to [field@S::A]
+//~^ ERROR incompatible link kind for `S::A`
+//~| NOTE this link resolved
+//~| HELP prefix with `variant@`
 pub fn f() {}
diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
index ee35749ce7f..488120304fd 100644
--- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
+++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
@@ -1,5 +1,5 @@
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:16:14
+  --> $DIR/disambiguator-mismatch.rs:22:14
    |
 LL | /// Link to [struct@S]
    |              ^^^^^^^^ this link resolved to an enum, which is not a struct
@@ -15,7 +15,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:21:14
+  --> $DIR/disambiguator-mismatch.rs:27:14
    |
 LL | /// Link to [mod@S]
    |              ^^^^^ this link resolved to an enum, which is not a module
@@ -26,7 +26,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:26:14
+  --> $DIR/disambiguator-mismatch.rs:32:14
    |
 LL | /// Link to [union@S]
    |              ^^^^^^^ this link resolved to an enum, which is not a union
@@ -37,7 +37,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:31:14
+  --> $DIR/disambiguator-mismatch.rs:37:14
    |
 LL | /// Link to [trait@S]
    |              ^^^^^^^ this link resolved to an enum, which is not a trait
@@ -48,7 +48,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `T`
-  --> $DIR/disambiguator-mismatch.rs:36:14
+  --> $DIR/disambiguator-mismatch.rs:42:14
    |
 LL | /// Link to [struct@T]
    |              ^^^^^^^^ this link resolved to a trait, which is not a struct
@@ -59,7 +59,7 @@ LL | /// Link to [trait@T]
    |              ~~~~~~
 
 error: incompatible link kind for `m`
-  --> $DIR/disambiguator-mismatch.rs:41:14
+  --> $DIR/disambiguator-mismatch.rs:47:14
    |
 LL | /// Link to [derive@m]
    |              ^^^^^^^^ this link resolved to a macro, which is not a derive macro
@@ -71,7 +71,7 @@ LL + /// Link to [m!]
    |
 
 error: unresolved link to `m`
-  --> $DIR/disambiguator-mismatch.rs:46:14
+  --> $DIR/disambiguator-mismatch.rs:52:14
    |
 LL | /// Link to [m()]
    |              ^^^ this link resolves to the macro `m`, which is not in the value namespace
@@ -82,7 +82,7 @@ LL | /// Link to [m!()]
    |               +
 
 error: incompatible link kind for `s`
-  --> $DIR/disambiguator-mismatch.rs:52:14
+  --> $DIR/disambiguator-mismatch.rs:58:14
    |
 LL | /// Link to [const@s]
    |              ^^^^^^^ this link resolved to a static, which is not a constant
@@ -93,7 +93,7 @@ LL | /// Link to [static@s]
    |              ~~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:57:14
+  --> $DIR/disambiguator-mismatch.rs:63:14
    |
 LL | /// Link to [static@c]
    |              ^^^^^^^^ this link resolved to a constant, which is not a static
@@ -104,7 +104,7 @@ LL | /// Link to [const@c]
    |              ~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:62:14
+  --> $DIR/disambiguator-mismatch.rs:68:14
    |
 LL | /// Link to [fn@c]
    |              ^^^^ this link resolved to a constant, which is not a function
@@ -115,7 +115,7 @@ LL | /// Link to [const@c]
    |              ~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:67:14
+  --> $DIR/disambiguator-mismatch.rs:73:14
    |
 LL | /// Link to [c()]
    |              ^^^ this link resolved to a constant, which is not a function
@@ -127,7 +127,7 @@ LL + /// Link to [const@c]
    |
 
 error: incompatible link kind for `f`
-  --> $DIR/disambiguator-mismatch.rs:72:14
+  --> $DIR/disambiguator-mismatch.rs:78:14
    |
 LL | /// Link to [const@f]
    |              ^^^^^^^ this link resolved to a function, which is not a constant
@@ -139,7 +139,7 @@ LL + /// Link to [f()]
    |
 
 error: unresolved link to `std`
-  --> $DIR/disambiguator-mismatch.rs:77:14
+  --> $DIR/disambiguator-mismatch.rs:83:14
    |
 LL | /// Link to [fn@std]
    |              ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
@@ -149,5 +149,27 @@ help: to link to the crate, prefix with `mod@`
 LL | /// Link to [mod@std]
    |              ~~~~
 
-error: aborting due to 13 previous errors
+error: incompatible link kind for `X::y`
+  --> $DIR/disambiguator-mismatch.rs:88:14
+   |
+LL | /// Link to [method@X::y]
+   |              ^^^^^^^^^^^ this link resolved to a field, which is not a function
+   |
+help: to link to the field, prefix with `field@`
+   |
+LL | /// Link to [field@X::y]
+   |              ~~~~~~
+
+error: incompatible link kind for `S::A`
+  --> $DIR/disambiguator-mismatch.rs:93:14
+   |
+LL | /// Link to [field@S::A]
+   |              ^^^^^^^^^^ this link resolved to a unit variant, which is not a field
+   |
+help: to link to the unit variant, prefix with `variant@`
+   |
+LL | /// Link to [variant@S::A]
+   |              ~~~~~~~~
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/rustdoc-ui/intra-doc/field-ice.rs b/tests/rustdoc-ui/intra-doc/field-ice.rs
index c5d501e38da..1ba865b53c2 100644
--- a/tests/rustdoc-ui/intra-doc/field-ice.rs
+++ b/tests/rustdoc-ui/intra-doc/field-ice.rs
@@ -4,8 +4,8 @@
 /// [`Foo::bar`]
 /// [`Foo::bar()`]
 //~^ERROR incompatible link kind for `Foo::bar`
-//~|HELP to link to the field, remove the disambiguator
+//~|HELP to link to the field, prefix with `field@`
 //~|NOTE this link resolved to a field, which is not a function
 pub struct Foo {
-    pub bar: u8
+    pub bar: u8,
 }
diff --git a/tests/rustdoc-ui/intra-doc/field-ice.stderr b/tests/rustdoc-ui/intra-doc/field-ice.stderr
index cc0ada873af..7321c87b790 100644
--- a/tests/rustdoc-ui/intra-doc/field-ice.stderr
+++ b/tests/rustdoc-ui/intra-doc/field-ice.stderr
@@ -9,10 +9,11 @@ note: the lint level is defined here
    |
 LL | #![deny(rustdoc::broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: to link to the field, remove the disambiguator
+help: to link to the field, prefix with `field@`
+   |
+LL - /// [`Foo::bar()`]
+LL + /// [`field@Foo::bar`]
    |
-LL | /// [`Foo::bar`]
-   |       ~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
index ed89fa8391d..9cd855b69ff 100644
--- a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
+++ b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
@@ -43,10 +43,10 @@ help: to link to the associated function, add parentheses
    |
 LL | /// [`Self::IDENT()`]
    |                  ++
-help: to link to the variant, prefix with `type@`
+help: to link to the variant, prefix with `variant@`
    |
-LL | /// [`type@Self::IDENT`]
-   |       +++++
+LL | /// [`variant@Self::IDENT`]
+   |       ++++++++
 
 error: `Self::IDENT2` is both an associated constant and an associated type
   --> $DIR/issue-108653-associated-items.rs:30:7
diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout
index 1ea3dbfb59f..790e58b0df9 100644
--- a/tests/rustdoc-ui/issues/issue-91713.stdout
+++ b/tests/rustdoc-ui/issues/issue-91713.stdout
@@ -5,6 +5,7 @@ strip-aliased-non-local - strips all non-local private aliased items from the ou
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
    propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
+ propagate-stability - propagates stability to child items
 collect-intra-doc-links - resolves intra-doc links
  collect-trait-impls - retrieves trait impls for items in the crate
 calculate-doc-coverage - counts the number of items with and without documentation
@@ -19,6 +20,7 @@ strip-aliased-non-local
   strip-priv-imports  (when --document-private-items)
 collect-intra-doc-links
    propagate-doc-cfg
+ propagate-stability
            run-lints
 
 Passes run with `--show-coverage`:
diff --git a/tests/rustdoc/intra-doc/field.rs b/tests/rustdoc/intra-doc/field.rs
index ba6b320e560..e98419618e2 100644
--- a/tests/rustdoc/intra-doc/field.rs
+++ b/tests/rustdoc/intra-doc/field.rs
@@ -1,4 +1,24 @@
 //@ has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
 //@ has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//@ has field/index.html '//a[@href="struct.FieldAndMethod.html#structfield.x"]' 'x'
+//@ has field/index.html '//a[@href="enum.VariantAndMethod.html#variant.X"]' 'X'
 //! [start][std::ops::Range::start]
 //! [not_found][std::io::ErrorKind::NotFound]
+//! [x][field@crate::FieldAndMethod::x]
+//! [X][variant@crate::VariantAndMethod::X]
+
+pub struct FieldAndMethod {
+    pub x: i32,
+}
+
+impl FieldAndMethod {
+    pub fn x(&self) {}
+}
+
+pub enum VariantAndMethod {
+    X {},
+}
+
+impl VariantAndMethod {
+    fn X() {}
+}
diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs
index de855b43ba5..fc72154cad8 100644
--- a/tests/rustdoc/stability.rs
+++ b/tests/rustdoc/stability.rs
@@ -25,28 +25,61 @@ pub struct ZzStable;
 
 #[unstable(feature = "unstable", issue = "none")]
 pub mod unstable {
-    //@ !hasraw stability/unstable/struct.Foo.html '//span[@class="since"]'
+    //@ !hasraw stability/unstable/struct.StableInUnstable.html \
+    //      '//span[@class="since"]'
     //@ has - '//div[@class="stab unstable"]' 'experimental'
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub struct Foo;
+    pub struct StableInUnstable;
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub mod stable_in_unstable {
+        //@ !hasraw stability/unstable/stable_in_unstable/struct.Inner.html \
+        //      '//span[@class="since"]'
+        //@ has - '//div[@class="stab unstable"]' 'experimental'
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct Inner;
+    }
 }
 
 #[stable(feature = "rust2", since = "2.2.2")]
 pub mod stable_later {
-    //@ has stability/stable_later/struct.Bar.html '//span[@class="since"]' '2.2.2'
+    //@ has stability/stable_later/struct.StableInLater.html \
+    //      '//span[@class="since"]' '2.2.2'
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub struct Bar;
+    pub struct StableInLater;
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub mod stable_in_later {
+        //@ has stability/stable_later/stable_in_later/struct.Inner.html \
+        //      '//span[@class="since"]' '2.2.2'
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct Inner;
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod stable_earlier {
-    //@ has stability/stable_earlier/struct.Foo.html '//span[@class="since"]' '1.0.0'
+    //@ has stability/stable_earlier/struct.StableInUnstable.html \
+    //      '//span[@class="since"]' '1.0.0'
+    #[doc(inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use crate::unstable::StableInUnstable;
+
+    //@ has stability/stable_earlier/stable_in_unstable/struct.Inner.html \
+    //      '//span[@class="since"]' '1.0.0'
+    #[doc(inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use crate::unstable::stable_in_unstable;
+
+    //@ has stability/stable_earlier/struct.StableInLater.html \
+    //      '//span[@class="since"]' '1.0.0'
     #[doc(inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::unstable::Foo;
+    pub use crate::stable_later::StableInLater;
 
-    //@ has stability/stable_earlier/struct.Bar.html '//span[@class="since"]' '1.0.0'
+    //@ has stability/stable_earlier/stable_in_later/struct.Inner.html \
+    //      '//span[@class="since"]' '1.0.0'
     #[doc(inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::stable_later::Bar;
+    pub use crate::stable_later::stable_in_later;
 }
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 653c1c983e2..7726c2d52f5 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 241 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 244 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 14832e7ff43..3c99fdd3821 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 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`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `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`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
index aafc0640dd2..8c54aef36ca 100644
--- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
+++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
@@ -4,7 +4,7 @@ error: `&'static mut ()` is forbidden as the type of a const generic parameter
 LL | fn uwu_0<const N: &'static mut ()>() {}
    |                   ^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `&'static u32` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:15:19
@@ -12,7 +12,7 @@ error: `&'static u32` is forbidden as the type of a const generic parameter
 LL | fn owo_0<const N: &'static u32>() {}
    |                   ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `Meow` is forbidden as the type of a const generic parameter
 LL | fn meow_0<const N: Meow>() {}
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `&'static Meow` is forbidden as the type of a const generic parameter
 LL | fn meow_1<const N: &'static Meow>() {}
    |                    ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -56,7 +56,7 @@ error: `[Meow; 100]` is forbidden as the type of a const generic parameter
 LL | fn meow_2<const N: [Meow; 100]>() {}
    |                    ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `(Meow, u8)` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:29:20
@@ -64,7 +64,7 @@ error: `(Meow, u8)` is forbidden as the type of a const generic parameter
 LL | fn meow_3<const N: (Meow, u8)>() {}
    |                    ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `(Meow, String)` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:34:20
@@ -72,7 +72,7 @@ error: `(Meow, String)` is forbidden as the type of a const generic parameter
 LL | fn meow_4<const N: (Meow, String)>() {}
    |                    ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `String` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:38:19
@@ -80,7 +80,7 @@ error: `String` is forbidden as the type of a const generic parameter
 LL | fn nya_0<const N: String>() {}
    |                   ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `Vec<u32>` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:40:19
@@ -88,7 +88,7 @@ error: `Vec<u32>` is forbidden as the type of a const generic parameter
 LL | fn nya_1<const N: Vec<u32>>() {}
    |                   ^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.full.stderr b/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
index d6753a74f85..34510f546c8 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
@@ -5,25 +5,25 @@ LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:14:15
+  --> $DIR/const-param-elided-lifetime.rs:13:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:17:21
+  --> $DIR/const-param-elided-lifetime.rs:15:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:22:15
+  --> $DIR/const-param-elided-lifetime.rs:19:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:26:17
+  --> $DIR/const-param-elided-lifetime.rs:22:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
index 62267224738..34510f546c8 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -5,109 +5,29 @@ LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:14:15
+  --> $DIR/const-param-elided-lifetime.rs:13:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:17:21
+  --> $DIR/const-param-elided-lifetime.rs:15:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:22:15
+  --> $DIR/const-param-elided-lifetime.rs:19:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:26:17
+  --> $DIR/const-param-elided-lifetime.rs:22:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:9:19
-   |
-LL | struct A<const N: &u8>;
-   |                   ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:14:15
-   |
-LL | impl<const N: &u8> A<N> {
-   |               ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:22:15
-   |
-LL | impl<const N: &u8> B for A<N> {}
-   |               ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:26:17
-   |
-LL | fn bar<const N: &u8>() {}
-   |                 ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:17:21
-   |
-LL |     fn foo<const M: &u8>(&self) {}
-   |                     ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 10 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0637`.
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs
index e75073de98d..b1cdb6a46c5 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.rs
+++ b/tests/ui/const-generics/const-param-elided-lifetime.rs
@@ -8,23 +8,18 @@
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 trait B {}
 
 impl<const N: &u8> A<N> {
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR `&u8` is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR `&u8` is forbidden
 }
 
 impl<const N: &u8> B for A<N> {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 
 fn bar<const N: &u8>() {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 
 fn main() {}
diff --git a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
index fcc86b9ac33..18b89963267 100644
--- a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
+++ b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
@@ -20,7 +20,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                               ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -32,7 +32,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                   ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/default-ty-closure.stderr b/tests/ui/const-generics/default-ty-closure.stderr
index 9c737c1a19d..3f6ca9aea4e 100644
--- a/tests/ui/const-generics/default-ty-closure.stderr
+++ b/tests/ui/const-generics/default-ty-closure.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/float-generic.simple.stderr b/tests/ui/const-generics/float-generic.simple.stderr
index 2999bce32d6..abc5e7c5a99 100644
--- a/tests/ui/const-generics/float-generic.simple.stderr
+++ b/tests/ui/const-generics/float-generic.simple.stderr
@@ -4,7 +4,7 @@ error: `f32` is forbidden as the type of a const generic parameter
 LL | fn foo<const F: f32>() {}
    |                 ^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/fn-const-param-call.min.stderr b/tests/ui/const-generics/fn-const-param-call.min.stderr
index d37766b28c9..b5b809d2787 100644
--- a/tests/ui/const-generics/fn-const-param-call.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-call.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/fn-const-param-call.rs:15:15
@@ -12,7 +12,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/fn-const-param-infer.min.stderr b/tests/ui/const-generics/fn-const-param-infer.min.stderr
index 4da503d344a..5e08f71a267 100644
--- a/tests/ui/const-generics/fn-const-param-infer.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-infer.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0308]: mismatched types
   --> $DIR/fn-const-param-infer.rs:33:25
diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
index 1f67a5c09f1..a8b6f06ab1c 100644
--- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
@@ -22,7 +22,7 @@ error: `Config` is forbidden as the type of a const generic parameter
 LL | struct B<const CFG: Config> {
    |                     ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
index 0e40255bcf5..d822fa5894a 100644
--- a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
@@ -12,7 +12,7 @@ error: `[usize; x]` is forbidden as the type of a const generic parameter
 LL | pub struct A<const z: [usize; x]> {}
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
index 15d3c472585..45be31c7ba3 100644
--- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
@@ -66,7 +66,7 @@ error: `[[usize; v4]; v4]` is forbidden as the type of a const generic parameter
 LL |     pub struct v17<const v10: usize, const v7: v11> {
    |                                                ^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
index 46a8a975d50..4ff386c8163 100644
--- a/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
+++ b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
index 2a6d9f53317..506f7d05fa6 100644
--- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
+++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -13,7 +13,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | trait Trait<const S: &'static str> {}
    |                      ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
index ff0a1bfc0b5..86eb57355bd 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr
+++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
@@ -6,22 +6,6 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |
    = note: lifetime parameters may not be used in the type of const parameters
 
-error: `&str` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-56445-1.rs:9:25
-   |
-LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
-   |                         ^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0770`.
diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs
index 53aab40b0ad..681e0e147cf 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.rs
+++ b/tests/ui/const-generics/issues/issue-56445-1.rs
@@ -8,6 +8,5 @@ use std::marker::PhantomData;
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~| ERROR: `&str` is forbidden as the type of a const generic parameter
 
 impl Bug<'_, ""> {}
diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr
index 5205726d738..bd17d70a50b 100644
--- a/tests/ui/const-generics/issues/issue-62878.min.stderr
+++ b/tests/ui/const-generics/issues/issue-62878.min.stderr
@@ -12,7 +12,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                 ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index 101ca456cd9..f14485a4976 100644
--- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -4,7 +4,7 @@ error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68366.full.stderr b/tests/ui/const-generics/issues/issue-68366.full.stderr
index 3363a895e47..caed3c1bf3f 100644
--- a/tests/ui/const-generics/issues/issue-68366.full.stderr
+++ b/tests/ui/const-generics/issues/issue-68366.full.stderr
@@ -4,7 +4,7 @@ error: `Option<usize>` is forbidden as the type of a const generic parameter
 LL | struct Collatz<const N: Option<usize>>;
    |                         ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr
index 276f91e76dd..10b5a06682f 100644
--- a/tests/ui/const-generics/issues/issue-68366.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68366.min.stderr
@@ -13,7 +13,7 @@ error: `Option<usize>` is forbidden as the type of a const generic parameter
 LL | struct Collatz<const N: Option<usize>>;
    |                         ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68615-adt.min.stderr b/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
index 2f95eef98c0..d25b34435ed 100644
--- a/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
@@ -4,7 +4,7 @@ error: `[usize; 0]` is forbidden as the type of a const generic parameter
 LL | struct Const<const V: [usize; 0]> {}
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68615-array.min.stderr b/tests/ui/const-generics/issues/issue-68615-array.min.stderr
index 6d18f8195d2..60cbc9b4eab 100644
--- a/tests/ui/const-generics/issues/issue-68615-array.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68615-array.min.stderr
@@ -4,7 +4,7 @@ error: `[usize; 0]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const V: [usize; 0] > {}
    |                     ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-71169.min.stderr b/tests/ui/const-generics/issues/issue-71169.min.stderr
index 94d11f969ff..2ecbc337951 100644
--- a/tests/ui/const-generics/issues/issue-71169.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71169.min.stderr
@@ -12,7 +12,7 @@ error: `[u8; LEN]` is forbidden as the type of a const generic parameter
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                      ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-71381.min.stderr b/tests/ui/const-generics/issues/issue-71381.min.stderr
index e16d3b7a8a4..38d2cbe6368 100644
--- a/tests/ui/const-generics/issues/issue-71381.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71381.min.stderr
@@ -20,7 +20,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/issue-71381.rs:23:19
@@ -28,7 +28,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |         const FN: unsafe extern "C" fn(Args),
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-71382.min.stderr b/tests/ui/const-generics/issues/issue-71382.min.stderr
index 0c58b10c0b7..f70e1733a97 100644
--- a/tests/ui/const-generics/issues/issue-71382.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71382.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     fn test<const FN: fn()>(&self) {
    |                       ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-71611.min.stderr b/tests/ui/const-generics/issues/issue-71611.min.stderr
index b01936f4d25..7252bfd1d6a 100644
--- a/tests/ui/const-generics/issues/issue-71611.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71611.min.stderr
@@ -12,7 +12,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                     ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-72352.min.stderr b/tests/ui/const-generics/issues/issue-72352.min.stderr
index ede0faec7c6..17ccfa8a0da 100644
--- a/tests/ui/const-generics/issues/issue-72352.min.stderr
+++ b/tests/ui/const-generics/issues/issue-72352.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const c_char) -> usize {
    |                                          ^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-73491.min.stderr b/tests/ui/const-generics/issues/issue-73491.min.stderr
index 8fdd65894ef..2cdbeea2fd6 100644
--- a/tests/ui/const-generics/issues/issue-73491.min.stderr
+++ b/tests/ui/const-generics/issues/issue-73491.min.stderr
@@ -4,7 +4,7 @@ error: `[u32; LEN]` is forbidden as the type of a const generic parameter
 LL | fn hoge<const IN: [u32; LEN]>() {}
    |                   ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
index cba03b1cb1f..256636c0628 100644
--- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
+++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
@@ -4,7 +4,7 @@ error: `&'static [u32]` is forbidden as the type of a const generic parameter
 LL | fn a<const X: &'static [u32]>() {}
    |               ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74101.min.stderr b/tests/ui/const-generics/issues/issue-74101.min.stderr
index 236556addce..65fb51d7df9 100644
--- a/tests/ui/const-generics/issues/issue-74101.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74101.min.stderr
@@ -4,7 +4,7 @@ error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 LL | fn test<const N: [u8; 1 + 2]>() {}
    |                  ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8; 1 + 2]>;
    |                     ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74255.min.stderr b/tests/ui/const-generics/issues/issue-74255.min.stderr
index 800902860a7..3b30227a9a6 100644
--- a/tests/ui/const-generics/issues/issue-74255.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74255.min.stderr
@@ -4,7 +4,7 @@ error: `IceEnum` is forbidden as the type of a const generic parameter
 LL |     fn ice_struct_fn<const I: IceEnum>() {}
    |                               ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74950.min.stderr b/tests/ui/const-generics/issues/issue-74950.min.stderr
index 086176d9959..22537af786b 100644
--- a/tests/ui/const-generics/issues/issue-74950.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74950.min.stderr
@@ -4,7 +4,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
@@ -29,7 +29,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
@@ -42,7 +42,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
diff --git a/tests/ui/const-generics/issues/issue-75047.min.stderr b/tests/ui/const-generics/issues/issue-75047.min.stderr
index f2cc76b9bed..d78ab671820 100644
--- a/tests/ui/const-generics/issues/issue-75047.min.stderr
+++ b/tests/ui/const-generics/issues/issue-75047.min.stderr
@@ -4,7 +4,7 @@ error: `[u8; Bar::<u32>::value()]` is forbidden as the type of a const generic p
 LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr
index a956fc741f4..5e380eea81c 100644
--- a/tests/ui/const-generics/issues/issue-82956.stderr
+++ b/tests/ui/const-generics/issues/issue-82956.stderr
@@ -14,7 +14,7 @@ LL + use std::collections::btree_map::IntoIter;
    |
 LL + use std::collections::btree_set::IntoIter;
    |
-     and 8 other candidates
+     and 9 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/lifetime-in-const-param.rs b/tests/ui/const-generics/lifetime-in-const-param.rs
index be90dbb213e..ce6b52b229f 100644
--- a/tests/ui/const-generics/lifetime-in-const-param.rs
+++ b/tests/ui/const-generics/lifetime-in-const-param.rs
@@ -4,6 +4,5 @@ struct S2<'b>(&'b ());
 
 struct S<'a, const N: S2>(&'a ());
 //~^ ERROR missing lifetime specifier [E0106]
-//~| ERROR `S2<'_>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/const-generics/lifetime-in-const-param.stderr b/tests/ui/const-generics/lifetime-in-const-param.stderr
index 4096725c52a..7c9d27c1e28 100644
--- a/tests/ui/const-generics/lifetime-in-const-param.stderr
+++ b/tests/ui/const-generics/lifetime-in-const-param.stderr
@@ -4,18 +4,6 @@ error[E0106]: missing lifetime specifier
 LL | struct S<'a, const N: S2>(&'a ());
    |                       ^^ expected named lifetime parameter
 
-error: `S2<'_>` is forbidden as the type of a const generic parameter
-  --> $DIR/lifetime-in-const-param.rs:5:23
-   |
-LL | struct S<'a, const N: S2>(&'a ());
-   |                       ^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/const-generics/min_const_generics/complex-types.stderr b/tests/ui/const-generics/min_const_generics/complex-types.stderr
index 0211770f9e5..bca68982c39 100644
--- a/tests/ui/const-generics/min_const_generics/complex-types.stderr
+++ b/tests/ui/const-generics/min_const_generics/complex-types.stderr
@@ -4,7 +4,7 @@ error: `[u8; 0]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8; 0]>;
    |                     ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | struct Bar<const N: ()>;
    |                     ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `No` is forbidden as the type of a const generic parameter
 LL | struct Fez<const N: No>;
    |                     ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `&'static u8` is forbidden as the type of a const generic parameter
 LL | struct Faz<const N: &'static u8>;
    |                     ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -56,7 +56,7 @@ error: `!` is forbidden as the type of a const generic parameter
 LL | struct Fiz<const N: !>;
    |                     ^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:20:19
@@ -64,7 +64,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | enum Goo<const N: ()> { A, B }
    |                   ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -76,7 +76,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | union Boo<const N: ()> { a: () }
    |                    ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/nested-type.min.stderr b/tests/ui/const-generics/nested-type.min.stderr
index 0da2b30e3f1..8696be3faf3 100644
--- a/tests/ui/const-generics/nested-type.min.stderr
+++ b/tests/ui/const-generics/nested-type.min.stderr
@@ -29,7 +29,7 @@ LL | |
 LL | | }]>;
    | |__^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.rs b/tests/ui/const-generics/not_wf_param_in_rpitit.rs
index 5471dc9022f..eb672194340 100644
--- a/tests/ui/const-generics/not_wf_param_in_rpitit.rs
+++ b/tests/ui/const-generics/not_wf_param_in_rpitit.rs
@@ -6,7 +6,6 @@ trait Trait<const N: Trait = bar> {
     //~| ERROR: the trait `Trait` cannot be made into an object
     //~| ERROR: the trait `Trait` cannot be made into an object
     //~| ERROR: the trait `Trait` cannot be made into an object
-    //~| ERROR: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
     //~| ERROR: trait objects must include the `dyn` keyword
     async fn a() {}
 }
diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
index 82e251f1306..ade40550c73 100644
--- a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
+++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
@@ -25,7 +25,7 @@ LL | trait Trait<const N: Trait = bar> {
    |                      ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -48,7 +48,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -64,14 +64,6 @@ help: alternatively, consider constraining `a` so it does not apply to trait obj
 LL |     async fn a() where Self: Sized {}
    |                  +++++++++++++++++
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/not_wf_param_in_rpitit.rs:3:22
-   |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/not_wf_param_in_rpitit.rs:3:13
    |
@@ -79,7 +71,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -107,7 +99,7 @@ help: add `dyn` keyword before this trait
 LL | trait Trait<const N: dyn Trait = bar> {
    |                      +++
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0038, E0391, E0425, E0782.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr
index 3947d645fcb..847f1da16f6 100644
--- a/tests/ui/const-generics/opaque_types.stderr
+++ b/tests/ui/const-generics/opaque_types.stderr
@@ -74,7 +74,7 @@ error: `Foo` is forbidden as the type of a const generic parameter
 LL | fn foo<const C: Foo>() {}
    |                 ^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}`
   --> $DIR/opaque_types.rs:3:12
diff --git a/tests/ui/const-generics/projection-as-arg-const.stderr b/tests/ui/const-generics/projection-as-arg-const.stderr
index 88672bce0a7..f6e7620db7d 100644
--- a/tests/ui/const-generics/projection-as-arg-const.stderr
+++ b/tests/ui/const-generics/projection-as-arg-const.stderr
@@ -4,7 +4,7 @@ error: `<i32 as Identity>::Identity` is forbidden as the type of a const generic
 LL | pub fn foo<const X: <i32 as Identity>::Identity>() {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
index 6027dbb01cd..fca2966e3a3 100644
--- a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
@@ -4,7 +4,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using raw pointers as const generic parameters is forbidden
   --> $DIR/raw-ptr-const-param-deref.rs:13:15
@@ -12,7 +12,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
index c48eea069e0..5694b12f2d5 100644
--- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
@@ -4,7 +4,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0308]: mismatched types
   --> $DIR/raw-ptr-const-param.rs:11:40
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
index 3b2410c9894..594f8b9b79a 100644
--- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
+++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | struct ConstString<const T: &'static str>;
    |                             ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -20,7 +20,7 @@ error: `&'static [u8]` is forbidden as the type of a const generic parameter
 LL | struct ConstBytes<const T: &'static [u8]>;
    |                            ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/std/const-generics-range.min.stderr b/tests/ui/const-generics/std/const-generics-range.min.stderr
index 67f137cf1a0..fd23b9b248a 100644
--- a/tests/ui/const-generics/std/const-generics-range.min.stderr
+++ b/tests/ui/const-generics/std/const-generics-range.min.stderr
@@ -4,7 +4,7 @@ error: `std::ops::Range<usize>` is forbidden as the type of a const generic para
 LL | struct _Range<const R: std::ops::Range<usize>>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
 LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `RangeFull` is forbidden as the type of a const generic parameter
 LL | struct _RangeFull<const R: std::ops::RangeFull>;
    |                            ^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `RangeInclusive<usize>` is forbidden as the type of a const generic param
 LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -52,7 +52,7 @@ error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
 LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -64,7 +64,7 @@ error: `RangeToInclusive<usize>` is forbidden as the type of a const generic par
 LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
index cf236487cf0..911afa3391d 100644
--- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
+++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
@@ -4,7 +4,7 @@ error: `&'static ()` is forbidden as the type of a const generic parameter
 LL | struct Const<const P: &'static ()>;
    |                       ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
index 5aee282952a..8995c415863 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
@@ -12,7 +12,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | trait Get<'a, const N: &'static str> {
    |                        ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
    |                         ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/type-dependent/issue-71382.stderr b/tests/ui/const-generics/type-dependent/issue-71382.stderr
index 69fd6f1c7d5..3830b1527c3 100644
--- a/tests/ui/const-generics/type-dependent/issue-71382.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71382.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
new file mode 100644
index 00000000000..88044b0272c
--- /dev/null
+++ b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
@@ -0,0 +1,13 @@
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+
+extern "rust-intrinsic" {
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_const_stable(feature = "stable", since = "1.0.0")]
+    #[rustc_nounwind]
+    pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+}
+
+#[unstable(feature = "unstable", issue = "42")]
+#[rustc_const_stable(feature = "stable", since = "1.0.0")]
+pub const fn some_unstable_fn() {}
diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs
index d19115ede74..869a43e4018 100644
--- a/tests/ui/consts/issue-103790.rs
+++ b/tests/ui/consts/issue-103790.rs
@@ -6,6 +6,5 @@ struct S<const S: (), const S: S = { S }>;
 //~| ERROR missing generics for struct `S`
 //~| ERROR cycle detected when computing type of `S::S`
 //~| ERROR `()` is forbidden as the type of a const generic parameter
-//~| ERROR `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr
index c671f078cb5..1515fa60a5c 100644
--- a/tests/ui/consts/issue-103790.stderr
+++ b/tests/ui/consts/issue-103790.stderr
@@ -42,25 +42,13 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | struct S<const S: (), const S: S = { S }>;
    |                   ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
    |
 
-error: `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-103790.rs:4:32
-   |
-LL | struct S<const S: (), const S: S = { S }>;
-   |                                ^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0107, E0391, E0403.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs
new file mode 100644
index 00000000000..f69e8d0efe5
--- /dev/null
+++ b/tests/ui/consts/unstable-const-stable.rs
@@ -0,0 +1,14 @@
+//@ aux-build:unstable_but_const_stable.rs
+
+extern crate unstable_but_const_stable;
+use unstable_but_const_stable::*;
+
+fn main() {
+    some_unstable_fn(); //~ERROR use of unstable library feature
+    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
+}
+
+const fn const_main() {
+    some_unstable_fn(); //~ERROR use of unstable library feature
+    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
+}
diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr
new file mode 100644
index 00000000000..c4ffbbb60db
--- /dev/null
+++ b/tests/ui/consts/unstable-const-stable.stderr
@@ -0,0 +1,43 @@
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:7:5
+   |
+LL |     some_unstable_fn();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:8:14
+   |
+LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
+   |              ^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:12:5
+   |
+LL |     some_unstable_fn();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:13:14
+   |
+LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
+   |              ^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed
index f228783f88b..199068d0fd2 100644
--- a/tests/ui/drop/lint-if-let-rescope.fixed
+++ b/tests/ui/drop/lint-if-let-rescope.fixed
@@ -1,8 +1,8 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope)]
-#![allow(irrefutable_let_patterns)]
+#![feature(if_let_rescope, stmt_expr_attributes)]
+#![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
     Droppy
@@ -68,4 +68,30 @@ fn main() {
         //~| HELP: the value is now dropped here in Edition 2024
         //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
     }
+
+    #[rustfmt::skip]
+    if (match droppy().get() { Some(_value) => { true } _ => { false }}) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+        // do something
+    } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
+
+    while let Some(_value) = droppy().get() {
+        // Should not lint
+        break;
+    }
+
+    while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
 }
diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs
index 241fb897fce..4c043c0266c 100644
--- a/tests/ui/drop/lint-if-let-rescope.rs
+++ b/tests/ui/drop/lint-if-let-rescope.rs
@@ -1,8 +1,8 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope)]
-#![allow(irrefutable_let_patterns)]
+#![feature(if_let_rescope, stmt_expr_attributes)]
+#![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
     Droppy
@@ -68,4 +68,30 @@ fn main() {
         //~| HELP: the value is now dropped here in Edition 2024
         //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
     }
+
+    #[rustfmt::skip]
+    if (if let Some(_value) = droppy().get() { true } else { false }) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+        // do something
+    } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
+
+    while let Some(_value) = droppy().get() {
+        // Should not lint
+        break;
+    }
+
+    while (if let Some(_value) = droppy().get() { false } else { true }) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
 }
diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr
index 25ca3cf1ca8..ef60d141b79 100644
--- a/tests/ui/drop/lint-if-let-rescope.stderr
+++ b/tests/ui/drop/lint-if-let-rescope.stderr
@@ -131,5 +131,65 @@ help: a `match` with a single arm can preserve the drop order up to Edition 2021
 LL |     if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } {
    |                   ~~~~~              +++++++++++++++++    ++++++++
 
-error: aborting due to 5 previous errors
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:73:12
+   |
+LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
+   |            ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                               |
+   |                               this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:73:53
+   |
+LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
+   |                                                     ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     if (match droppy().get() { Some(_value) => { true } _ => { false }}) {
+   |         ~~~~~                +++++++++++++++++          ~~~~          +
+
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:79:21
+   |
+LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+   |                     ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                                        |
+   |                                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:79:62
+   |
+LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+   |                                                              ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) {
+   |                  ~~~~~                +++++++++++++++++          ~~~~          +
+
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:91:15
+   |
+LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
+   |               ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                                  |
+   |                                  this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:91:57
+   |
+LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
+   |                                                         ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
+   |            ~~~~~                +++++++++++++++++           ~~~~         +
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
index 649e936888b..18d514f8cb5 100644
--- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
+++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | struct Foo<const NAME: &'static str>;
    |                        ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
index 0a87f34f4f5..85ca2f59cb6 100644
--- a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
+++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
@@ -4,7 +4,7 @@ error: `[u8]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8]>;
    |                     ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/generic-const-items/elided-lifetimes.rs b/tests/ui/generic-const-items/elided-lifetimes.rs
index cca73e2e81e..90899de5af6 100644
--- a/tests/ui/generic-const-items/elided-lifetimes.rs
+++ b/tests/ui/generic-const-items/elided-lifetimes.rs
@@ -9,7 +9,6 @@ where
 
 const I<const S: &str>: &str = "";
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//~| ERROR `&str` is forbidden as the type of a const generic parameter
 
 const B<T: Trait<'_>>: () = (); //~ ERROR `'_` cannot be used here
 
diff --git a/tests/ui/generic-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr
index 85807a1b631..2b543d02b5d 100644
--- a/tests/ui/generic-const-items/elided-lifetimes.stderr
+++ b/tests/ui/generic-const-items/elided-lifetimes.stderr
@@ -16,27 +16,11 @@ LL | const I<const S: &str>: &str = "";
    |                  ^ explicit lifetime name needed here
 
 error[E0637]: `'_` cannot be used here
-  --> $DIR/elided-lifetimes.rs:14:18
+  --> $DIR/elided-lifetimes.rs:13:18
    |
 LL | const B<T: Trait<'_>>: () = ();
    |                  ^^ `'_` is a reserved lifetime name
 
-error: `&str` is forbidden as the type of a const generic parameter
-  --> $DIR/elided-lifetimes.rs:10:18
-   |
-LL | const I<const S: &str>: &str = "";
-   |                  ^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0637`.
diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs
new file mode 100644
index 00000000000..856f7b622d7
--- /dev/null
+++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs
@@ -0,0 +1,7 @@
+//! Regression test for #118179: `adt_const_params` feature shouldn't leak
+//! `{type error}` in error messages.
+
+struct G<T, const N: Vec<T>>(T);
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr
new file mode 100644
index 00000000000..654004571db
--- /dev/null
+++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr
@@ -0,0 +1,11 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/wfcheck_err_leak_issue_118179.rs:4:26
+   |
+LL | struct G<T, const N: Vec<T>>(T);
+   |                          ^ the type must not depend on the parameter `T`
+   |
+   = note: type parameters may not be used in the type of const parameters
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/tests/ui/issues/issue-12041.stderr b/tests/ui/issues/issue-12041.stderr
index 51061c0262e..f2c10b83383 100644
--- a/tests/ui/issues/issue-12041.stderr
+++ b/tests/ui/issues/issue-12041.stderr
@@ -4,7 +4,7 @@ error[E0382]: use of moved value: `tx`
 LL |             let tx = tx;
    |                      ^^ value moved here, in previous iteration of loop
    |
-   = note: move occurs because `tx` has type `Sender<i32>`, which does not implement the `Copy` trait
+   = note: move occurs because `tx` has type `std::sync::mpsc::Sender<i32>`, which does not implement the `Copy` trait
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs
index 0708a00d371..0e92b41ae1e 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.rs
+++ b/tests/ui/lifetimes/unusual-rib-combinations.rs
@@ -20,11 +20,9 @@ fn c<T = u8()>() {}
 // Elided lifetime in path in ConstGeneric
 fn d<const C: S>() {}
 //~^ ERROR missing lifetime specifier
-//~| ERROR `S<'_>` is forbidden as the type of a const generic parameter
 
 trait Foo<'a> {}
 struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
 //~^ ERROR the type of const parameters must not depend on other generic parameters
-//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index ebf6f6ca403..b7effdc8d61 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -5,7 +5,7 @@ LL | fn d<const C: S>() {}
    |               ^ expected named lifetime parameter
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/unusual-rib-combinations.rs:26:22
+  --> $DIR/unusual-rib-combinations.rs:25:22
    |
 LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
    |                      ^^ the type must not depend on the parameter `'a`
@@ -40,35 +40,7 @@ error[E0308]: mismatched types
 LL | fn a() -> [u8; foo()] {
    |                ^^^^^ expected `usize`, found `()`
 
-error: `S<'_>` is forbidden as the type of a const generic parameter
-  --> $DIR/unusual-rib-combinations.rs:21:15
-   |
-LL | fn d<const C: S>() {}
-   |               ^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
-  --> $DIR/unusual-rib-combinations.rs:26:21
-   |
-LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0106, E0214, E0308, E0770.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
index f027e169b42..003c6975c95 100644
--- a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
+++ b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty`
 LL |     ($wrong:t_ty) => ()
    |      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr
index 4683e5dd8f3..0d4304e2e2e 100644
--- a/tests/ui/lint/use_suggestion_json.stderr
+++ b/tests/ui/lint/use_suggestion_json.stderr
@@ -369,6 +369,29 @@ mod foo {
             }
           ],
           "label": null,
+          "suggested_replacement": "use std::sync::mpmc::Iter;
+
+",
+          "suggestion_applicability": "MaybeIncorrect",
+          "expansion": null
+        },
+        {
+          "file_name": "$DIR/use_suggestion_json.rs",
+          "byte_start": 541,
+          "byte_end": 541,
+          "line_start": 11,
+          "line_end": 11,
+          "column_start": 1,
+          "column_end": 1,
+          "is_primary": true,
+          "text": [
+            {
+              "text": "fn main() {",
+              "highlight_start": 1,
+              "highlight_end": 1
+            }
+          ],
+          "label": null,
           "suggested_replacement": "use std::sync::mpsc::Iter;
 
 ",
@@ -396,7 +419,7 @@ mod foo {
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::hash_map::Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m     and 8 other candidates\u001b[0m
+\u001b[0m     and 9 other candidates\u001b[0m
 
 "
 }
diff --git a/tests/ui/macros/expr_2021.rs b/tests/ui/macros/expr_2021.rs
new file mode 100644
index 00000000000..8a274e77533
--- /dev/null
+++ b/tests/ui/macros/expr_2021.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+//@ edition: 2015
+
+// Ensures expr_2021 fragment specifier is accepted in old editions
+
+macro_rules! my_macro {
+    ($x:expr_2021) => {
+        println!("Hello, {}!", $x);
+    };
+}
+
+fn main() {
+    my_macro!("world");
+}
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
index 1becd8a92d6..061a4b98033 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
@@ -1,8 +1,6 @@
 //@ run-rustfix
 //@ check-pass
 //@ compile-flags: --edition=2021
-#![allow(incomplete_features)]
-#![feature(expr_fragment_specifier_2024)]
 #![warn(edition_2024_expr_fragment_specifier)]
 
 macro_rules! m {
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
index ec0b86d2c23..cd9cd965fad 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.rs
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
@@ -1,8 +1,6 @@
 //@ run-rustfix
 //@ check-pass
 //@ compile-flags: --edition=2021
-#![allow(incomplete_features)]
-#![feature(expr_fragment_specifier_2024)]
 #![warn(edition_2024_expr_fragment_specifier)]
 
 macro_rules! m {
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
index e8a44fed322..fe1fd4a26a0 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
@@ -1,5 +1,5 @@
 warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
-  --> $DIR/expr_2021_cargo_fix_edition.rs:9:9
+  --> $DIR/expr_2021_cargo_fix_edition.rs:7:9
    |
 LL |     ($e:expr) => {
    |         ^^^^
@@ -7,7 +7,7 @@ LL |     ($e:expr) => {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
 note: the lint level is defined here
-  --> $DIR/expr_2021_cargo_fix_edition.rs:6:9
+  --> $DIR/expr_2021_cargo_fix_edition.rs:4:9
    |
 LL | #![warn(edition_2024_expr_fragment_specifier)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     ($e:expr_2021) => {
    |         ~~~~~~~~~
 
 warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
-  --> $DIR/expr_2021_cargo_fix_edition.rs:13:11
+  --> $DIR/expr_2021_cargo_fix_edition.rs:11:11
    |
 LL |     ($($i:expr)*) => { };
    |           ^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
index b55ae62030c..22d662aaaf2 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:26:12
+  --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,13 +8,13 @@ LL |     m2021!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2021_inline_const.rs:10:6
+  --> $DIR/expr_2021_inline_const.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:27:12
+  --> $DIR/expr_2021_inline_const.rs:24:12
    |
 LL | macro_rules! m2024 {
    | ------------------ when calling this macro
@@ -23,7 +23,7 @@ LL |     m2024!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr`
-  --> $DIR/expr_2021_inline_const.rs:16:6
+  --> $DIR/expr_2021_inline_const.rs:13:6
    |
 LL |     ($e:expr) => {
    |      ^^^^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
index 285db53d6c8..2555e4f757a 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:26:12
+  --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,7 +8,7 @@ LL |     m2021!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2021_inline_const.rs:10:6
+  --> $DIR/expr_2021_inline_const.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index 06b74a466d6..39a542fe4d9 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -3,9 +3,6 @@
 //@[edi2021]compile-flags: --edition=2021
 
 // This test ensures that the inline const match only on edition 2024
-#![feature(expr_fragment_specifier_2024)]
-#![allow(incomplete_features)]
-
 macro_rules! m2021 {
     ($e:expr_2021) => {
         $e
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
index 335b3f61343..34df20a69ef 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:22:12
+  --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,13 +8,13 @@ LL |     m2021!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2024_underscore_expr.rs:10:6
+  --> $DIR/expr_2024_underscore_expr.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:23:12
+  --> $DIR/expr_2024_underscore_expr.rs:20:12
    |
 LL | macro_rules! m2024 {
    | ------------------ when calling this macro
@@ -23,7 +23,7 @@ LL |     m2024!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr`
-  --> $DIR/expr_2024_underscore_expr.rs:16:6
+  --> $DIR/expr_2024_underscore_expr.rs:13:6
    |
 LL |     ($e:expr) => {
    |      ^^^^^^^
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
index 9e49f66a89a..372c5d8637c 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:22:12
+  --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,7 +8,7 @@ LL |     m2021!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2024_underscore_expr.rs:10:6
+  --> $DIR/expr_2024_underscore_expr.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs
index b2129bf154f..86e31374506 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.rs
+++ b/tests/ui/macros/expr_2024_underscore_expr.rs
@@ -3,9 +3,6 @@
 //@[edi2021]compile-flags: --edition=2021
 // This test ensures that the `_` tok is considered an
 // expression on edition 2024.
-#![feature(expr_fragment_specifier_2024)]
-#![allow(incomplete_features)]
-
 macro_rules! m2021 {
     ($e:expr_2021) => {
         $e = 1;
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
deleted file mode 100644
index 5a737b29821..00000000000
--- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@  compile-flags: --edition=2024 -Z unstable-options
-
-macro_rules! m {
-    ($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
-        $e
-    };
-}
-
-fn main() {
-    m!(());
-}
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
deleted file mode 100644
index 273a93877ce..00000000000
--- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: fragment specifier `expr_2021` is unstable
-  --> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
-   |
-LL |     ($e:expr_2021) => {
-   |      ^^^^^^^^^^^^
-   |
-   = note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
-   = help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/invalid-fragment-specifier.stderr b/tests/ui/macros/invalid-fragment-specifier.stderr
index 7516dbc3a08..a51ea619b36 100644
--- a/tests/ui/macros/invalid-fragment-specifier.stderr
+++ b/tests/ui/macros/invalid-fragment-specifier.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `id`
 LL |     ($wrong:id) => {};
    |      ^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: invalid fragment specifier `r#if`
   --> $DIR/invalid-fragment-specifier.rs:7:6
@@ -12,7 +12,7 @@ error: invalid fragment specifier `r#if`
 LL |     ($wrong:r#if) => {};
    |      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/macros/issue-21356.stderr b/tests/ui/macros/issue-21356.stderr
index dd09da6df4f..5ff92642514 100644
--- a/tests/ui/macros/issue-21356.stderr
+++ b/tests/ui/macros/issue-21356.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty`
 LL | macro_rules! test { ($wrong:t_ty ..) => () }
    |                      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.e2024.stderr
index 3afa069c170..0dc48e0c7b2 100644
--- a/tests/ui/macros/macro-missing-fragment.e2024.stderr
+++ b/tests/ui/macros/macro-missing-fragment.e2024.stderr
@@ -5,7 +5,7 @@ LL |     ( $( any_token $field_rust_type )* ) => {};
    |                    ^^^^^^^^^^^^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $( any_token $field_rust_type:spec )* ) => {};
@@ -18,7 +18,7 @@ LL |     ( $name ) => {};
    |       ^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $name:spec ) => {};
@@ -31,7 +31,7 @@ LL |     ( $name ) => {};
    |       ^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $name:spec ) => {};
diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
index 3eec1208b89..9a5b92f5032 100644
--- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
+++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
@@ -6,7 +6,6 @@
 // This test captures the behavior of macro-generating-macros with fragment
 // specifiers across edition boundaries.
 
-#![feature(expr_fragment_specifier_2024)]
 #![feature(macro_metavar_expr)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
index 8c814295de4..8e12b40381f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
@@ -22,7 +22,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | pub struct Quantity<S, const D: Dimension>(S);
    |                                 ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
    |               ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -52,7 +52,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
    |                     ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
index 7094ee8c67c..8df76b296ac 100644
--- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
+++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
@@ -4,7 +4,7 @@ error: `<i32 as Trait>::Type` is forbidden as the type of a const generic parame
 LL | struct Wrapper<const C: <i32 as Trait>::Type> {}
    |                         ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: the constant `C` is not of type `<i32 as Trait>::Type`
   --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:22
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index e0cbee88aa1..377dfc8b529 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -10,7 +10,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
@@ -18,7 +18,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
index 7f793e1269f..c4c070e49fd 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
@@ -1,21 +1,22 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@ check-pass
+//@ build-pass
 
-// We should be able to instantiate a binder during trait upcasting.
-// This test could be `check-pass`, but we should make sure that we
-// do so in both trait solvers.
+// Check that we are able to instantiate a binder during trait upcasting,
+// and that it doesn't cause any issues with codegen either.
 
 #![feature(trait_upcasting)]
 
 trait Supertrait<'a, 'b> {}
 trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
 
-impl<'a> Supertrait<'a, 'a> for () {}
-impl<'a> Subtrait<'a, 'a> for () {}
+impl Supertrait<'_, '_> for () {}
+impl Subtrait<'_, '_> for () {}
 fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
     x
 }
 
-fn main() {}
+fn main() {
+    ok(&());
+}
diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
index 3b6999cabc4..b7999a695e7 100644
--- a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
+++ b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
@@ -4,7 +4,7 @@ error: `Bar` is forbidden as the type of a const generic parameter
 LL | async fn test<const N: crate::Bar>() {
    |                        ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
index 55a5a3d2000..b526ab49d8d 100644
--- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
+++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
@@ -45,7 +45,7 @@ error: `Bar` is forbidden as the type of a const generic parameter
 LL | async fn test<const N: crate::Bar>() {
    |                        ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr
index 0479f134a38..742096f3861 100644
--- a/tests/ui/typeck/ice-unexpected-region-123863.stderr
+++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | const fn concat_strs<const A: &'static str>() -> &'static str {
    |                               ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -20,7 +20,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL |     struct Inner<const A: &'static str>;
    |                           ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
index 3f43fbfc0cf..53363319ba0 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
@@ -4,7 +4,6 @@ trait Trait<const N: Trait = bar> {
     //~| ERROR the trait `Trait` cannot be made into an object
     //~| ERROR the trait `Trait` cannot be made into an object
     //~| ERROR the trait `Trait` cannot be made into an object
-    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
     //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
     //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
@@ -15,7 +14,6 @@ trait Trait<const N: Trait = bar> {
         //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
         //~| ERROR associated item referring to unboxed trait object for its own trait
         //~| ERROR the trait `Trait` cannot be made into an object
-        //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
         //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
         //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
         //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
index 6b309c223af..fefb788fac7 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -1,5 +1,5 @@
 error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:18
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:18
    |
 LL | trait Trait<const N: Trait = bar> {
    |                   - first use of `N`
@@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> {
    |                              ^^^ not found in this scope
 
 error[E0423]: expected value, found builtin type `u32`
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:29
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:29
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                             ^^^ not a value
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:25:9
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:23:9
    |
 LL |         bar
    |         ^^^ not found in this scope
@@ -54,13 +54,13 @@ LL | trait Trait<const N: Trait = bar> {
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:12
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:12
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |            ^^^^^^^^^^^^^^^^^^^^
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^
@@ -73,7 +73,7 @@ LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
    |                     +++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                                            ^^^^^
@@ -106,7 +106,7 @@ LL | trait Trait<const N: Trait = bar> {
    |                      ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -122,7 +122,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -131,16 +131,8 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |        ^^^ ...because method `fnc` has generic type parameters
    = help: consider moving `fnc` to another trait
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
-   |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- in this trait
@@ -154,7 +146,7 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Self {
    |                                            ~~~~
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^
@@ -168,13 +160,13 @@ LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
    |                     +++
 
 error[E0038]: the trait `Trait` cannot be made into an object
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -190,7 +182,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -200,15 +192,7 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    = help: consider moving `fnc` to another trait
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                     ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
-error: aborting due to 13 previous errors; 5 warnings emitted
+error: aborting due to 11 previous errors; 5 warnings emitted
 
 Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
index d2b0e2d92e0..f8905437c6e 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
@@ -73,7 +73,7 @@ error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic para
 LL | trait Foo<const N: Bar<2>> {
    |                    ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11
@@ -104,7 +104,7 @@ error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic para
 LL | trait Bar<const M: Foo<2>> {}
    |                    ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 5 previous errors; 2 warnings emitted