use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics;
+use crate::intrinsics::{self, const_eval_select};
use crate::slice::{self, SliceIndex};
impl<T: ?Sized> *mut T {
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
#[inline]
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.
- match (self as *mut u8).guaranteed_eq(null_mut()) {
- None => false,
- Some(res) => res,
+ #[inline]
+ fn runtime_impl(ptr: *mut u8) -> bool {
+ ptr.addr() == 0
}
+
+ #[inline]
+ const fn const_impl(ptr: *mut u8) -> bool {
+ // Compare via a cast to a thin pointer, so fat pointers are only
+ // considering their "data" part for null-ness.
+ match (ptr).guaranteed_eq(null_mut()) {
+ None => false,
+ Some(res) => res,
+ }
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
}
/// Casts to a pointer of another type.
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
- pub fn addr(self) -> usize
- where
- T: Sized,
- {
+ pub fn addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
// provenance).
- unsafe { mem::transmute(self) }
+ unsafe { mem::transmute(self.cast::<()>()) }
}
/// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
- pub fn expose_addr(self) -> usize
- where
- T: Sized,
- {
+ pub fn expose_addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
- self as usize
+ self.cast::<()>() as usize
}
/// Creates a new pointer with the given address.
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
- pub fn with_addr(self, addr: usize) -> Self
- where
- T: Sized,
- {
+ pub fn with_addr(self, addr: usize) -> Self {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
//
// In the mean-time, this operation is defined to be "as if" it was
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
- pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self
- where
- T: Sized,
- {
+ pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
self.with_addr(f(self.addr()))
}
/// This computes the same value that [`offset_from`](#method.offset_from)
/// would compute, but with the added precondition that the offset is
/// guaranteed to be non-negative. This method is equivalent to
- /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`,
+ /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`,
/// but it provides slightly more information to the optimizer, which can
/// sometimes allow it to optimize slightly better with some backends.
///
panic!("align_offset: align is not a power-of-two");
}
- #[cfg(bootstrap)]
- {
- fn rt_impl<T>(p: *mut T, align: usize) -> usize {
- // SAFETY: `align` has been checked to be a power of 2 above
- unsafe { align_offset(p, align) }
- }
-
- const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
- usize::MAX
- }
-
- // SAFETY:
- // It is permissible for `align_offset` to always return `usize::MAX`,
- // algorithm correctness can not depend on `align_offset` returning non-max values.
- //
- // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
- unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
- }
-
- #[cfg(not(bootstrap))]
{
// SAFETY: `align` has been checked to be a power of 2 above
unsafe { align_offset(self, align) }
/// is never aligned if cast to a type with a stricter alignment than the reference's
/// underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
/// cannot be stricter aligned than the reference's underlying allocation.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
- #[cfg_attr(bootstrap, doc = "```ignore")]
- #[cfg_attr(not(bootstrap), doc = "```")]
+ /// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
panic!("is_aligned_to: align is not a power-of-two");
}
- // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
- // The cast to `()` is used to
- // 1. deal with fat pointers; and
- // 2. ensure that `align_offset` doesn't actually try to compute an offset.
- self.cast::<()>().align_offset(align) == 0
+ #[inline]
+ fn runtime_impl(ptr: *mut (), align: usize) -> bool {
+ ptr.addr() & (align - 1) == 0
+ }
+
+ #[inline]
+ const fn const_impl(ptr: *mut (), align: usize) -> bool {
+ // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
+ // The cast to `()` is used to
+ // 1. deal with fat pointers; and
+ // 2. ensure that `align_offset` doesn't actually try to compute an offset.
+ ptr.align_offset(align) == 0
+ }
+
+ // SAFETY: The two versions are equivalent at runtime.
+ unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
}
}