Auto merge of #101483 - oli-obk:guaranteed_opt, r=fee1-dead
The `<*const T>::guaranteed_*` methods now return an option for the unknown case cc https://github.com/rust-lang/rust/issues/53020#issuecomment-1236932443 I chose `0` for "not equal" and `1` for "equal" and left `2` for the unknown case so backends can just forward to raw pointer equality and it works ✨ r? `@fee1-dead` or `@lcnr` cc `@rust-lang/wg-const-eval`
This commit is contained in:
commit
5197c96c49
12 changed files with 119 additions and 138 deletions
|
@ -2013,21 +2013,24 @@ extern "rust-intrinsic" {
|
|||
pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
|
||||
|
||||
/// See documentation of `<*const T>::guaranteed_eq` for details.
|
||||
/// Returns `2` if the result is unknown.
|
||||
/// Returns `1` if the pointers are guaranteed equal
|
||||
/// Returns `0` if the pointers are guaranteed inequal
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
|
||||
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[cfg(bootstrap)]
|
||||
pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
|
||||
|
||||
/// See documentation of `<*const T>::guaranteed_ne` for details.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[cfg(bootstrap)]
|
||||
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
|
||||
|
||||
/// Allocates a block of memory at compile time.
|
||||
|
@ -2213,6 +2216,16 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
|
|||
diff >= size
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 {
|
||||
match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) {
|
||||
(false, false) => 2,
|
||||
(true, false) => 1,
|
||||
(false, true) => 0,
|
||||
(true, true) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
|
||||
/// and destination must *not* overlap.
|
||||
///
|
||||
|
|
|
@ -36,7 +36,10 @@ impl<T: ?Sized> *const T {
|
|||
pub const fn is_null(self) -> bool {
|
||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||
// considering their "data" part for null-ness.
|
||||
(self as *const u8).guaranteed_eq(null())
|
||||
match (self as *const u8).guaranteed_eq(null()) {
|
||||
None => false,
|
||||
Some(res) => res,
|
||||
}
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
|
@ -770,20 +773,16 @@ impl<T: ?Sized> *const T {
|
|||
|
||||
/// Returns whether two pointers are guaranteed to be equal.
|
||||
///
|
||||
/// At runtime this function behaves like `self == other`.
|
||||
/// At runtime this function behaves like `Some(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.
|
||||
/// spuriously return `None` for pointers that later actually turn out to have its equality known.
|
||||
/// But when it returns `Some`, the pointers' equality is guaranteed to be known.
|
||||
///
|
||||
/// 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 must not
|
||||
/// The return value may change from `Some` to `None` and vice versa depending on the compiler
|
||||
/// version and unsafe code must 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
|
||||
/// for performance optimizations where spurious `None` 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
|
||||
|
@ -792,29 +791,28 @@ impl<T: ?Sized> *const T {
|
|||
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[inline]
|
||||
pub const fn guaranteed_eq(self, other: *const T) -> bool
|
||||
pub const fn guaranteed_eq(self, other: *const T) -> Option<bool>
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::ptr_guaranteed_eq(self, other)
|
||||
match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
|
||||
2 => None,
|
||||
other => Some(other == 1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether two pointers are guaranteed to be unequal.
|
||||
/// Returns whether two pointers are guaranteed to be inequal.
|
||||
///
|
||||
/// At runtime this function behaves like `self != other`.
|
||||
/// At runtime this function behaves like `Some(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 unequal.
|
||||
/// But when it returns `true`, the pointers are guaranteed to be unequal.
|
||||
/// it is not always possible to determine inequality of two pointers, so this function may
|
||||
/// spuriously return `None` for pointers that later actually turn out to have its inequality known.
|
||||
/// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
|
||||
///
|
||||
/// 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 must not
|
||||
/// The return value may change from `Some` to `None` and vice versa depending on the compiler
|
||||
/// version and unsafe code must 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
|
||||
/// for performance optimizations where spurious `None` 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
|
||||
|
@ -823,11 +821,14 @@ impl<T: ?Sized> *const T {
|
|||
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[inline]
|
||||
pub const fn guaranteed_ne(self, other: *const T) -> bool
|
||||
pub const fn guaranteed_ne(self, other: *const T) -> Option<bool>
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::ptr_guaranteed_ne(self, other)
|
||||
match self.guaranteed_eq(other) {
|
||||
None => None,
|
||||
Some(eq) => Some(!eq),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
|
|
|
@ -35,7 +35,10 @@ impl<T: ?Sized> *mut T {
|
|||
pub const fn is_null(self) -> bool {
|
||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||
// considering their "data" part for null-ness.
|
||||
(self as *mut u8).guaranteed_eq(null_mut())
|
||||
match (self as *mut u8).guaranteed_eq(null_mut()) {
|
||||
None => false,
|
||||
Some(res) => res,
|
||||
}
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
|
@ -697,20 +700,16 @@ impl<T: ?Sized> *mut T {
|
|||
|
||||
/// Returns whether two pointers are guaranteed to be equal.
|
||||
///
|
||||
/// At runtime this function behaves like `self == other`.
|
||||
/// At runtime this function behaves like `Some(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.
|
||||
/// spuriously return `None` for pointers that later actually turn out to have its equality known.
|
||||
/// But when it returns `Some`, the pointers' equality is guaranteed to be known.
|
||||
///
|
||||
/// 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 might not
|
||||
/// The return value may change from `Some` to `None` and vice versa depending on the compiler
|
||||
/// version and unsafe code must 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
|
||||
/// for performance optimizations where spurious `None` 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
|
||||
|
@ -719,29 +718,25 @@ impl<T: ?Sized> *mut T {
|
|||
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[inline]
|
||||
pub const fn guaranteed_eq(self, other: *mut T) -> bool
|
||||
pub const fn guaranteed_eq(self, other: *mut T) -> Option<bool>
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
|
||||
(self as *const T).guaranteed_eq(other as _)
|
||||
}
|
||||
|
||||
/// Returns whether two pointers are guaranteed to be unequal.
|
||||
/// Returns whether two pointers are guaranteed to be inequal.
|
||||
///
|
||||
/// At runtime this function behaves like `self != other`.
|
||||
/// At runtime this function behaves like `Some(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 unequal.
|
||||
/// But when it returns `true`, the pointers are guaranteed to be unequal.
|
||||
/// it is not always possible to determine inequality of two pointers, so this function may
|
||||
/// spuriously return `None` for pointers that later actually turn out to have its inequality known.
|
||||
/// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
|
||||
///
|
||||
/// 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 might not
|
||||
/// The return value may change from `Some` to `None` and vice versa depending on the compiler
|
||||
/// version and unsafe code must 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
|
||||
/// for performance optimizations where spurious `None` 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
|
||||
|
@ -750,11 +745,11 @@ impl<T: ?Sized> *mut T {
|
|||
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
#[inline]
|
||||
pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
|
||||
pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
|
||||
(self as *const T).guaranteed_ne(other as _)
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue