Add fuzzy pointer comparison intrinsics
This commit is contained in:
parent
9245ba8304
commit
e09b620339
14 changed files with 260 additions and 22 deletions
|
@ -1948,6 +1948,16 @@ extern "rust-intrinsic" {
|
||||||
#[cfg(not(bootstrap))]
|
#[cfg(not(bootstrap))]
|
||||||
#[lang = "count_code_region"]
|
#[lang = "count_code_region"]
|
||||||
pub fn count_code_region(index: u32);
|
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
|
// Some functions are defined here because they accidentally got made
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
#![feature(const_generics)]
|
#![feature(const_generics)]
|
||||||
#![feature(const_ptr_offset)]
|
#![feature(const_ptr_offset)]
|
||||||
#![feature(const_ptr_offset_from)]
|
#![feature(const_ptr_offset_from)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
|
||||||
#![feature(const_result)]
|
#![feature(const_result)]
|
||||||
#![feature(const_slice_from_raw_parts)]
|
#![feature(const_slice_from_raw_parts)]
|
||||||
#![feature(const_slice_ptr_len)]
|
#![feature(const_slice_ptr_len)]
|
||||||
|
|
|
@ -295,6 +295,72 @@ impl<T: ?Sized> *const T {
|
||||||
intrinsics::ptr_offset_from(self, origin)
|
intrinsics::ptr_offset_from(self, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether two pointers are guaranteed 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 not 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 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
|
/// 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>()`.
|
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -273,6 +273,72 @@ impl<T: ?Sized> *mut T {
|
||||||
if self.is_null() { None } else { Some(&mut *self) }
|
if self.is_null() { None } else { Some(&mut *self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether two pointers are guaranteed 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 not 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 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
|
/// 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>()`.
|
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -5946,7 +5946,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use an equal-pointer optimization when types are `Eq`
|
// Remove after boostrap bump
|
||||||
|
#[cfg(bootstrap)]
|
||||||
impl<A> SlicePartialEq<A> for [A]
|
impl<A> SlicePartialEq<A> for [A]
|
||||||
where
|
where
|
||||||
A: PartialEq<A> + Eq,
|
A: PartialEq<A> + Eq,
|
||||||
|
@ -5964,7 +5965,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use memcmp for bytewise equality when the types allow
|
// Remove after boostrap bump
|
||||||
|
#[cfg(bootstrap)]
|
||||||
impl<A> SlicePartialEq<A> for [A]
|
impl<A> SlicePartialEq<A> for [A]
|
||||||
where
|
where
|
||||||
A: PartialEq<A> + BytewiseEquality,
|
A: PartialEq<A> + BytewiseEquality,
|
||||||
|
@ -5983,6 +5985,50 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use an equal-pointer optimization when types are `Eq`
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
impl<A> SlicePartialEq<A> for [A]
|
||||||
|
where
|
||||||
|
A: PartialEq<A> + Eq,
|
||||||
|
{
|
||||||
|
default fn equal(&self, other: &[A]) -> bool {
|
||||||
|
if self.len() != other.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While performance would suffer if `guaranteed_eq` just returned `false`
|
||||||
|
// for all arguments, correctness and return value of this function are not affected.
|
||||||
|
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iter().zip(other.iter()).all(|(x, y)| x == y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use memcmp for bytewise equality when the types allow
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
impl<A> SlicePartialEq<A> for [A]
|
||||||
|
where
|
||||||
|
A: PartialEq<A> + BytewiseEquality,
|
||||||
|
{
|
||||||
|
fn equal(&self, other: &[A]) -> bool {
|
||||||
|
if self.len() != other.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While performance would suffer if `guaranteed_eq` just returned `false`
|
||||||
|
// for all arguments, correctness and return value of this function are not affected.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
// intermediate trait for specialization of slice's PartialOrd
|
// intermediate trait for specialization of slice's PartialOrd
|
||||||
trait SlicePartialOrd: Sized {
|
trait SlicePartialOrd: Sized {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use log::debug;
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
|
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::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::glue;
|
||||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||||
|
@ -731,6 +731,18 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
|
||||||
|
let a = args[0].immediate();
|
||||||
|
let b = args[1].immediate();
|
||||||
|
let a = self.ptrtoint(a, self.type_isize());
|
||||||
|
let b = self.ptrtoint(b, self.type_isize());
|
||||||
|
if name == "ptr_guaranteed_eq" {
|
||||||
|
self.icmp(IntPredicate::IntEQ, a, b)
|
||||||
|
} else {
|
||||||
|
self.icmp(IntPredicate::IntNE, a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"ptr_offset_from" => {
|
"ptr_offset_from" => {
|
||||||
let ty = substs.type_at(0);
|
let ty = substs.type_at(0);
|
||||||
let pointee_size = self.size_of(ty);
|
let pointee_size = self.size_of(ty);
|
||||||
|
|
|
@ -291,6 +291,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
|
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
|
||||||
self.write_scalar(offset_ptr, dest)?;
|
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 => {
|
sym::ptr_offset_from => {
|
||||||
let a = self.read_immediate(args[0])?.to_scalar()?;
|
let a = self.read_immediate(args[0])?.to_scalar()?;
|
||||||
let b = self.read_immediate(args[1])?.to_scalar()?;
|
let b = self.read_immediate(args[1])?.to_scalar()?;
|
||||||
|
|
|
@ -290,17 +290,23 @@ impl NonConstOp for RawPtrComparison {
|
||||||
"pointers cannot be compared in a meaningful way during const eval.",
|
"pointers cannot be compared in a meaningful way during const eval.",
|
||||||
);
|
);
|
||||||
err.note(
|
err.note(
|
||||||
"It is conceptually impossible for const eval to know in all cases whether two \
|
"see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
|
||||||
pointers are equal. While sometimes it is clear (the address of a static item \
|
for more information",
|
||||||
is never equal to the address of another static item), comparing an integer \
|
|
||||||
address with any allocation's address is impossible to do at compile-time.",
|
|
||||||
);
|
);
|
||||||
err.note(
|
err.note(
|
||||||
"That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all \
|
"It is conceptually impossible for const eval to know in all cases whether two \
|
||||||
comparisons where CTFE isn't sure whether two addresses are equal. The mirror \
|
pointers are equal. While sometimes it is clear (the address of a non-zst static item \
|
||||||
intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't \
|
is never equal to the address of another non-zst static item), comparing an integer \
|
||||||
sure whether two addresses are inequal.",
|
address with any allocation's address is impossible to do at compile-time.",
|
||||||
);
|
);
|
||||||
|
if ccx.tcx.sess.parse_sess.unstable_features.is_nightly_build() {
|
||||||
|
err.note(
|
||||||
|
"That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` \
|
||||||
|
for all comparisons where CTFE is sure that two addresses are equal. The mirror \
|
||||||
|
intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where \
|
||||||
|
CTFE is sure that two addresses are inequal.",
|
||||||
|
);
|
||||||
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -588,6 +588,8 @@ symbols! {
|
||||||
proc_macro_non_items,
|
proc_macro_non_items,
|
||||||
proc_macro_path_invoc,
|
proc_macro_path_invoc,
|
||||||
profiler_runtime,
|
profiler_runtime,
|
||||||
|
ptr_guaranteed_eq,
|
||||||
|
ptr_guaranteed_ne,
|
||||||
ptr_offset_from,
|
ptr_offset_from,
|
||||||
pub_restricted,
|
pub_restricted,
|
||||||
pure,
|
pure,
|
||||||
|
|
|
@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
|
||||||
| "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
|
| "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
|
||||||
| "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
|
| "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
|
||||||
| "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
|
| "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
|
||||||
| "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
|
| "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
|
||||||
hir::Unsafety::Normal
|
| "maxnumf64" | "type_name" => hir::Unsafety::Normal,
|
||||||
}
|
|
||||||
_ => hir::Unsafety::Unsafe,
|
_ => 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]))
|
(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" => {
|
"ptr_offset_from" => {
|
||||||
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
|
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval.
|
||||||
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
|
||||||
= note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal.
|
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
||||||
|
= note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal.
|
||||||
|
|
||||||
error: pointers cannot be compared in a meaningful way during const eval.
|
error: pointers cannot be compared in a meaningful way during const eval.
|
||||||
--> $DIR/const_raw_ptr_ops.rs:6:27
|
--> $DIR/const_raw_ptr_ops.rs:6:27
|
||||||
|
@ -13,8 +14,9 @@ error: pointers cannot be compared in a meaningful way during const eval.
|
||||||
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
|
||||||
= note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal.
|
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
||||||
|
= note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal.
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
17
src/test/ui/consts/miri_unleashed/slice_eq.rs
Normal file
17
src/test/ui/consts/miri_unleashed/slice_eq.rs
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval.
|
||||||
LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
|
LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
|
||||||
= note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal.
|
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
||||||
|
= note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal.
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval.
|
||||||
LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
|
LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
|
||||||
= note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal.
|
= note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time.
|
||||||
|
= note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal.
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue