about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/liballoc/raw_vec.rs2
-rw-r--r--src/libcore/intrinsics.rs16
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/ptr/const_ptr.rs66
-rw-r--r--src/libcore/ptr/mut_ptr.rs66
-rw-r--r--src/libcore/slice/mod.rs17
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs12
-rw-r--r--src/librustc_feature/active.rs3
-rw-r--r--src/librustc_feature/removed.rs5
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs5
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs20
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs15
-rw-r--r--src/librustc_span/symbol.rs2
-rw-r--r--src/librustc_typeck/check/intrinsic.rs9
-rw-r--r--src/librustc_typeck/collect/type_of.rs26
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.rs7
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.stderr18
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.rs11
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr41
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.rs7
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.stderr18
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.rs6
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.stderr14
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops.rs15
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr44
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs13
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr28
-rw-r--r--src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs2
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.stderr2
-rw-r--r--src/test/ui/consts/miri_unleashed/slice_eq.rs17
-rw-r--r--src/test/ui/error-codes/E0395.rs4
-rw-r--r--src/test/ui/error-codes/E0395.stderr6
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr10
-rw-r--r--src/test/ui/issues/issue-25826.rs2
-rw-r--r--src/test/ui/issues/issue-25826.stderr4
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.rs8
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.stderr8
-rw-r--r--src/tools/tidy/src/features.rs5
39 files changed, 358 insertions, 201 deletions
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 15e81f92887..67ebdcc9f33 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -60,7 +60,7 @@ impl<T> RawVec<T, Global> {
     /// `#[rustc_force_min_const_fn]` attribute which requires conformance
     /// with `min_const_fn` but does not necessarily allow calling it in
     /// `stable(...) const fn` / user code not enabling `foo` when
-    /// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
+    /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
     pub const NEW: Self = Self::new();
 
     /// Creates the biggest possible `RawVec` (on the system heap)
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 9061145a695..50e321f9c71 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1012,7 +1012,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::type_name`](../../std/any/fn.type_name.html)
-    #[rustc_const_unstable(feature = "const_type_name", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
     /// Gets an identifier which is globally unique to the specified type. This
@@ -1021,7 +1021,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
-    #[rustc_const_unstable(feature = "const_type_id", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
     /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -1931,7 +1931,7 @@ extern "rust-intrinsic" {
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
     /// See documentation of `<*const T>::offset_from` for details.
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal hook used by Miri to implement unwinding.
@@ -1948,6 +1948,16 @@ extern "rust-intrinsic" {
     #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
     pub fn count_code_region(index: u32);
+
+    /// See documentation of `<*const T>::guaranteed_eq` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
+
+    /// See documentation of `<*const T>::guaranteed_ne` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 0115c4df2fd..4eb2fdbd078 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -87,6 +87,7 @@
 #![feature(const_generics)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
+#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
 #![feature(const_result)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index acc09ddc014..395b3879cfd 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -295,6 +295,72 @@ impl<T: ?Sized> *const T {
         intrinsics::ptr_offset_from(self, origin)
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self, other)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_ne(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self, other)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 2bbeb95965e..b86ef5b13b3 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -273,6 +273,72 @@ impl<T: ?Sized> *mut T {
         if self.is_null() { None } else { Some(&mut *self) }
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    /// ```
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 21ba2b5abcf..c69aafe687c 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -5956,10 +5956,18 @@ where
             return false;
         }
 
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
 
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
+
         self.iter().zip(other.iter()).all(|(x, y)| x == y)
     }
 }
@@ -5973,9 +5981,18 @@ where
         if self.len() != other.len() {
             return false;
         }
+
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
+
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
         unsafe {
             let size = mem::size_of_val(self);
             memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 95465939070..0a8525f06fa 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -12,7 +12,7 @@ use log::debug;
 use rustc_ast::ast;
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
-use rustc_codegen_ssa::common::TypeKind;
+use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -731,6 +731,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 return;
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                let a = args[0].immediate();
+                let b = args[1].immediate();
+                if name == "ptr_guaranteed_eq" {
+                    self.icmp(IntPredicate::IntEQ, a, b)
+                } else {
+                    self.icmp(IntPredicate::IntNE, a, b)
+                }
+            }
+
             "ptr_offset_from" => {
                 let ty = substs.type_at(0);
                 let pointee_size = self.size_of(ty);
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 7aadf58243f..e2d497a3ada 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -401,9 +401,6 @@ declare_features! (
     /// Allows dereferencing raw pointers during const eval.
     (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
 
-    /// Allows comparing raw pointers during const eval.
-    (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
-
     /// Allows `#[doc(alias = "...")]`.
     (active, doc_alias, "1.27.0", Some(50146), None),
 
diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs
index 4e348054fbd..8d410894e8b 100644
--- a/src/librustc_feature/removed.rs
+++ b/src/librustc_feature/removed.rs
@@ -113,6 +113,11 @@ declare_features! (
      Some("removed in favor of `#![feature(marker_trait_attr)]`")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+
+    /// Allows comparing raw pointers during const eval.
+    (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
+     Some("cannot be allowed in const eval in any meaningful way")),
+
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 31bdc45a2ea..6ac1e6be036 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -296,6 +296,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
                 self.write_scalar(offset_ptr, dest)?;
             }
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+                // FIXME: return `true` for at least some comparisons where we can reliably
+                // determine the result of runtime (in)equality tests at compile-time.
+                self.write_scalar(Scalar::from_bool(false), dest)?;
+            }
             sym::ptr_offset_from => {
                 let a = self.read_immediate(args[0])?.to_scalar()?;
                 let b = self.read_immediate(args[1])?.to_scalar()?;
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 733ae908451..45073ab8b4d 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -296,18 +296,16 @@ impl NonConstOp for Panic {
 #[derive(Debug)]
 pub struct RawPtrComparison;
 impl NonConstOp for RawPtrComparison {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_compare_raw_pointers)
-    }
-
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_compare_raw_pointers,
-            span,
-            &format!("comparing raw pointers inside {}", ccx.const_kind()),
-        )
-        .emit();
+        let mut err = ccx
+            .tcx
+            .sess
+            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+        err.note(
+            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
+            for more information",
+        );
+        err.emit();
     }
 }
 
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 7dbb2ebad8b..ac7acff1eca 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -171,21 +171,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     _ => {}
                 }
             }
-            // raw pointer and fn pointer operations are unsafe as it is not clear whether one
-            // pointer would be "less" or "equal" to another, because we cannot know where llvm
-            // or the linker will place various statics in memory. Without this information the
-            // result of a comparison of addresses would differ between runtime and compile-time.
-            Rvalue::BinaryOp(_, ref lhs, _)
-                if self.const_context && self.tcx.features().const_compare_raw_pointers =>
-            {
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
-                    self.require_unsafe(
-                        "pointer operation",
-                        "operations on pointers in constants",
-                        UnsafetyViolationKind::General,
-                    );
-                }
-            }
             _ => {}
         }
         self.super_rvalue(rvalue, location);
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 970a2632592..06d1f36622b 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -588,6 +588,8 @@ symbols! {
         proc_macro_non_items,
         proc_macro_path_invoc,
         profiler_runtime,
+        ptr_guaranteed_eq,
+        ptr_guaranteed_ne,
         ptr_offset_from,
         pub_restricted,
         pure,
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 3ec6973a17d..ef6c7c14404 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
         | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
         | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
         | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
-        | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
-            hir::Unsafety::Normal
-        }
+        | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
+        | "maxnumf64" | "type_name" => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
 }
@@ -258,6 +257,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
+            }
+
             "ptr_offset_from" => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
             }
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index cf5f2ec69d8..3dd9c9c5c39 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -10,8 +10,7 @@ use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
@@ -303,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
             GenericParamKind::Const { ty: ref hir_ty, .. } => {
                 let ty = icx.to_ty(hir_ty);
-                if !tcx.features().const_compare_raw_pointers {
-                    let err = match ty.peel_refs().kind {
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => None,
-                    };
-                    if let Some(unsupported_type) = err {
-                        feature_err(
-                            &tcx.sess.parse_sess,
-                            sym::const_compare_raw_pointers,
+                let err = match ty.peel_refs().kind {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                };
+                if let Some(unsupported_type) = err {
+                    tcx.sess
+                        .struct_span_err(
                             hir_ty.span,
                             &format!(
-                                "using {} as const generic parameters is unstable",
+                                "using {} as const generic parameters is forbidden",
                                 unsupported_type
                             ),
                         )
                         .emit();
-                    };
-                }
+                };
                 if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
                     .is_some()
                 {
diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs
index afa577fa67f..90c438b05cb 100644
--- a/src/test/ui/const-generics/fn-const-param-call.rs
+++ b/src/test/ui/const-generics/fn-const-param-call.rs
@@ -1,15 +1,14 @@
-// run-pass
-
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 fn function() -> u32 {
     17
 }
 
-struct Wrapper<const F: fn() -> u32>;
+struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
 
 impl<const F: fn() -> u32> Wrapper<F> {
+//~^ ERROR: using function pointers as const generic parameters
     fn call() -> u32 {
         F()
     }
diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr
index 9c0f7e3ab9b..b5811243caa 100644
--- a/src/test/ui/const-generics/fn-const-param-call.stderr
+++ b/src/test/ui/const-generics/fn-const-param-call.stderr
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-const-param-call.rs:3:12
+  --> $DIR/fn-const-param-call.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:8:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:10:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs
index 08f6e0db31c..14fa3b494b3 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.rs
+++ b/src/test/ui/const-generics/fn-const-param-infer.rs
@@ -1,7 +1,8 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 struct Checked<const F: fn(usize) -> bool>;
+//~^ ERROR: using function pointers as const generic parameters
 
 fn not_one(val: usize) -> bool { val != 1 }
 fn not_two(val: usize) -> bool { val != 2 }
@@ -13,14 +14,14 @@ fn generic<T>(val: usize) -> bool { val != 1 }
 fn main() {
     let _: Option<Checked<not_one>> = None;
     let _: Checked<not_one> = Checked::<not_one>;
-    let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
+    let _: Checked<not_one> = Checked::<not_two>;
 
     let _ = Checked::<generic_arg>;
     let _ = Checked::<{generic_arg::<usize>}>;
-    let _ = Checked::<{generic_arg::<u32>}>;  //~ mismatched types
+    let _ = Checked::<{generic_arg::<u32>}>;
 
-    let _ = Checked::<generic>; //~ type annotations needed
+    let _ = Checked::<generic>;
     let _ = Checked::<{generic::<u16>}>;
     let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
-    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
+    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
 }
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
index de41d2984a6..7aaa41eb7d7 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -1,46 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/fn-const-param-infer.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:16:31
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:4:25
    |
-LL |     let _: Checked<not_one> = Checked::<not_two>;
-   |                               ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
-   |
-   = note: expected type `{not_one as fn(usize) -> bool}`
-              found type `{not_two as fn(usize) -> bool}`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:20:24
-   |
-LL |     let _ = Checked::<{generic_arg::<u32>}>;
-   |                        ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
-   |
-   = note: expected fn pointer `fn(usize) -> _`
-                 found fn item `fn(u32) -> _ {generic_arg::<u32>}`
-
-error[E0282]: type annotations needed
-  --> $DIR/fn-const-param-infer.rs:22:23
-   |
-LL |     let _ = Checked::<generic>;
-   |                       ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:25:40
-   |
-LL |     let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
-   |
-   = note: expected type `{generic::<u32> as fn(usize) -> bool}`
-              found type `{generic::<u16> as fn(usize) -> bool}`
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
index c498bfe2e97..97ca9d6a44c 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs
@@ -1,12 +1,11 @@
-// run-pass
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 const A: u32 = 3;
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
-impl<const P: *const u32> Const<P> {
+impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
     fn get() -> u32 {
         unsafe {
             *P
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
index 1ffc63ffdac..1ce8bb9c054 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-ptr-const-param-deref.rs:2:12
+  --> $DIR/raw-ptr-const-param-deref.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:6:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:8:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs
index d7d970e952b..237b410e073 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.rs
+++ b/src/test/ui/const-generics/raw-ptr-const-param.rs
@@ -1,9 +1,9 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
 fn main() {
-    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
+    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
     let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
 }
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr
index 7a665397c12..6e64f8a327f 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr
@@ -1,21 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/raw-ptr-const-param.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/raw-ptr-const-param.rs:7:40
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:4:23
    |
-LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
-   |
-   = note: expected type `{0xf as *const u32}`
-              found type `{0xa as *const u32}`
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
index 9be1374f85d..e238e13b8e2 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
@@ -1,17 +1,6 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
-
 fn main() {}
 
 // unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
-// unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
-// unconst and fine
-const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
-// unconst and bad, will thus error in miri
-const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
-// unconst and fine
-const Z: i32 = unsafe { *(&1 as *const i32) };
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
 // unconst and bad, will thus error in miri
-const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
-const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
index cc40728e6b5..21d3f5e7e85 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
@@ -1,44 +1,18 @@
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:6:26
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:4:26
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
-   | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[deny(const_err)]` on by default
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:8:27
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:6:27
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
-   | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                           |
-   |                           "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:12:28
-   |
-LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
-   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
-   |                            |
-   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:16:26
-   |
-LL | const Z2: i32 = unsafe { *(42 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:17:26
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | const Z3: i32 = unsafe { *(44 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
new file mode 100644
index 00000000000..d2a7623837a
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
@@ -0,0 +1,13 @@
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+
+fn main() {}
+
+// unconst and fine
+const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
+// unconst and bad, will thus error in miri
+const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
+// unconst and fine
+const Z: i32 = unsafe { *(&1 as *const i32) };
+// unconst and bad, will thus error in miri
+const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
+const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
new file mode 100644
index 00000000000..93f2261745d
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
@@ -0,0 +1,28 @@
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:8:28
+   |
+LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
+   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
+   |                            |
+   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:12:26
+   |
+LL | const Z2: i32 = unsafe { *(42 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:13:26
+   |
+LL | const Z3: i32 = unsafe { *(44 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
index c6fb5eeab5a..d724fe3060b 100644
--- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
+++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
@@ -1,4 +1,4 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
 
 fn main() {
     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
index 805ba9c6b03..21f11dda5a6 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -12,7 +12,7 @@ LL |     let _v = x + 0;
 
 warning: skipping const checks
    |
-help: skipping check for `const_compare_raw_pointers` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/ptr_arith.rs:9:14
    |
 LL |     let _v = x == x;
diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs
new file mode 100644
index 00000000000..fd843105daf
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/slice_eq.rs
@@ -0,0 +1,17 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+// run-pass
+
+#![feature(const_raw_ptr_comparison)]
+
+const EMPTY_SLICE: &[i32] = &[];
+const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
+const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
+const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
+const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
+
+fn main() {
+    assert!(!EMPTY_EQ);
+    assert!(!EMPTY_EQ2);
+    assert!(!EMPTY_NE);
+    assert!(!EMPTY_NE2);
+}
diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs
index bbefff27d7f..d2edd97efb2 100644
--- a/src/test/ui/error-codes/E0395.rs
+++ b/src/test/ui/error-codes/E0395.rs
@@ -1,10 +1,8 @@
-// gate-test-const_compare_raw_pointers
-
 static FOO: i32 = 42;
 static BAR: i32 = 42;
 
 static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR comparing raw pointers inside static
+//~^ ERROR pointers cannot be reliably compared during const eval
 
 fn main() {
 }
diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr
index 20c8622f337..674cc696450 100644
--- a/src/test/ui/error-codes/E0395.stderr
+++ b/src/test/ui/error-codes/E0395.stderr
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside static
-  --> $DIR/E0395.rs:6:29
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/E0395.rs:4:29
    |
 LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
index 1ab11ce3b44..dc602ba7e6f 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
@@ -1,9 +1,9 @@
 struct ConstFn<const F: fn()>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is unstable
+//~^^ ERROR using function pointers as const generic parameters is forbidden
 
 struct ConstPtr<const P: *const u32>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is unstable
+//~^^ ERROR using raw pointers as const generic parameters is forbidden
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
index dc7ef55e7ab..b2c96d3810f 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
@@ -16,23 +16,17 @@ LL | struct ConstPtr<const P: *const u32>;
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
-error[E0658]: using function pointers as const generic parameters is unstable
+error: using function pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:1:25
    |
 LL | struct ConstFn<const F: fn()>;
    |                         ^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
-error[E0658]: using raw pointers as const generic parameters is unstable
+error: using raw pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:5:26
    |
 LL | struct ConstPtr<const P: *const u32>;
    |                          ^^^^^^^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs
index 36a69cf4c22..d1093c20579 100644
--- a/src/test/ui/issues/issue-25826.rs
+++ b/src/test/ui/issues/issue-25826.rs
@@ -1,6 +1,6 @@
 fn id<T>(t: T) -> T { t }
 fn main() {
     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
-    //~^ ERROR comparing raw pointers inside constant
+    //~^ ERROR pointers cannot be reliably compared during const eval
     println!("{}", A);
 }
diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr
index 3a5a6b509ba..67d1b3ab9be 100644
--- a/src/test/ui/issues/issue-25826.stderr
+++ b/src/test/ui/issues/issue-25826.stderr
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside constant
+error: pointers cannot be reliably compared during const eval.
   --> $DIR/issue-25826.rs:3:30
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
index d9d85ee9132..963d892931a 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
@@ -1,13 +1,13 @@
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
-#![feature(const_compare_raw_pointers)]
+#![feature(const_raw_ptr_deref)]
 #![feature(const_fn)]
 
 #[stable(feature = "foo", since = "1.33.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-const fn unstable(a: *const i32, b: *const i32) -> bool {
-    a == b
-    //~^ pointer operation is unsafe
+const fn unstable(a: *const i32, b: i32) -> bool {
+    *a == b
+    //~^ dereference of raw pointer is unsafe
 }
 
 fn main() {}
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
index d8f3737c8f5..4642a7a5fc9 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
@@ -1,10 +1,10 @@
-error[E0133]: pointer operation is unsafe and requires unsafe function or block
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
   --> $DIR/unsafe-unstable-const-fn.rs:9:5
    |
-LL |     a == b
-   |     ^^^^^^ pointer operation
+LL |     *a == b
+   |     ^^ dereference of raw pointer
    |
-   = note: operations on pointers in constants
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index d9320e9147c..3fa637b5a69 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -444,10 +444,7 @@ fn map_lib_features(
                         level: Status::Unstable,
                         since: None,
                         has_gate_test: false,
-                        // FIXME(#57563): #57563 is now used as a common tracking issue,
-                        // although we would like to have specific tracking issues for each
-                        // `rustc_const_unstable` in the future.
-                        tracking_issue: NonZeroU32::new(57563),
+                        tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
                     };
                     mf(Ok((feature_name, feature)), file, i + 1);
                     continue;