about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-05 13:23:56 +0000
committerbors <bors@rust-lang.org>2024-02-05 13:23:56 +0000
commit86eaa892c098f79ff76fd24178caffa1eda86be2 (patch)
treeff35353ce11549191a14d4e7b1cda713edc1a0a3
parent8c0b4f67c9b4bf477df38c16669fd576d46a2b3d (diff)
parentdc0b1f961a42e5200831cea9f34973320069620f (diff)
downloadrust-86eaa892c098f79ff76fd24178caffa1eda86be2.tar.gz
rust-86eaa892c098f79ff76fd24178caffa1eda86be2.zip
Auto merge of #120671 - matthiaskrgr:rollup-spjnpno, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #113833 (`std::error::Error` -> Trait Implementations: lifetimes consistency improvement)
 - #115386 (PartialEq, PartialOrd: update and synchronize handling of transitive chains)
 - #116284 (make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern)
 - #118960 (Add LocalWaker and ContextBuilder types to core, and LocalWake trait to alloc.)
 - #120384 (Use `<T, U>` for array/slice equality `impl`s)
 - #120518 (riscv only supports split_debuginfo=off for now)
 - #120657 (Remove unused struct)
 - #120661 (target: default to the medium code model on LoongArch targets)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_lint/src/lib.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs50
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs71
-rw-r--r--compiler/rustc_mir_build/messages.ftl6
-rw-r--r--compiler/rustc_mir_build/src/errors.rs11
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs29
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs5
-rw-r--r--library/alloc/src/boxed.rs16
-rw-r--r--library/alloc/src/lib.rs3
-rw-r--r--library/alloc/src/task.rs185
-rw-r--r--library/core/src/array/equality.rs64
-rw-r--r--library/core/src/cmp.rs60
-rw-r--r--library/core/src/slice/cmp.rs8
-rw-r--r--library/core/src/task/mod.rs2
-rw-r--r--library/core/src/task/wake.rs388
-rw-r--r--library/std/src/sys/pal/sgx/net.rs3
-rw-r--r--library/std/src/sys/pal/teeos/net.rs3
-rw-r--r--library/std/src/sys/pal/xous/net/mod.rs3
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs16
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr16
-rw-r--r--tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs7
-rw-r--r--tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr6
-rw-r--r--tests/ui/array-slice-vec/vec-matching-autoslice.rs1
-rw-r--r--tests/ui/binding/match-range.rs1
-rw-r--r--tests/ui/consts/too_generic_eval_ice.stderr12
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs1
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr136
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs1
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs1
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr26
-rw-r--r--tests/ui/lint/issue-86600-lint-twice.rs15
-rw-r--r--tests/ui/lint/issue-86600-lint-twice.stderr12
-rw-r--r--tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs16
-rw-r--r--tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr8
-rw-r--r--tests/ui/match/issue-41255.rs50
-rw-r--r--tests/ui/match/issue-41255.stderr115
-rw-r--r--tests/ui/match/match-float.rs11
-rw-r--r--tests/ui/parser/issues/issue-7222.rs1
-rw-r--r--tests/ui/pattern/usefulness/floats.rs1
-rw-r--r--tests/ui/pattern/usefulness/floats.stderr18
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match.rs2
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-match.stderr20
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs41
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr91
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs21
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr25
-rw-r--r--tests/ui/union/union-pat-refutability.rs1
55 files changed, 1010 insertions, 604 deletions
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 1d9ce10bcaf..0a15671e686 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -516,6 +516,10 @@ fn register_builtins(store: &mut LintStore) {
         "converted into hard error, see PR #118649 \
          <https://github.com/rust-lang/rust/pull/118649> for more information",
     );
+    store.register_removed(
+        "illegal_floating_point_literal_pattern",
+        "no longer a warning, float patterns behave the same as `==`",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e6d837ecd92..07c0e75a71c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -45,7 +45,6 @@ declare_lint_pass! {
         FUZZY_PROVENANCE_CASTS,
         HIDDEN_GLOB_REEXPORTS,
         ILL_FORMED_ATTRIBUTE_INPUT,
-        ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
         INCOMPLETE_INCLUDE,
         INDIRECT_STRUCTURAL_MATCH,
         INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
@@ -1874,55 +1873,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `illegal_floating_point_literal_pattern` lint detects
-    /// floating-point literals used in patterns.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// let x = 42.0;
-    ///
-    /// match x {
-    ///     5.0 => {}
-    ///     _ => {}
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Previous versions of the compiler accepted floating-point literals in
-    /// patterns, but it was later determined this was a mistake. The
-    /// semantics of comparing floating-point values may not be clear in a
-    /// pattern when contrasted with "structural equality". Typically you can
-    /// work around this by using a [match guard], such as:
-    ///
-    /// ```rust
-    /// # let x = 42.0;
-    ///
-    /// match x {
-    ///     y if y == 5.0 => {}
-    ///     _ => {}
-    /// }
-    /// ```
-    ///
-    /// This is a [future-incompatible] lint to transition this to a hard
-    /// error in the future. See [issue #41620] for more details.
-    ///
-    /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
-    /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-    Warn,
-    "floating-point literals cannot be used in patterns",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
-    };
-}
-
-declare_lint! {
     /// The `unstable_name_collisions` lint detects that you have used a name
     /// that the standard library plans to add in the future.
     ///
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 5ecff04f3ae..e937c17c8ac 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -418,8 +418,8 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
 
     #[inline]
     pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
-        // Going through `to_uint` to check size and truncation.
-        Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?))
+        // Going through `to_bits` to check size and truncation.
+        Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index f7c33960fdd..515d564e81d 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -249,11 +249,6 @@ impl ScalarInt {
         }
     }
 
-    #[inline]
-    pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
-        Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
-    }
-
     /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
     /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
     /// `ScalarInt`s size in that case.
@@ -262,24 +257,12 @@ impl ScalarInt {
         self.to_bits(size)
     }
 
-    // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt`
-    // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size`
-    // value of the `ScalarInt` in that case.
-    #[inline]
-    pub fn try_to_bool(self) -> Result<bool, Size> {
-        match self.try_to_u8()? {
-            0 => Ok(false),
-            1 => Ok(true),
-            _ => Err(self.size()),
-        }
-    }
-
     // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
     // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
     // that case.
     #[inline]
     pub fn try_to_u8(self) -> Result<u8, Size> {
-        self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
+        self.try_to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
@@ -287,7 +270,7 @@ impl ScalarInt {
     /// that case.
     #[inline]
     pub fn try_to_u16(self) -> Result<u16, Size> {
-        self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
+        self.try_to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
@@ -295,7 +278,7 @@ impl ScalarInt {
     /// that case.
     #[inline]
     pub fn try_to_u32(self) -> Result<u32, Size> {
-        self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
+        self.try_to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
@@ -303,7 +286,7 @@ impl ScalarInt {
     /// that case.
     #[inline]
     pub fn try_to_u64(self) -> Result<u64, Size> {
-        self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
+        self.try_to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
     }
 
     /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
@@ -311,7 +294,24 @@ impl ScalarInt {
     /// that case.
     #[inline]
     pub fn try_to_u128(self) -> Result<u128, Size> {
-        self.to_bits(Size::from_bits(128))
+        self.try_to_uint(Size::from_bits(128))
+    }
+
+    #[inline]
+    pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
+        self.try_to_uint(tcx.data_layout.pointer_size).map(|v| u64::try_from(v).unwrap())
+    }
+
+    // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt`
+    // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size`
+    // value of the `ScalarInt` in that case.
+    #[inline]
+    pub fn try_to_bool(self) -> Result<bool, Size> {
+        match self.try_to_u8()? {
+            0 => Ok(false),
+            1 => Ok(true),
+            _ => Err(self.size()),
+        }
     }
 
     /// Tries to convert the `ScalarInt` to a signed integer of the given size.
@@ -357,6 +357,27 @@ impl ScalarInt {
     pub fn try_to_i128(self) -> Result<i128, Size> {
         self.try_to_int(Size::from_bits(128))
     }
+
+    #[inline]
+    pub fn try_to_target_isize(&self, tcx: TyCtxt<'_>) -> Result<i64, Size> {
+        self.try_to_int(tcx.data_layout.pointer_size).map(|v| i64::try_from(v).unwrap())
+    }
+
+    #[inline]
+    pub fn try_to_float<F: Float>(self) -> Result<F, Size> {
+        // Going through `to_uint` to check size and truncation.
+        Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
+    }
+
+    #[inline]
+    pub fn try_to_f32(self) -> Result<Single, Size> {
+        self.try_to_float()
+    }
+
+    #[inline]
+    pub fn try_to_f64(self) -> Result<Double, Size> {
+        self.try_to_float()
+    }
 }
 
 macro_rules! from {
@@ -399,11 +420,7 @@ impl TryFrom<ScalarInt> for bool {
     type Error = Size;
     #[inline]
     fn try_from(int: ScalarInt) -> Result<Self, Size> {
-        int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
-            0 => Ok(false),
-            1 => Ok(true),
-            _ => Err(Size::from_bytes(1)),
-        })
+        int.try_to_bool()
     }
 }
 
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 9631b72f20c..8a6ccdb8578 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -107,8 +107,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
     .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
     .label = use of extern static
 
-mir_build_float_pattern = floating-point types cannot be used in patterns
-
 mir_build_indirect_structural_match =
     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
 
@@ -232,6 +230,10 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
     .note = mutating layout constrained fields cannot statically be checked for valid values
     .label = mutation of layout constrained field
 
+mir_build_nan_pattern = cannot use NaN in patterns
+    .note = NaNs compare inequal to everything, even themselves, so this pattern would never match
+    .help = try using the `is_nan` method instead
+
 mir_build_non_const_path = runtime values cannot be referenced in patterns
 
 mir_build_non_empty_never_pattern =
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 3c1ba26a503..232b6033946 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -780,9 +780,14 @@ pub struct UnsizedPattern<'tcx> {
     pub non_sm_ty: Ty<'tcx>,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(mir_build_float_pattern)]
-pub struct FloatPattern;
+#[derive(Diagnostic)]
+#[diag(mir_build_nan_pattern)]
+#[note]
+#[help]
+pub struct NaNPattern {
+    #[primary_span]
+    pub span: Span,
+}
 
 #[derive(LintDiagnostic)]
 #[diag(mir_build_pointer_pattern)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 22305f03a76..9d3a9bf6745 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,3 +1,4 @@
+use rustc_apfloat::Float;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
@@ -16,7 +17,7 @@ use std::cell::Cell;
 
 use super::PatCtxt;
 use crate::errors::{
-    FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
+    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch,
     NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
@@ -317,16 +318,6 @@ impl<'tcx> ConstToPat<'tcx> {
         let param_env = self.param_env;
 
         let kind = match ty.kind() {
-            ty::Float(_) => {
-                self.saw_const_match_lint.set(true);
-                tcx.emit_node_span_lint(
-                    lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-                    id,
-                    span,
-                    FloatPattern,
-                );
-                return Err(FallbackToOpaqueConst);
-            }
             // If the type is not structurally comparable, just emit the constant directly,
             // causing the pattern match code to treat it opaquely.
             // FIXME: This code doesn't emit errors itself, the caller emits the errors.
@@ -486,6 +477,22 @@ impl<'tcx> ConstToPat<'tcx> {
                     }
                 }
             },
+            ty::Float(flt) => {
+                let v = cv.unwrap_leaf();
+                let is_nan = match flt {
+                    ty::FloatTy::F32 => v.try_to_f32().unwrap().is_nan(),
+                    ty::FloatTy::F64 => v.try_to_f64().unwrap().is_nan(),
+                };
+                if is_nan {
+                    // NaNs are not ever equal to anything so they make no sense as patterns.
+                    // Also see <https://github.com/rust-lang/rfcs/pull/3535>.
+                    let e = tcx.dcx().emit_err(NaNPattern { span });
+                    self.saw_const_match_error.set(Some(e));
+                    return Err(FallbackToOpaqueConst);
+                } else {
+                    PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
+                }
+            }
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
                 // The raw pointers we see here have been "vetted" by valtree construction to be
                 // just integers, so we simply allow them.
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index 0f05e7c475a..cb24e740c86 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{base, Target, TargetOptions};
+use crate::spec::{base, CodeModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -7,6 +7,7 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
         arch: "loongarch64".into(),
         options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
             cpu: "generic".into(),
             features: "+f,+d".into(),
             llvm_abiname: "lp64d".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index 3b1ea8e206f..f448017a2a5 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(64),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            code_model: Some(CodeModel::Small),
+            code_model: Some(CodeModel::Medium),
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
index ab9300ef9c7..d636c9599a7 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(64),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            code_model: Some(CodeModel::Small),
+            code_model: Some(CodeModel::Medium),
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
index 06e8f183763..0be32cbd771 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{base, CodeModel, Target, TargetOptions};
+use std::borrow::Cow;
+
+use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -12,6 +14,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".into(),
             llvm_abiname: "ilp32d".into(),
             max_atomic_width: Some(32),
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             ..base::linux_gnu::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
index 722703d2384..cfa9990dac9 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
@@ -1,4 +1,6 @@
-use crate::spec::{base, CodeModel, Target, TargetOptions};
+use std::borrow::Cow;
+
+use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -12,6 +14,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".into(),
             llvm_abiname: "ilp32d".into(),
             max_atomic_width: Some(32),
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             ..base::linux_musl::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
index 40e447dbb83..762197d7217 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
@@ -1,4 +1,6 @@
-use crate::spec::{base, CodeModel, SanitizerSet, Target, TargetOptions};
+use std::borrow::Cow;
+
+use crate::spec::{base, CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -13,6 +15,7 @@ pub fn target() -> Target {
             llvm_abiname: "lp64d".into(),
             supported_sanitizers: SanitizerSet::ADDRESS,
             max_atomic_width: Some(64),
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             ..base::android::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
index c0969d4e11e..e71929a1904 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{base, CodeModel, Target, TargetOptions};
+use std::borrow::Cow;
+
+use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -12,6 +14,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".into(),
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             ..base::linux_gnu::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
index 656e260d094..8ea28d6b162 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
@@ -1,4 +1,6 @@
-use crate::spec::{base, CodeModel, Target, TargetOptions};
+use std::borrow::Cow;
+
+use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
@@ -12,6 +14,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".into(),
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
+            supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
             ..base::linux_musl::opts()
         },
     }
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 2e321018407..953041b8c20 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -2284,7 +2284,7 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl From<String> for Box<dyn Error + Send + Sync> {
+impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
     /// # Examples
@@ -2299,7 +2299,7 @@ impl From<String> for Box<dyn Error + Send + Sync> {
     ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
     /// ```
     #[inline]
-    fn from(err: String) -> Box<dyn Error + Send + Sync> {
+    fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
         struct StringError(String);
 
         impl Error for StringError {
@@ -2328,7 +2328,7 @@ impl From<String> for Box<dyn Error + Send + Sync> {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_box_error", since = "1.6.0")]
-impl From<String> for Box<dyn Error> {
+impl<'a> From<String> for Box<dyn Error + 'a> {
     /// Converts a [`String`] into a box of dyn [`Error`].
     ///
     /// # Examples
@@ -2341,7 +2341,7 @@ impl From<String> for Box<dyn Error> {
     /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
     /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
     /// ```
-    fn from(str_err: String) -> Box<dyn Error> {
+    fn from(str_err: String) -> Box<dyn Error + 'a> {
         let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
         let err2: Box<dyn Error> = err1;
         err2
@@ -2374,7 +2374,7 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_box_error", since = "1.6.0")]
-impl From<&str> for Box<dyn Error> {
+impl<'a> From<&str> for Box<dyn Error + 'a> {
     /// Converts a [`str`] into a box of dyn [`Error`].
     ///
     /// [`str`]: prim@str
@@ -2389,7 +2389,7 @@ impl From<&str> for Box<dyn Error> {
     /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
     /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
     /// ```
-    fn from(err: &str) -> Box<dyn Error> {
+    fn from(err: &str) -> Box<dyn Error + 'a> {
         From::from(String::from(err))
     }
 }
@@ -2418,7 +2418,7 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
     /// Converts a [`Cow`] into a box of dyn [`Error`].
     ///
     /// # Examples
@@ -2432,7 +2432,7 @@ impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
     /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
     /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
     /// ```
-    fn from(err: Cow<'a, str>) -> Box<dyn Error> {
+    fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
         From::from(String::from(err))
     }
 }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index ab08b483367..96d43e11dc6 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -135,6 +135,7 @@
 #![feature(iter_next_chunk)]
 #![feature(iter_repeat_n)]
 #![feature(layout_for_ptr)]
+#![feature(local_waker)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_uninit_array_transpose)]
@@ -252,7 +253,7 @@ pub mod str;
 pub mod string;
 #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
 pub mod sync;
-#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))]
 pub mod task;
 #[cfg(test)]
 mod tests;
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 5d9772b878b..87db8629ad0 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -2,14 +2,19 @@
 
 //! Types and Traits for working with asynchronous tasks.
 //!
-//! **Note**: This module is only available on platforms that support atomic
-//! loads and stores of pointers. This may be detected at compile time using
+//! **Note**: Some of the types in this module are only available
+//! on platforms that support atomic loads and stores of pointers.
+//! This may be detected at compile time using
 //! `#[cfg(target_has_atomic = "ptr")]`.
 
+use crate::rc::Rc;
 use core::mem::ManuallyDrop;
-use core::task::{RawWaker, RawWakerVTable, Waker};
+use core::task::{LocalWaker, RawWaker, RawWakerVTable};
 
+#[cfg(target_has_atomic = "ptr")]
 use crate::sync::Arc;
+#[cfg(target_has_atomic = "ptr")]
+use core::task::Waker;
 
 /// The implementation of waking a task on an executor.
 ///
@@ -73,6 +78,7 @@ use crate::sync::Arc;
 ///     println!("Hi from inside a future!");
 /// });
 /// ```
+#[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
 pub trait Wake {
     /// Wake this task.
@@ -91,7 +97,7 @@ pub trait Wake {
         self.clone().wake();
     }
 }
-
+#[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
     /// Use a `Wake`-able type as a `Waker`.
@@ -103,7 +109,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
         unsafe { Waker::from_raw(raw_waker(waker)) }
     }
 }
-
+#[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
     /// Use a `Wake`-able type as a `RawWaker`.
@@ -119,6 +125,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
 // the safety of `From<Arc<W>> for Waker` does not depend on the correct
 // trait dispatch - instead both impls call this function directly and
 // explicitly.
+#[cfg(target_has_atomic = "ptr")]
 #[inline(always)]
 fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
     // Increment the reference count of the arc to clone it.
@@ -152,3 +159,171 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
         &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
     )
 }
+
+/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API
+/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead
+/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`.
+///
+/// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker
+/// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls
+/// to `Arc::clone`, which requires atomic synchronization.
+///
+///
+/// # Examples
+///
+/// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
+/// is used to push new tasks onto the run queue, while the block on function will remove them
+/// and poll them. When a task is woken, it will put itself back on the run queue to be polled
+/// by the executor.
+///
+/// **Note:** This example trades correctness for simplicity. A real world example would interleave
+/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop.
+///
+/// ```rust
+/// #![feature(local_waker)]
+/// #![feature(noop_waker)]
+/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker};
+/// use std::future::Future;
+/// use std::pin::Pin;
+/// use std::rc::Rc;
+/// use std::cell::RefCell;
+/// use std::collections::VecDeque;
+///
+///
+/// thread_local! {
+///     // A queue containing all tasks ready to do progress
+///     static RUN_QUEUE: RefCell<VecDeque<Rc<Task>>> = RefCell::default();
+/// }
+///
+/// type BoxedFuture = Pin<Box<dyn Future<Output = ()>>>;
+///
+/// struct Task(RefCell<BoxedFuture>);
+///
+/// impl LocalWake for Task {
+///     fn wake(self: Rc<Self>) {
+///         RUN_QUEUE.with_borrow_mut(|queue| {
+///             queue.push_back(self)
+///         })
+///     }
+/// }
+///
+/// fn spawn<F>(future: F)
+/// where
+///     F: Future<Output=()> + 'static + Send + Sync
+/// {
+///     let task = RefCell::new(Box::pin(future));
+///     RUN_QUEUE.with_borrow_mut(|queue| {
+///         queue.push_back(Rc::new(Task(task)));
+///     });
+/// }
+///
+/// fn block_on<F>(future: F)
+/// where
+///     F: Future<Output=()> + 'static + Sync + Send
+/// {
+///     spawn(future);
+///     loop {
+///         let Some(task) = RUN_QUEUE.with_borrow_mut(|queue| queue.pop_front()) else {
+///             // we exit, since there are no more tasks remaining on the queue
+///             return;
+///         };
+///
+///         // cast the Rc<Task> into a `LocalWaker`
+///         let local_waker: LocalWaker = task.clone().into();
+///         // Build the context using `ContextBuilder`
+///         let mut cx = ContextBuilder::from_waker(Waker::noop())
+///             .local_waker(&local_waker)
+///             .build();
+///
+///         // Poll the task
+///         let _ = task.0
+///             .borrow_mut()
+///             .as_mut()
+///             .poll(&mut cx);
+///     }
+/// }
+///
+/// block_on(async {
+///     println!("hello world");
+/// });
+/// ```
+///
+#[unstable(feature = "local_waker", issue = "118959")]
+pub trait LocalWake {
+    /// Wake this task.
+    #[unstable(feature = "local_waker", issue = "118959")]
+    fn wake(self: Rc<Self>);
+
+    /// Wake this task without consuming the local waker.
+    ///
+    /// If an executor supports a cheaper way to wake without consuming the
+    /// waker, it should override this method. By default, it clones the
+    /// [`Rc`] and calls [`wake`] on the clone.
+    ///
+    /// [`wake`]: LocalWaker::wake
+    #[unstable(feature = "local_waker", issue = "118959")]
+    fn wake_by_ref(self: &Rc<Self>) {
+        self.clone().wake();
+    }
+}
+
+#[unstable(feature = "local_waker", issue = "118959")]
+impl<W: LocalWake + 'static> From<Rc<W>> for LocalWaker {
+    /// Use a `Wake`-able type as a `LocalWaker`.
+    ///
+    /// No heap allocations or atomic operations are used for this conversion.
+    fn from(waker: Rc<W>) -> LocalWaker {
+        // SAFETY: This is safe because raw_waker safely constructs
+        // a RawWaker from Rc<W>.
+        unsafe { LocalWaker::from_raw(local_raw_waker(waker)) }
+    }
+}
+#[allow(ineffective_unstable_trait_impl)]
+#[unstable(feature = "local_waker", issue = "118959")]
+impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
+    /// Use a `Wake`-able type as a `RawWaker`.
+    ///
+    /// No heap allocations or atomic operations are used for this conversion.
+    fn from(waker: Rc<W>) -> RawWaker {
+        local_raw_waker(waker)
+    }
+}
+
+// NB: This private function for constructing a RawWaker is used, rather than
+// inlining this into the `From<Rc<W>> for RawWaker` impl, to ensure that
+// the safety of `From<Rc<W>> for Waker` does not depend on the correct
+// trait dispatch - instead both impls call this function directly and
+// explicitly.
+#[inline(always)]
+fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
+    // Increment the reference count of the Rc to clone it.
+    unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
+        unsafe { Rc::increment_strong_count(waker as *const W) };
+        RawWaker::new(
+            waker as *const (),
+            &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
+        )
+    }
+
+    // Wake by value, moving the Rc into the LocalWake::wake function
+    unsafe fn wake<W: LocalWake + 'static>(waker: *const ()) {
+        let waker = unsafe { Rc::from_raw(waker as *const W) };
+        <W as LocalWake>::wake(waker);
+    }
+
+    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
+    unsafe fn wake_by_ref<W: LocalWake + 'static>(waker: *const ()) {
+        let waker = unsafe { ManuallyDrop::new(Rc::from_raw(waker as *const W)) };
+        <W as LocalWake>::wake_by_ref(&waker);
+    }
+
+    // Decrement the reference count of the Rc on drop
+    unsafe fn drop_waker<W: LocalWake + 'static>(waker: *const ()) {
+        unsafe { Rc::decrement_strong_count(waker as *const W) };
+    }
+
+    RawWaker::new(
+        Rc::into_raw(waker) as *const (),
+        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
+    )
+}
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index d749865f76f..bdb6599abf5 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -2,36 +2,36 @@ use crate::cmp::BytewiseEq;
 use crate::convert::TryInto;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
+impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N]
 where
-    A: PartialEq<B>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &[B; N]) -> bool {
+    fn eq(&self, other: &[U; N]) -> bool {
         SpecArrayEq::spec_eq(self, other)
     }
     #[inline]
-    fn ne(&self, other: &[B; N]) -> bool {
+    fn ne(&self, other: &[U; N]) -> bool {
         SpecArrayEq::spec_ne(self, other)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
+impl<T, U, const N: usize> PartialEq<[U]> for [T; N]
 where
-    A: PartialEq<B>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &[B]) -> bool {
-        let b: Result<&[B; N], _> = other.try_into();
+    fn eq(&self, other: &[U]) -> bool {
+        let b: Result<&[U; N], _> = other.try_into();
         match b {
             Ok(b) => *self == *b,
             Err(_) => false,
         }
     }
     #[inline]
-    fn ne(&self, other: &[B]) -> bool {
-        let b: Result<&[B; N], _> = other.try_into();
+    fn ne(&self, other: &[U]) -> bool {
+        let b: Result<&[U; N], _> = other.try_into();
         match b {
             Ok(b) => *self != *b,
             Err(_) => true,
@@ -40,21 +40,21 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
+impl<T, U, const N: usize> PartialEq<[U; N]> for [T]
 where
-    B: PartialEq<A>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &[A; N]) -> bool {
-        let b: Result<&[B; N], _> = self.try_into();
+    fn eq(&self, other: &[U; N]) -> bool {
+        let b: Result<&[T; N], _> = self.try_into();
         match b {
             Ok(b) => *b == *other,
             Err(_) => false,
         }
     }
     #[inline]
-    fn ne(&self, other: &[A; N]) -> bool {
-        let b: Result<&[B; N], _> = self.try_into();
+    fn ne(&self, other: &[U; N]) -> bool {
+        let b: Result<&[T; N], _> = self.try_into();
         match b {
             Ok(b) => *b != *other,
             Err(_) => true,
@@ -63,61 +63,61 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<&[B]> for [A; N]
+impl<T, U, const N: usize> PartialEq<&[U]> for [T; N]
 where
-    A: PartialEq<B>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &&[B]) -> bool {
+    fn eq(&self, other: &&[U]) -> bool {
         *self == **other
     }
     #[inline]
-    fn ne(&self, other: &&[B]) -> bool {
+    fn ne(&self, other: &&[U]) -> bool {
         *self != **other
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<[A; N]> for &[B]
+impl<T, U, const N: usize> PartialEq<[U; N]> for &[T]
 where
-    B: PartialEq<A>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &[A; N]) -> bool {
+    fn eq(&self, other: &[U; N]) -> bool {
         **self == *other
     }
     #[inline]
-    fn ne(&self, other: &[A; N]) -> bool {
+    fn ne(&self, other: &[U; N]) -> bool {
         **self != *other
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N]
+impl<T, U, const N: usize> PartialEq<&mut [U]> for [T; N]
 where
-    A: PartialEq<B>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &&mut [B]) -> bool {
+    fn eq(&self, other: &&mut [U]) -> bool {
         *self == **other
     }
     #[inline]
-    fn ne(&self, other: &&mut [B]) -> bool {
+    fn ne(&self, other: &&mut [U]) -> bool {
         *self != **other
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B]
+impl<T, U, const N: usize> PartialEq<[U; N]> for &mut [T]
 where
-    B: PartialEq<A>,
+    T: PartialEq<U>,
 {
     #[inline]
-    fn eq(&self, other: &[A; N]) -> bool {
+    fn eq(&self, other: &[U; N]) -> bool {
         **self == *other
     }
     #[inline]
-    fn ne(&self, other: &[A; N]) -> bool {
+    fn ne(&self, other: &[U; N]) -> bool {
         **self != *other
     }
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index dd0d59f6035..a2f07814726 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -61,11 +61,13 @@ use self::Ordering::*;
 /// The equality relation `==` must satisfy the following conditions
 /// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
 ///
-/// - **Symmetric**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b`
+/// - **Symmetry**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b`
 ///   implies `b == a`**; and
 ///
-/// - **Transitive**: if `A: PartialEq<B>` and `B: PartialEq<C>` and `A:
+/// - **Transitivity**: if `A: PartialEq<B>` and `B: PartialEq<C>` and `A:
 ///   PartialEq<C>`, then **`a == b` and `b == c` implies `a == c`**.
+///   This must also work for longer chains, such as when `A: PartialEq<B>`, `B: PartialEq<C>`,
+///   `C: PartialEq<D>`, and `A: PartialEq<D>` all exist.
 ///
 /// Note that the `B: PartialEq<A>` (symmetric) and `A: PartialEq<C>`
 /// (transitive) impls are not forced to exist, but these requirements apply
@@ -76,6 +78,25 @@ use self::Ordering::*;
 /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
 /// methods.
 ///
+/// ## Cross-crate considerations
+///
+/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq`
+/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
+/// standard library). The recommendation is to never implement this trait for a foreign type. In
+/// other words, such a crate should do `impl PartialEq<ForeignType> for LocalType`, but it should
+/// *not* do `impl PartialEq<LocalType> for ForeignType`.
+///
+/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
+/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T == U`. In
+/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ...
+/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the
+/// crate defining `T` already knows about. This rules out transitive chains where downstream crates
+/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
+/// transitivity.
+///
+/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
+/// more `PartialEq` implementations can cause build failures in downstream crates.
+///
 /// ## Derivable
 ///
 /// This trait can be used with `#[derive]`. When `derive`d on structs, two
@@ -920,20 +941,43 @@ pub macro Ord($item:item) {
 /// easy to accidentally make them disagree by deriving some of the traits and manually
 /// implementing others.
 ///
-/// The comparison must satisfy, for all `a`, `b` and `c`:
+/// The comparison relations must satisfy the following conditions
+/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
 ///
-/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
-/// - duality: `a < b` if and only if `b > a`.
+/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A:
+///   PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
+///   This must also work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`,
+///   `C: PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
+/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b > a`.
 ///
-/// Note that these requirements mean that the trait itself must be implemented symmetrically and
-/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
-/// PartialOrd<V>`.
+/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>`
+/// (transitive) impls are not forced to exist, but these requirements apply
+/// whenever they do exist.
 ///
 /// Violating these requirements is a logic error. The behavior resulting from a logic error is not
 /// specified, but users of the trait must ensure that such logic errors do *not* result in
 /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
 /// methods.
 ///
+/// ## Cross-crate considerations
+///
+/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd`
+/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
+/// standard library). The recommendation is to never implement this trait for a foreign type. In
+/// other words, such a crate should do `impl PartialOrd<ForeignType> for LocalType`, but it should
+/// *not* do `impl PartialOrd<LocalType> for ForeignType`.
+///
+/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
+/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T < U`. In
+/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ...
+/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate
+/// defining `T` already knows about. This rules out transitive chains where downstream crates can
+/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
+/// transitivity.
+///
+/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
+/// more `PartialOrd` implementations can cause build failures in downstream crates.
+///
 /// ## Corollaries
 ///
 /// The following corollaries follow from the above requirements:
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 8a8d634c007..e8b0010ba15 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -8,15 +8,15 @@ use super::from_raw_parts;
 use super::memchr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B> PartialEq<[B]> for [A]
+impl<T, U> PartialEq<[U]> for [T]
 where
-    A: PartialEq<B>,
+    T: PartialEq<U>,
 {
-    fn eq(&self, other: &[B]) -> bool {
+    fn eq(&self, other: &[U]) -> bool {
         SlicePartialEq::equal(self, other)
     }
 
-    fn ne(&self, other: &[B]) -> bool {
+    fn ne(&self, other: &[U]) -> bool {
         SlicePartialEq::not_equal(self, other)
     }
 }
diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs
index 3f0080e3832..f1a789e32a7 100644
--- a/library/core/src/task/mod.rs
+++ b/library/core/src/task/mod.rs
@@ -8,7 +8,7 @@ pub use self::poll::Poll;
 
 mod wake;
 #[stable(feature = "futures_api", since = "1.36.0")]
-pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
+pub use self::wake::{Context, ContextBuilder, LocalWaker, RawWaker, RawWakerVTable, Waker};
 
 mod ready;
 #[stable(feature = "ready_macro", since = "1.64.0")]
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 077852b0120..9ad71e394ea 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -1,11 +1,13 @@
 #![stable(feature = "futures_api", since = "1.36.0")]
 
+use crate::mem::transmute;
+
 use crate::fmt;
 use crate::marker::PhantomData;
 use crate::ptr;
 
 /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
-/// which provides customized wakeup behavior.
+/// or a [`LocalWaker`] which provides customized wakeup behavior.
 ///
 /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
 ///
@@ -33,9 +35,18 @@ impl RawWaker {
     /// The value of this pointer will get passed to all functions that are part
     /// of the `vtable` as the first parameter.
     ///
+    /// It is important to consider that the `data` pointer must point to a
+    /// thread safe type such as an `[Arc]<T: Send + Sync>`
+    /// when used to construct a [`Waker`]. This restriction is lifted when
+    /// constructing a [`LocalWaker`], which allows using types that do not implement
+    /// <code>[Send] + [Sync]</code> like `[Rc]<T>`.
+    ///
     /// The `vtable` customizes the behavior of a `Waker` which gets created
     /// from a `RawWaker`. For each operation on the `Waker`, the associated
     /// function in the `vtable` of the underlying `RawWaker` will be called.
+    ///
+    /// [`Arc`]: std::sync::Arc
+    /// [`Rc`]: std::rc::Rc
     #[inline]
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
@@ -60,6 +71,21 @@ impl RawWaker {
     pub fn vtable(&self) -> &'static RawWakerVTable {
         self.vtable
     }
+
+    #[unstable(feature = "noop_waker", issue = "98286")]
+    const NOOP: RawWaker = {
+        const VTABLE: RawWakerVTable = RawWakerVTable::new(
+            // Cloning just returns a new no-op raw waker
+            |_| RawWaker::NOOP,
+            // `wake` does nothing
+            |_| {},
+            // `wake_by_ref` does nothing
+            |_| {},
+            // Dropping does nothing as we don't allocate anything
+            |_| {},
+        );
+        RawWaker::new(ptr::null(), &VTABLE)
+    };
 }
 
 /// A virtual function pointer table (vtable) that specifies the behavior
@@ -73,11 +99,19 @@ impl RawWaker {
 /// [`RawWaker`] implementation. Calling one of the contained functions using
 /// any other `data` pointer will cause undefined behavior.
 ///
-/// These functions must all be thread-safe (even though [`RawWaker`] is
-/// <code>\![Send] + \![Sync]</code>)
-/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
-/// arbitrary threads or invoked by `&` reference. For example, this means that if the
-/// `clone` and `drop` functions manage a reference count, they must do so atomically.
+/// # Thread safety
+/// If the [`RawWaker`] will be used to construct a [`Waker`] then
+/// these functions must all be thread-safe (even though [`RawWaker`] is
+/// <code>\![Send] + \![Sync]</code>). This is because [`Waker`] is <code>[Send] + [Sync]</code>,
+/// and it may be moved to arbitrary threads or invoked by `&` reference. For example,
+/// this means that if the `clone` and `drop` functions manage a reference count,
+/// they must do so atomically.
+///
+/// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then
+/// these functions don't need to be thread safe. This means that <code>\![Send] + \![Sync]</code>
+///  data can be stored in the data pointer, and reference counting does not need any atomic
+/// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot
+/// be sent across threads.
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct RawWakerVTable {
@@ -117,16 +151,22 @@ impl RawWakerVTable {
     /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
     /// `wake_by_ref`, and `drop` functions.
     ///
-    /// These functions must all be thread-safe (even though [`RawWaker`] is
-    /// <code>\![Send] + \![Sync]</code>)
-    /// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
-    /// arbitrary threads or invoked by `&` reference. For example, this means that if the
-    /// `clone` and `drop` functions manage a reference count, they must do so atomically.
-    ///
+    /// If the [`RawWaker`] will be used to construct a [`Waker`] then
+    /// these functions must all be thread-safe (even though [`RawWaker`] is
+    /// <code>\![Send] + \![Sync]</code>). This is because [`Waker`] is <code>[Send] + [Sync]</code>,
+    /// and it may be moved to arbitrary threads or invoked by `&` reference. For example,
+    /// this means that if the `clone` and `drop` functions manage a reference count,
+    /// they must do so atomically.
+    ///
+    /// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then
+    /// these functions don't need to be thread safe. This means that <code>\![Send] + \![Sync]</code>
+    /// data can be stored in the data pointer, and reference counting does not need any atomic
+    /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot
+    /// be sent across threads.
     /// # `clone`
     ///
     /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
-    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
+    /// the [`Waker`]/[`LocalWaker`] in which the [`RawWaker`] is stored gets cloned.
     ///
     /// The implementation of this function must retain all resources that are
     /// required for this additional instance of a [`RawWaker`] and associated
@@ -152,7 +192,7 @@ impl RawWakerVTable {
     ///
     /// # `drop`
     ///
-    /// This function gets called when a [`Waker`] gets dropped.
+    /// This function gets called when a [`Waker`]/[`LocalWaker`] gets dropped.
     ///
     /// The implementation of this function must make sure to release any
     /// resources that are associated with this instance of a [`RawWaker`] and
@@ -178,6 +218,7 @@ impl RawWakerVTable {
 #[lang = "Context"]
 pub struct Context<'a> {
     waker: &'a Waker,
+    local_waker: &'a LocalWaker,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
     // are contravariant while return-position lifetimes are
@@ -195,17 +236,24 @@ impl<'a> Context<'a> {
     #[must_use]
     #[inline]
     pub const fn from_waker(waker: &'a Waker) -> Self {
-        Context { waker, _marker: PhantomData, _marker2: PhantomData }
+        ContextBuilder::from_waker(waker).build()
     }
 
     /// Returns a reference to the [`Waker`] for the current task.
+    #[inline]
+    #[must_use]
     #[stable(feature = "futures_api", since = "1.36.0")]
     #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
-    #[must_use]
-    #[inline]
     pub const fn waker(&self) -> &'a Waker {
         &self.waker
     }
+    /// Returns a reference to the [`LocalWaker`] for the current task.
+    #[inline]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn local_waker(&self) -> &'a LocalWaker {
+        &self.local_waker
+    }
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
@@ -215,6 +263,72 @@ impl fmt::Debug for Context<'_> {
     }
 }
 
+/// A Builder used to construct a `Context` instance
+/// with support for `LocalWaker`.
+///
+/// # Examples
+/// ```
+/// #![feature(local_waker)]
+/// #![feature(noop_waker)]
+/// use std::task::{ContextBuilder, LocalWaker, Waker, Poll};
+/// use std::future::Future;
+///
+/// let local_waker = LocalWaker::noop();
+/// let waker = Waker::noop();
+///
+/// let mut cx = ContextBuilder::from_waker(&waker)
+///     .local_waker(&local_waker)
+///     .build();
+///
+/// let mut future = std::pin::pin!(async { 20 });
+/// let poll = future.as_mut().poll(&mut cx);
+/// assert_eq!(poll, Poll::Ready(20));
+///
+/// ```
+#[unstable(feature = "local_waker", issue = "118959")]
+#[derive(Debug)]
+pub struct ContextBuilder<'a> {
+    waker: &'a Waker,
+    local_waker: &'a LocalWaker,
+    // Ensure we future-proof against variance changes by forcing
+    // the lifetime to be invariant (argument-position lifetimes
+    // are contravariant while return-position lifetimes are
+    // covariant).
+    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
+}
+
+impl<'a> ContextBuilder<'a> {
+    /// Create a ContextBuilder from a Waker.
+    #[inline]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    pub const fn from_waker(waker: &'a Waker) -> Self {
+        // SAFETY: LocalWaker is just Waker without thread safety
+        let local_waker = unsafe { transmute(waker) };
+        Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
+    }
+
+    /// This method is used to set the value for the local waker on `Context`.
+    #[inline]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
+        Self { local_waker, ..self }
+    }
+
+    /// Builds the `Context`.
+    #[inline]
+    #[unstable(feature = "local_waker", issue = "118959")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const fn build(self) -> Context<'a> {
+        let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
+        Context { waker, local_waker, _marker, _marker2 }
+    }
+}
+
 /// A `Waker` is a handle for waking up a task by notifying its executor that it
 /// is ready to be run.
 ///
@@ -354,25 +468,8 @@ impl Waker {
     #[must_use]
     #[unstable(feature = "noop_waker", issue = "98286")]
     pub const fn noop() -> &'static Waker {
-        // Ideally all this data would be explicitly `static` because it is used by reference and
-        // only ever needs one copy. But `const fn`s (and `const` items) cannot refer to statics,
-        // even though their values can be promoted to static. (That might change; see #119618.)
-        // An alternative would be a `pub static NOOP: &Waker`, but associated static items are not
-        // currently allowed either, and making it non-associated would be unergonomic.
-        const VTABLE: RawWakerVTable = RawWakerVTable::new(
-            // Cloning just returns a new no-op raw waker
-            |_| RAW,
-            // `wake` does nothing
-            |_| {},
-            // `wake_by_ref` does nothing
-            |_| {},
-            // Dropping does nothing as we don't allocate anything
-            |_| {},
-        );
-        const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);
-        const WAKER_REF: &Waker = &Waker { waker: RAW };
-
-        WAKER_REF
+        const WAKER: &Waker = &Waker { waker: RawWaker::NOOP };
+        WAKER
     }
 
     /// Get a reference to the underlying [`RawWaker`].
@@ -425,3 +522,222 @@ impl fmt::Debug for Waker {
             .finish()
     }
 }
+
+/// A `LocalWaker` is analogous to a [`Waker`], but it does not implement [`Send`] or [`Sync`].
+///
+/// This handle encapsulates a [`RawWaker`] instance, which defines the
+/// executor-specific wakeup behavior.
+///
+/// Local wakers can be requested from a `Context` with the [`local_waker`] method.
+///
+/// The typical life of a `LocalWaker` is that it is constructed by an executor, wrapped in a
+/// [`Context`] using [`ContextBuilder`], then passed to [`Future::poll()`]. Then, if the future chooses to return
+/// [`Poll::Pending`], it must also store the waker somehow and call [`LocalWaker::wake()`] when
+/// the future should be polled again.
+///
+/// Implements [`Clone`], but neither [`Send`] nor [`Sync`]; therefore, a local waker may
+/// not be moved to other threads. In general, when deciding to use wakers or local wakers,
+/// local wakers are preferable unless the waker needs to be sent across threads. This is because
+/// wakers can incur in additional cost related to memory synchronization.
+///
+/// Note that it is preferable to use `local_waker.clone_from(&new_waker)` instead
+/// of `*local_waker = new_waker.clone()`, as the former will avoid cloning the waker
+/// unnecessarily if the two wakers [wake the same task](Self::will_wake).
+///
+/// # Examples
+/// Usage of a local waker to implement a future analogous to `std::thread::yield_now()`.
+/// ```
+/// #![feature(local_waker)]
+/// use std::future::{Future, poll_fn};
+/// use std::task::Poll;
+///
+/// // a future that returns pending once.
+/// fn yield_now() -> impl Future<Output=()> + Unpin {
+///     let mut yielded = false;
+///     poll_fn(move |cx| {
+///         if !yielded {
+///             yielded = true;
+///             cx.local_waker().wake_by_ref();
+///             return Poll::Pending;
+///         }
+///         return Poll::Ready(())
+///     })
+/// }
+///
+/// # async fn __() {
+/// yield_now().await;
+/// # }
+/// ```
+///
+/// [`Future::poll()`]: core::future::Future::poll
+/// [`Poll::Pending`]: core::task::Poll::Pending
+/// [`local_waker`]: core::task::Context::local_waker
+#[unstable(feature = "local_waker", issue = "118959")]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
+pub struct LocalWaker {
+    waker: RawWaker,
+}
+
+#[unstable(feature = "local_waker", issue = "118959")]
+impl Unpin for LocalWaker {}
+
+impl LocalWaker {
+    /// Wake up the task associated with this `LocalWaker`.
+    ///
+    /// As long as the executor keeps running and the task is not finished, it is
+    /// guaranteed that each invocation of [`wake()`](Self::wake) (or
+    /// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one
+    /// [`poll()`] of the task to which this `LocalWaker` belongs. This makes
+    /// it possible to temporarily yield to other tasks while running potentially
+    /// unbounded processing loops.
+    ///
+    /// Note that the above implies that multiple wake-ups may be coalesced into a
+    /// single [`poll()`] invocation by the runtime.
+    ///
+    /// Also note that yielding to competing tasks is not guaranteed: it is the
+    /// executor’s choice which task to run and the executor may choose to run the
+    /// current task again.
+    ///
+    /// [`poll()`]: crate::future::Future::poll
+    #[inline]
+    #[stable(feature = "futures_api", since = "1.36.0")]
+    pub fn wake(self) {
+        // The actual wakeup call is delegated through a virtual function call
+        // to the implementation which is defined by the executor.
+        let wake = self.waker.vtable.wake;
+        let data = self.waker.data;
+
+        // Don't call `drop` -- the waker will be consumed by `wake`.
+        crate::mem::forget(self);
+
+        // SAFETY: This is safe because `Waker::from_raw` is the only way
+        // to initialize `wake` and `data` requiring the user to acknowledge
+        // that the contract of `RawWaker` is upheld.
+        unsafe { (wake)(data) };
+    }
+
+    /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`.
+    ///
+    /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in
+    /// the case where an owned `Waker` is available. This method should be preferred to
+    /// calling `waker.clone().wake()`.
+    #[inline]
+    #[stable(feature = "futures_api", since = "1.36.0")]
+    pub fn wake_by_ref(&self) {
+        // The actual wakeup call is delegated through a virtual function call
+        // to the implementation which is defined by the executor.
+
+        // SAFETY: see `wake`
+        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
+    }
+
+    /// Returns `true` if this `LocalWaker` and another `LocalWaker` would awake the same task.
+    ///
+    /// This function works on a best-effort basis, and may return false even
+    /// when the `Waker`s would awaken the same task. However, if this function
+    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
+    ///
+    /// This function is primarily used for optimization purposes — for example,
+    /// this type's [`clone_from`](Self::clone_from) implementation uses it to
+    /// avoid cloning the waker when they would wake the same task anyway.
+    #[inline]
+    #[must_use]
+    #[stable(feature = "futures_api", since = "1.36.0")]
+    pub fn will_wake(&self, other: &LocalWaker) -> bool {
+        self.waker == other.waker
+    }
+
+    /// Creates a new `LocalWaker` from [`RawWaker`].
+    ///
+    /// The behavior of the returned `LocalWaker` is undefined if the contract defined
+    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
+    /// Therefore this method is unsafe.
+    #[inline]
+    #[must_use]
+    #[stable(feature = "futures_api", since = "1.36.0")]
+    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+    pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker {
+        Self { waker }
+    }
+
+    /// Creates a new `LocalWaker` that does nothing when `wake` is called.
+    ///
+    /// This is mostly useful for writing tests that need a [`Context`] to poll
+    /// some futures, but are not expecting those futures to wake the waker or
+    /// do not need to do anything specific if it happens.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(local_waker)]
+    /// #![feature(noop_waker)]
+    ///
+    /// use std::future::Future;
+    /// use std::task::{ContextBuilder, LocalWaker, Waker, Poll};
+    ///
+    /// let mut cx = ContextBuilder::from_waker(Waker::noop())
+    ///     .local_waker(LocalWaker::noop())
+    ///     .build();
+    ///
+    /// let mut future = Box::pin(async { 10 });
+    /// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(10));
+    /// ```
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "noop_waker", issue = "98286")]
+    pub const fn noop() -> &'static LocalWaker {
+        const WAKER: &LocalWaker = &LocalWaker { waker: RawWaker::NOOP };
+        WAKER
+    }
+
+    /// Get a reference to the underlying [`RawWaker`].
+    #[inline]
+    #[must_use]
+    #[unstable(feature = "waker_getters", issue = "96992")]
+    pub fn as_raw(&self) -> &RawWaker {
+        &self.waker
+    }
+}
+#[unstable(feature = "local_waker", issue = "118959")]
+impl Clone for LocalWaker {
+    #[inline]
+    fn clone(&self) -> Self {
+        LocalWaker {
+            // SAFETY: This is safe because `Waker::from_raw` is the only way
+            // to initialize `clone` and `data` requiring the user to acknowledge
+            // that the contract of [`RawWaker`] is upheld.
+            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
+        }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, source: &Self) {
+        if !self.will_wake(source) {
+            *self = source.clone();
+        }
+    }
+}
+
+#[unstable(feature = "local_waker", issue = "118959")]
+impl AsRef<LocalWaker> for Waker {
+    fn as_ref(&self) -> &LocalWaker {
+        // SAFETY: LocalWaker is just Waker without thread safety
+        unsafe { transmute(self) }
+    }
+}
+
+#[stable(feature = "futures_api", since = "1.36.0")]
+impl fmt::Debug for LocalWaker {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
+        f.debug_struct("LocalWaker")
+            .field("data", &self.waker.data)
+            .field("vtable", &vtable_ptr)
+            .finish()
+    }
+}
+
+#[unstable(feature = "local_waker", issue = "118959")]
+impl !Send for LocalWaker {}
+#[unstable(feature = "local_waker", issue = "118959")]
+impl !Sync for LocalWaker {}
diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs
index 03620a08f2c..c4d5da1627c 100644
--- a/library/std/src/sys/pal/sgx/net.rs
+++ b/library/std/src/sys/pal/sgx/net.rs
@@ -542,7 +542,4 @@ pub mod netc {
         pub sin6_flowinfo: u32,
         pub sin6_scope_id: u32,
     }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
 }
diff --git a/library/std/src/sys/pal/teeos/net.rs b/library/std/src/sys/pal/teeos/net.rs
index 0df681dbfa5..fed95205027 100644
--- a/library/std/src/sys/pal/teeos/net.rs
+++ b/library/std/src/sys/pal/teeos/net.rs
@@ -364,9 +364,6 @@ pub mod netc {
         pub sin6_flowinfo: u32,
         pub sin6_scope_id: u32,
     }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
 }
 
 pub type Socket = UdpSocket;
diff --git a/library/std/src/sys/pal/xous/net/mod.rs b/library/std/src/sys/pal/xous/net/mod.rs
index b5a3da136a6..dd8b765aa74 100644
--- a/library/std/src/sys/pal/xous/net/mod.rs
+++ b/library/std/src/sys/pal/xous/net/mod.rs
@@ -78,7 +78,4 @@ pub mod netc {
         pub sin6_flowinfo: u32,
         pub sin6_scope_id: u32,
     }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
 }
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 3811421dc71..72097bfabd7 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -20,12 +20,8 @@ mod rustc_ok {
     pub fn rustc_lints() {
         let x = 42.0;
 
-        #[expect(illegal_floating_point_literal_pattern)]
-        match x {
-            5.0 => {}
-            6.0 => {}
-            _ => {}
-        }
+        #[expect(invalid_nan_comparisons)]
+        let _b = x == f32::NAN;
     }
 }
 
@@ -38,13 +34,9 @@ mod rustc_warn {
     pub fn rustc_lints() {
         let x = 42;
 
-        #[expect(illegal_floating_point_literal_pattern)]
+        #[expect(invalid_nan_comparisons)]
         //~^ ERROR: this lint expectation is unfulfilled
-        match x {
-            5 => {}
-            6 => {}
-            _ => {}
-        }
+        let _b = x == 5;
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index 3f8d0b72436..2a418d84566 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -1,5 +1,5 @@
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:35:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:31:14
    |
 LL |     #[expect(dead_code)]
    |              ^^^^^^^^^
@@ -8,31 +8,31 @@ LL |     #[expect(dead_code)]
    = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`
 
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:41:18
+  --> $DIR/expect_tool_lint_rfc_2383.rs:37:18
    |
-LL |         #[expect(illegal_floating_point_literal_pattern)]
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:116:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:108:14
    |
 LL |     #[expect(clippy::almost_swapped)]
    |              ^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:124:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:116:14
    |
 LL |     #[expect(clippy::bytes_nth)]
    |              ^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:130:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:122:14
    |
 LL |     #[expect(clippy::if_same_then_else)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:136:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:128:14
    |
 LL |     #[expect(clippy::overly_complex_bool_expr)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs
index 0901ac3640f..ffd694e9879 100644
--- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs
+++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.rs
@@ -24,10 +24,9 @@ mod rustc_ok {
     pub fn rustc_lints() {
         let x = 42.0;
 
-        #[expect(illegal_floating_point_literal_pattern)]
+        #[expect(invalid_nan_comparisons)]
         match x {
-            5.0 => {}
-            6.0 => {}
+            f32::NAN => {}
             _ => {}
         }
     }
@@ -40,7 +39,7 @@ mod rustc_warn {
     pub fn rustc_lints() {
         let x = 42;
 
-        #[expect(illegal_floating_point_literal_pattern)]
+        #[expect(invalid_nan_comparisons)]
         match x {
             5 => {}
             6 => {}
diff --git a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr
index efc5f349f4f..5ae3c039d27 100644
--- a/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr
+++ b/tests/rustdoc-ui/lints/expect-tool-lint-rfc-2383.stderr
@@ -7,19 +7,19 @@ LL | #![expect(rustdoc::missing_crate_level_docs)]
    = note: `#[warn(unfulfilled_lint_expectations)]` on by default
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect-tool-lint-rfc-2383.rs:71:14
+  --> $DIR/expect-tool-lint-rfc-2383.rs:70:14
    |
 LL |     #[expect(rustdoc::broken_intra_doc_links)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect-tool-lint-rfc-2383.rs:76:14
+  --> $DIR/expect-tool-lint-rfc-2383.rs:75:14
    |
 LL |     #[expect(rustdoc::invalid_html_tags)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect-tool-lint-rfc-2383.rs:81:14
+  --> $DIR/expect-tool-lint-rfc-2383.rs:80:14
    |
 LL |     #[expect(rustdoc::bare_urls)]
    |              ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/array-slice-vec/vec-matching-autoslice.rs b/tests/ui/array-slice-vec/vec-matching-autoslice.rs
index 8179edf420c..f839cd62b1a 100644
--- a/tests/ui/array-slice-vec/vec-matching-autoslice.rs
+++ b/tests/ui/array-slice-vec/vec-matching-autoslice.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
 
 pub fn main() {
     let x = [1, 2, 3];
diff --git a/tests/ui/binding/match-range.rs b/tests/ui/binding/match-range.rs
index 1dca84dfd45..cb7b93e7cc6 100644
--- a/tests/ui/binding/match-range.rs
+++ b/tests/ui/binding/match-range.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
 #![feature(exclusive_range_pattern)]
 
 pub fn main() {
diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr
index 843d6d9e04b..4089c850c80 100644
--- a/tests/ui/consts/too_generic_eval_ice.stderr
+++ b/tests/ui/consts/too_generic_eval_ice.stderr
@@ -22,13 +22,13 @@ LL |         [5; Self::HOST_SIZE] == [6; 0]
    |
    = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]`
    = help: the following other types implement trait `PartialEq<Rhs>`:
-             <[A; N] as PartialEq<[B; N]>>
-             <[A; N] as PartialEq<[B]>>
-             <[A; N] as PartialEq<&[B]>>
-             <[A; N] as PartialEq<&mut [B]>>
+             <[T; N] as PartialEq<[U; N]>>
+             <[T; N] as PartialEq<[U]>>
+             <[T; N] as PartialEq<&[U]>>
+             <[T; N] as PartialEq<&mut [U]>>
              <[T] as PartialEq<Vec<U, A>>>
-             <[A] as PartialEq<[B]>>
-             <[B] as PartialEq<[A; N]>>
+             <[T] as PartialEq<[U; N]>>
+             <[T] as PartialEq<[U]>>
              <&[T] as PartialEq<Vec<U, A>>>
            and 3 others
 
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
index a2a4c62fa02..33b99259dfe 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
@@ -1,7 +1,6 @@
 // Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges.
 
 #![feature(exclusive_range_pattern)]
-#![allow(illegal_floating_point_literal_pattern)]
 
 fn main() {}
 
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
index 6b20a820b73..1e68235303b 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:14:8
    |
 LL |     m!(0f32, f32::NEG_INFINITY..);
    |        ^^^^ pattern `_` not covered
@@ -11,7 +11,7 @@ LL |         match $s { $($t)+ => {}, _ => todo!() }
    |                                ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8
    |
 LL |     m!(0f32, ..f32::INFINITY);
    |        ^^^^ pattern `_` not covered
@@ -23,7 +23,7 @@ LL |         match $s { $($t)+ => {}, _ => todo!() }
    |                                ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:24:8
    |
 LL |     m!('a', ..core::char::MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
@@ -35,7 +35,7 @@ LL |         match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
    |                                +++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8
    |
 LL |     m!('a', ..ALMOST_MAX);
    |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
@@ -47,7 +47,7 @@ LL |         match $s { $($t)+ => {}, '\u{10fffe}'..='\u{10ffff}' => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'\0'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
    |
 LL |     m!('a', ALMOST_MIN..);
    |        ^^^ pattern `'\0'` not covered
@@ -59,7 +59,7 @@ LL |         match $s { $($t)+ => {}, '\0' => todo!() }
    |                                +++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
    |
 LL |     m!('a', ..=ALMOST_MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
@@ -71,7 +71,7 @@ LL |         match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
    |                                +++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
    |
 LL |     m!('a', ..=VAL | VAL_2..);
    |        ^^^ pattern `'b'` not covered
@@ -83,7 +83,7 @@ LL |         match $s { $($t)+ => {}, 'b' => todo!() }
    |                                ++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
    |
 LL |     m!('a', ..VAL_1 | VAL_2..);
    |        ^^^ pattern `'b'` not covered
@@ -95,7 +95,7 @@ LL |         match $s { $($t)+ => {}, 'b' => todo!() }
    |                                ++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:39:12
    |
 LL |         m!(0, ..u8::MAX);
    |            ^ pattern `u8::MAX` not covered
@@ -107,7 +107,7 @@ LL |         match $s { $($t)+ => {}, u8::MAX => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `254_u8..=u8::MAX` not covered
@@ -119,7 +119,7 @@ LL |         match $s { $($t)+ => {}, 254_u8..=u8::MAX => todo!() }
    |                                +++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u8` not covered
@@ -131,7 +131,7 @@ LL |         match $s { $($t)+ => {}, 0_u8 => todo!() }
    |                                +++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u8::MAX` not covered
@@ -143,7 +143,7 @@ LL |         match $s { $($t)+ => {}, u8::MAX => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u8` not covered
@@ -155,7 +155,7 @@ LL |         match $s { $($t)+ => {}, 43_u8 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u8` not covered
@@ -167,7 +167,7 @@ LL |         match $s { $($t)+ => {}, 43_u8 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:52:12
    |
 LL |         m!(0, ..u16::MAX);
    |            ^ pattern `u16::MAX` not covered
@@ -179,7 +179,7 @@ LL |         match $s { $($t)+ => {}, u16::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `65534_u16..=u16::MAX` not covered
@@ -191,7 +191,7 @@ LL |         match $s { $($t)+ => {}, 65534_u16..=u16::MAX => todo!() }
    |                                +++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u16` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u16` not covered
@@ -203,7 +203,7 @@ LL |         match $s { $($t)+ => {}, 0_u16 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u16::MAX` not covered
@@ -215,7 +215,7 @@ LL |         match $s { $($t)+ => {}, u16::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u16` not covered
@@ -227,7 +227,7 @@ LL |         match $s { $($t)+ => {}, 43_u16 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u16` not covered
@@ -239,7 +239,7 @@ LL |         match $s { $($t)+ => {}, 43_u16 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:65:12
    |
 LL |         m!(0, ..u32::MAX);
    |            ^ pattern `u32::MAX` not covered
@@ -251,7 +251,7 @@ LL |         match $s { $($t)+ => {}, u32::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `4294967294_u32..=u32::MAX` not covered
@@ -263,7 +263,7 @@ LL |         match $s { $($t)+ => {}, 4294967294_u32..=u32::MAX => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u32` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u32` not covered
@@ -275,7 +275,7 @@ LL |         match $s { $($t)+ => {}, 0_u32 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u32::MAX` not covered
@@ -287,7 +287,7 @@ LL |         match $s { $($t)+ => {}, u32::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u32` not covered
@@ -299,7 +299,7 @@ LL |         match $s { $($t)+ => {}, 43_u32 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u32` not covered
@@ -311,7 +311,7 @@ LL |         match $s { $($t)+ => {}, 43_u32 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:78:12
    |
 LL |         m!(0, ..u64::MAX);
    |            ^ pattern `u64::MAX` not covered
@@ -323,7 +323,7 @@ LL |         match $s { $($t)+ => {}, u64::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
@@ -335,7 +335,7 @@ LL |         match $s { $($t)+ => {}, 18446744073709551614_u64..=u64::MAX => tod
    |                                ++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u64` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u64` not covered
@@ -347,7 +347,7 @@ LL |         match $s { $($t)+ => {}, 0_u64 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u64::MAX` not covered
@@ -359,7 +359,7 @@ LL |         match $s { $($t)+ => {}, u64::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u64` not covered
@@ -371,7 +371,7 @@ LL |         match $s { $($t)+ => {}, 43_u64 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u64` not covered
@@ -383,7 +383,7 @@ LL |         match $s { $($t)+ => {}, 43_u64 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:91:12
    |
 LL |         m!(0, ..u128::MAX);
    |            ^ pattern `u128::MAX` not covered
@@ -395,7 +395,7 @@ LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
@@ -407,7 +407,7 @@ LL |         match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u1
    |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u128` not covered
@@ -419,7 +419,7 @@ LL |         match $s { $($t)+ => {}, 0_u128 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u128::MAX` not covered
@@ -431,7 +431,7 @@ LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u128` not covered
@@ -443,7 +443,7 @@ LL |         match $s { $($t)+ => {}, 43_u128 => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u128` not covered
@@ -455,7 +455,7 @@ LL |         match $s { $($t)+ => {}, 43_u128 => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:107:12
    |
 LL |         m!(0, ..i8::MAX);
    |            ^ pattern `i8::MAX` not covered
@@ -467,7 +467,7 @@ LL |         match $s { $($t)+ => {}, i8::MAX => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `126_i8..=i8::MAX` not covered
@@ -479,7 +479,7 @@ LL |         match $s { $($t)+ => {}, 126_i8..=i8::MAX => todo!() }
    |                                +++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i8::MIN` not covered
@@ -491,7 +491,7 @@ LL |         match $s { $($t)+ => {}, i8::MIN => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i8::MAX` not covered
@@ -503,7 +503,7 @@ LL |         match $s { $($t)+ => {}, i8::MAX => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i8` not covered
@@ -515,7 +515,7 @@ LL |         match $s { $($t)+ => {}, 43_i8 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i8` not covered
@@ -527,7 +527,7 @@ LL |         match $s { $($t)+ => {}, 43_i8 => todo!() }
    |                                ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:120:12
    |
 LL |         m!(0, ..i16::MAX);
    |            ^ pattern `i16::MAX` not covered
@@ -539,7 +539,7 @@ LL |         match $s { $($t)+ => {}, i16::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `32766_i16..=i16::MAX` not covered
@@ -551,7 +551,7 @@ LL |         match $s { $($t)+ => {}, 32766_i16..=i16::MAX => todo!() }
    |                                +++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i16::MIN` not covered
@@ -563,7 +563,7 @@ LL |         match $s { $($t)+ => {}, i16::MIN => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i16::MAX` not covered
@@ -575,7 +575,7 @@ LL |         match $s { $($t)+ => {}, i16::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i16` not covered
@@ -587,7 +587,7 @@ LL |         match $s { $($t)+ => {}, 43_i16 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i16` not covered
@@ -599,7 +599,7 @@ LL |         match $s { $($t)+ => {}, 43_i16 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:133:12
    |
 LL |         m!(0, ..i32::MAX);
    |            ^ pattern `i32::MAX` not covered
@@ -611,7 +611,7 @@ LL |         match $s { $($t)+ => {}, i32::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `2147483646_i32..=i32::MAX` not covered
@@ -623,7 +623,7 @@ LL |         match $s { $($t)+ => {}, 2147483646_i32..=i32::MAX => todo!() }
    |                                ++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i32::MIN` not covered
@@ -635,7 +635,7 @@ LL |         match $s { $($t)+ => {}, i32::MIN => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i32::MAX` not covered
@@ -647,7 +647,7 @@ LL |         match $s { $($t)+ => {}, i32::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i32` not covered
@@ -659,7 +659,7 @@ LL |         match $s { $($t)+ => {}, 43_i32 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i32` not covered
@@ -671,7 +671,7 @@ LL |         match $s { $($t)+ => {}, 43_i32 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:146:12
    |
 LL |         m!(0, ..i64::MAX);
    |            ^ pattern `i64::MAX` not covered
@@ -683,7 +683,7 @@ LL |         match $s { $($t)+ => {}, i64::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
@@ -695,7 +695,7 @@ LL |         match $s { $($t)+ => {}, 9223372036854775806_i64..=i64::MAX => todo
    |                                +++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i64::MIN` not covered
@@ -707,7 +707,7 @@ LL |         match $s { $($t)+ => {}, i64::MIN => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i64::MAX` not covered
@@ -719,7 +719,7 @@ LL |         match $s { $($t)+ => {}, i64::MAX => todo!() }
    |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i64` not covered
@@ -731,7 +731,7 @@ LL |         match $s { $($t)+ => {}, 43_i64 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i64` not covered
@@ -743,7 +743,7 @@ LL |         match $s { $($t)+ => {}, 43_i64 => todo!() }
    |                                +++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:159:12
    |
 LL |         m!(0, ..i128::MAX);
    |            ^ pattern `i128::MAX` not covered
@@ -755,7 +755,7 @@ LL |         match $s { $($t)+ => {}, i128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12
    |
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
@@ -767,7 +767,7 @@ LL |         match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i1
    |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
    |
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i128::MIN` not covered
@@ -779,7 +779,7 @@ LL |         match $s { $($t)+ => {}, i128::MIN => todo!() }
    |                                ++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
    |
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i128::MAX` not covered
@@ -791,7 +791,7 @@ LL |         match $s { $($t)+ => {}, i128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i128` not covered
@@ -803,7 +803,7 @@ LL |         match $s { $($t)+ => {}, 43_i128 => todo!() }
    |                                ++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
-  --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i128` not covered
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
index 6c6ba93196b..d5af7bea543 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
@@ -4,7 +4,6 @@
 // via `.contains(...)` and make sure the dynamic semantics match.
 
 #![feature(exclusive_range_pattern)]
-#![allow(illegal_floating_point_literal_pattern)]
 #![allow(unreachable_patterns)]
 
 macro_rules! yes {
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
index 4b14a314e7a..158da650966 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
@@ -1,5 +1,4 @@
 #![feature(exclusive_range_pattern)]
-#![allow(illegal_floating_point_literal_pattern)]
 
 macro_rules! m {
     ($s:expr, $($t:tt)+) => {
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
index e9702bb380f..169e776fc20 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
@@ -1,77 +1,77 @@
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:10:11
    |
 LL |     m!(0, ..u8::MIN);
    |           ^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11
    |
 LL |     m!(0, ..u16::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
    |
 LL |     m!(0, ..u32::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:16:11
    |
 LL |     m!(0, ..u64::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:18:11
    |
 LL |     m!(0, ..u128::MIN);
    |           ^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11
    |
 LL |     m!(0, ..i8::MIN);
    |           ^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
    |
 LL |     m!(0, ..i16::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:25:11
    |
 LL |     m!(0, ..i32::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
    |
 LL |     m!(0, ..i64::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:29:11
    |
 LL |     m!(0, ..i128::MIN);
    |           ^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:32:14
    |
 LL |     m!(0f32, ..f32::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:34:14
    |
 LL |     m!(0f64, ..f64::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:38:13
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:13
    |
 LL |     m!('a', ..'\u{0}');
    |             ^^^^^^^^^
diff --git a/tests/ui/lint/issue-86600-lint-twice.rs b/tests/ui/lint/issue-86600-lint-twice.rs
deleted file mode 100644
index 0e8a837d987..00000000000
--- a/tests/ui/lint/issue-86600-lint-twice.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Regression test for #86600, where an instance of the
-// `illegal_floating_point_literal_pattern` lint was issued twice.
-
-// check-pass
-
-fn main() {
-    let x = 42.0;
-
-    match x {
-        5.0 => {}
-        //~^ WARNING: floating-point types cannot be used in patterns
-        //~| WARNING: this was previously accepted by the compiler
-        _ => {}
-    }
-}
diff --git a/tests/ui/lint/issue-86600-lint-twice.stderr b/tests/ui/lint/issue-86600-lint-twice.stderr
deleted file mode 100644
index 5a65c612128..00000000000
--- a/tests/ui/lint/issue-86600-lint-twice.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-warning: floating-point types cannot be used in patterns
-  --> $DIR/issue-86600-lint-twice.rs:10:9
-   |
-LL |         5.0 => {}
-   |         ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-   = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
index f80fe88cbb9..82ca49461ed 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
@@ -22,12 +22,8 @@ mod rustc_ok {
     pub fn rustc_lints() {
         let x = 42.0;
 
-        #[expect(illegal_floating_point_literal_pattern)]
-        match x {
-            5.0 => {}
-            6.0 => {}
-            _ => {}
-        }
+        #[expect(invalid_nan_comparisons)]
+        let _b = x == f32::NAN;
     }
 }
 
@@ -40,13 +36,9 @@ mod rustc_warn {
     pub fn rustc_lints() {
         let x = 42;
 
-        #[expect(illegal_floating_point_literal_pattern)]
+        #[expect(invalid_nan_comparisons)]
         //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
-        match x {
-            5 => {}
-            6 => {}
-            _ => {}
-        }
+        let _b = x == 5;
     }
 }
 
diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
index 6d49e7543dc..efe1aa04e5e 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
+++ b/tests/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
@@ -1,5 +1,5 @@
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:37:14
+  --> $DIR/expect_tool_lint_rfc_2383.rs:33:14
    |
 LL |     #[expect(dead_code)]
    |              ^^^^^^^^^
@@ -7,10 +7,10 @@ LL |     #[expect(dead_code)]
    = note: `#[warn(unfulfilled_lint_expectations)]` on by default
 
 warning: this lint expectation is unfulfilled
-  --> $DIR/expect_tool_lint_rfc_2383.rs:43:18
+  --> $DIR/expect_tool_lint_rfc_2383.rs:39:18
    |
-LL |         #[expect(illegal_floating_point_literal_pattern)]
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         #[expect(invalid_nan_comparisons)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/match/issue-41255.rs b/tests/ui/match/issue-41255.rs
deleted file mode 100644
index d163801fd19..00000000000
--- a/tests/ui/match/issue-41255.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Matching against float literals should result in a linter error
-
-#![feature(exclusive_range_pattern)]
-#![allow(unused)]
-#![forbid(illegal_floating_point_literal_pattern)]
-
-fn main() {
-    let x = 42.0;
-    match x {
-        5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
-                   //~| WARNING hard error
-        5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns
-                      //~| WARNING hard error
-        -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
-                    //~| WARNING hard error
-        1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns
-                           //~| WARNING hard error
-                           //~| ERROR floating-point types cannot be used in patterns
-                           //~| WARNING hard error
-        39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns
-                             //~| ERROR floating-point types cannot be used in patterns
-                             //~| WARNING hard error
-                             //~| WARNING hard error
-
-        ..71.0 => {}
-        //~^ ERROR floating-point types cannot be used in patterns
-        //~| WARNING this was previously accepted by the compiler
-        ..=72.0 => {}
-        //~^ ERROR floating-point types cannot be used in patterns
-        //~| WARNING this was previously accepted by the compiler
-        71.0.. => {}
-        //~^ ERROR floating-point types cannot be used in patterns
-        //~| WARNING this was previously accepted by the compiler
-        _ => {},
-    };
-    let y = 5.0;
-    // Same for tuples
-    match (x, 5) {
-        (3.14, 1) => {}, //~ ERROR floating-point types cannot be used
-                         //~| WARNING hard error
-        _ => {},
-    }
-    // Or structs
-    struct Foo { x: f32 };
-    match (Foo { x }) {
-        Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used
-                              //~| WARNING hard error
-        _ => {},
-    }
-}
diff --git a/tests/ui/match/issue-41255.stderr b/tests/ui/match/issue-41255.stderr
deleted file mode 100644
index 9bc49654e6d..00000000000
--- a/tests/ui/match/issue-41255.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:10:9
-   |
-LL |         5.0 => {},
-   |         ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-note: the lint level is defined here
-  --> $DIR/issue-41255.rs:5:11
-   |
-LL | #![forbid(illegal_floating_point_literal_pattern)]
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:12:9
-   |
-LL |         5.0f32 => {},
-   |         ^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:14:10
-   |
-LL |         -5.0 => {},
-   |          ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:16:9
-   |
-LL |         1.0 .. 33.0 => {},
-   |         ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:16:16
-   |
-LL |         1.0 .. 33.0 => {},
-   |                ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:20:9
-   |
-LL |         39.0 ..= 70.0 => {},
-   |         ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:20:18
-   |
-LL |         39.0 ..= 70.0 => {},
-   |                  ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:25:11
-   |
-LL |         ..71.0 => {}
-   |           ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:28:12
-   |
-LL |         ..=72.0 => {}
-   |            ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:31:9
-   |
-LL |         71.0.. => {}
-   |         ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:39:10
-   |
-LL |         (3.14, 1) => {},
-   |          ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:46:18
-   |
-LL |         Foo { x: 2.0 } => {},
-   |                  ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: aborting due to 12 previous errors
-
diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs
new file mode 100644
index 00000000000..8da6a9ed204
--- /dev/null
+++ b/tests/ui/match/match-float.rs
@@ -0,0 +1,11 @@
+// run-pass
+// Makes sure we use `==` (not bitwise) semantics for float comparison.
+
+fn main() {
+    const F1: f32 = 0.0;
+    const F2: f32 = -0.0;
+    assert_eq!(F1, F2);
+    assert_ne!(F1.to_bits(), F2.to_bits());
+    assert!(matches!(F1, F2));
+    assert!(matches!(F2, F1));
+}
diff --git a/tests/ui/parser/issues/issue-7222.rs b/tests/ui/parser/issues/issue-7222.rs
index 64907316626..fb18f4cd62e 100644
--- a/tests/ui/parser/issues/issue-7222.rs
+++ b/tests/ui/parser/issues/issue-7222.rs
@@ -1,6 +1,5 @@
 // run-pass
 // pretty-expanded FIXME #23616
-#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
 
 pub fn main() {
     const FOO: f64 = 10.0;
diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs
index 2616dfadb85..63ce26adab2 100644
--- a/tests/ui/pattern/usefulness/floats.rs
+++ b/tests/ui/pattern/usefulness/floats.rs
@@ -1,5 +1,4 @@
 #![feature(exclusive_range_pattern)]
-#![allow(illegal_floating_point_literal_pattern)]
 #![deny(unreachable_patterns)]
 
 fn main() {
diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr
index f5041911824..d99f05f5284 100644
--- a/tests/ui/pattern/usefulness/floats.stderr
+++ b/tests/ui/pattern/usefulness/floats.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/floats.rs:11:11
+  --> $DIR/floats.rs:10:11
    |
 LL |     match 0.0 {
    |           ^^^ pattern `_` not covered
@@ -12,49 +12,49 @@ LL +         _ => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/floats.rs:19:9
+  --> $DIR/floats.rs:18:9
    |
 LL |         0.01f64 => {}
    |         ^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/floats.rs:3:9
+  --> $DIR/floats.rs:2:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:20:9
+  --> $DIR/floats.rs:19:9
    |
 LL |         0.02f64 => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:21:9
+  --> $DIR/floats.rs:20:9
    |
 LL |         6.5f64 => {}
    |         ^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:23:9
+  --> $DIR/floats.rs:22:9
    |
 LL |         1.0f64..=4.0f64 => {}
    |         ^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:35:9
+  --> $DIR/floats.rs:34:9
    |
 LL |         0.01f32 => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:36:9
+  --> $DIR/floats.rs:35:9
    |
 LL |         0.02f32 => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:37:9
+  --> $DIR/floats.rs:36:9
    |
 LL |         6.5f32 => {}
    |         ^^^^^^
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.rs b/tests/ui/pattern/usefulness/non-exhaustive-match.rs
index 1cb58b8cebe..44acd397f8d 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-match.rs
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match.rs
@@ -1,5 +1,3 @@
-#![allow(illegal_floating_point_literal_pattern)]
-
 enum T { A, B }
 
 fn main() {
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
index 4bebd3cbbef..61ed0eb4fc4 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -1,11 +1,11 @@
 error[E0004]: non-exhaustive patterns: `T::A` not covered
-  --> $DIR/non-exhaustive-match.rs:7:11
+  --> $DIR/non-exhaustive-match.rs:5:11
    |
 LL |     match x { T::B => { } }
    |           ^ pattern `T::A` not covered
    |
 note: `T` defined here
-  --> $DIR/non-exhaustive-match.rs:3:6
+  --> $DIR/non-exhaustive-match.rs:1:6
    |
 LL | enum T { A, B }
    |      ^   - not covered
@@ -16,7 +16,7 @@ LL |     match x { T::B => { }, T::A => todo!() }
    |                          +++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `false` not covered
-  --> $DIR/non-exhaustive-match.rs:8:11
+  --> $DIR/non-exhaustive-match.rs:6:11
    |
 LL |     match true {
    |           ^^^^ pattern `false` not covered
@@ -29,7 +29,7 @@ LL +       false => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/non-exhaustive-match.rs:11:11
+  --> $DIR/non-exhaustive-match.rs:9:11
    |
 LL |     match Some(10) {
    |           ^^^^^^^^ pattern `Some(_)` not covered
@@ -47,7 +47,7 @@ LL +       Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
-  --> $DIR/non-exhaustive-match.rs:14:11
+  --> $DIR/non-exhaustive-match.rs:12:11
    |
 LL |     match (2, 3, 4) {
    |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
@@ -60,7 +60,7 @@ LL +       (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
-  --> $DIR/non-exhaustive-match.rs:18:11
+  --> $DIR/non-exhaustive-match.rs:16:11
    |
 LL |     match (T::A, T::A) {
    |           ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered
@@ -73,13 +73,13 @@ LL +       (T::A, T::A) | (T::B, T::B) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `T::B` not covered
-  --> $DIR/non-exhaustive-match.rs:22:11
+  --> $DIR/non-exhaustive-match.rs:20:11
    |
 LL |     match T::A {
    |           ^^^^ pattern `T::B` not covered
    |
 note: `T` defined here
-  --> $DIR/non-exhaustive-match.rs:3:6
+  --> $DIR/non-exhaustive-match.rs:1:6
    |
 LL | enum T { A, B }
    |      ^      - not covered
@@ -91,7 +91,7 @@ LL +       T::B => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/non-exhaustive-match.rs:33:11
+  --> $DIR/non-exhaustive-match.rs:31:11
    |
 LL |     match *vec {
    |           ^^^^ pattern `[]` not covered
@@ -104,7 +104,7 @@ LL +         [] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
-  --> $DIR/non-exhaustive-match.rs:46:11
+  --> $DIR/non-exhaustive-match.rs:44:11
    |
 LL |     match *vec {
    |           ^^^^ pattern `[_, _, _, _, ..]` not covered
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs
new file mode 100644
index 00000000000..d43db576b38
--- /dev/null
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs
@@ -0,0 +1,41 @@
+// Matching against NaN should result in an error
+#![feature(exclusive_range_pattern)]
+#![allow(unused)]
+
+const NAN: f64 = f64::NAN;
+
+#[derive(PartialEq, Eq)]
+struct MyType<T>(T);
+
+const C: MyType<f32> = MyType(f32::NAN);
+
+fn main() {
+    let x = NAN;
+    match x {
+        NAN => {}, //~ ERROR cannot use NaN in patterns
+        _ => {},
+    };
+
+    match [x, 1.0] {
+        [NAN, _] => {}, //~ ERROR cannot use NaN in patterns
+        _ => {},
+    };
+
+    match MyType(1.0f32) {
+        C => {}, //~ ERROR cannot use NaN in patterns
+        _ => {},
+    }
+
+    // Also cover range patterns
+    match x {
+        NAN..=1.0 => {}, //~ ERROR cannot use NaN in patterns
+        //~^ ERROR lower range bound must be less than or equal to upper
+        -1.0..=NAN => {}, //~ ERROR cannot use NaN in patterns
+        //~^ ERROR lower range bound must be less than or equal to upper
+        NAN.. => {}, //~ ERROR cannot use NaN in patterns
+        //~^ ERROR lower range bound must be less than or equal to upper
+        ..NAN => {}, //~ ERROR cannot use NaN in patterns
+        //~^ ERROR lower range bound must be less than upper
+        _ => {},
+    };
+}
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
new file mode 100644
index 00000000000..167ada783c2
--- /dev/null
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
@@ -0,0 +1,91 @@
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:15:9
+   |
+LL |         NAN => {},
+   |         ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:20:10
+   |
+LL |         [NAN, _] => {},
+   |          ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:25:9
+   |
+LL |         C => {},
+   |         ^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:31:9
+   |
+LL |         NAN..=1.0 => {},
+   |         ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/issue-6804-nan-match.rs:31:9
+   |
+LL |         NAN..=1.0 => {},
+   |         ^^^^^^^^^ lower bound larger than upper bound
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:33:16
+   |
+LL |         -1.0..=NAN => {},
+   |                ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/issue-6804-nan-match.rs:33:9
+   |
+LL |         -1.0..=NAN => {},
+   |         ^^^^^^^^^^ lower bound larger than upper bound
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:35:9
+   |
+LL |         NAN.. => {},
+   |         ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/issue-6804-nan-match.rs:35:9
+   |
+LL |         NAN.. => {},
+   |         ^^^^^ lower bound larger than upper bound
+
+error: cannot use NaN in patterns
+  --> $DIR/issue-6804-nan-match.rs:37:11
+   |
+LL |         ..NAN => {},
+   |           ^^^
+   |
+   = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
+   = help: try using the `is_nan` method instead
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/issue-6804-nan-match.rs:37:9
+   |
+LL |         ..NAN => {},
+   |         ^^^^^
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0030, E0579.
+For more information about an error, try `rustc --explain E0030`.
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs
deleted file mode 100644
index 0260caa82cb..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Matching against NaN should result in a warning
-
-#![allow(unused)]
-#![deny(illegal_floating_point_literal_pattern)]
-
-const NAN: f64 = f64::NAN;
-
-fn main() {
-    let x = NAN;
-    match x {
-        NAN => {}, //~ ERROR floating-point types cannot be used
-        //~| WARN this was previously accepted by the compiler but is being phased out
-        _ => {},
-    };
-
-    match [x, 1.0] {
-        [NAN, _] => {}, //~ ERROR floating-point types cannot be used
-        //~| WARN this was previously accepted by the compiler but is being phased out
-        _ => {},
-    };
-}
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr
deleted file mode 100644
index f37255d0828..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-6804.rs:11:9
-   |
-LL |         NAN => {},
-   |         ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-note: the lint level is defined here
-  --> $DIR/issue-6804.rs:4:9
-   |
-LL | #![deny(illegal_floating_point_literal_pattern)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: floating-point types cannot be used in patterns
-  --> $DIR/issue-6804.rs:17:10
-   |
-LL |         [NAN, _] => {},
-   |          ^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/union/union-pat-refutability.rs b/tests/ui/union/union-pat-refutability.rs
index 17ac6c6dfa9..edcc1add38f 100644
--- a/tests/ui/union/union-pat-refutability.rs
+++ b/tests/ui/union/union-pat-refutability.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![allow(dead_code)]
-#![allow(illegal_floating_point_literal_pattern)]
 
 #[repr(u32)]
 enum Tag {