Skip to content

Commit

Permalink
Auto merge of #101483 - oli-obk:guaranteed_opt, r=fee1-dead
Browse files Browse the repository at this point in the history
The `<*const T>::guaranteed_*` methods now return an option for the unknown case

cc rust-lang/rust#53020 (comment)

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`
  • Loading branch information
bors committed Sep 10, 2022
2 parents 8aff01d + 2b991af commit c9c7c36
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 60 deletions.
25 changes: 19 additions & 6 deletions core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
///
Expand Down
55 changes: 28 additions & 27 deletions core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
///
/// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
/// 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.
///
/// [`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
Expand All @@ -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
Expand All @@ -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)`).
Expand Down
49 changes: 22 additions & 27 deletions core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
///
/// 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
/// 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.
///
/// 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
Expand All @@ -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.
///
/// 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
/// 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.
///
/// 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
Expand All @@ -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
Expand Down

0 comments on commit c9c7c36

Please sign in to comment.