Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

downgrade ptr.is_aligned_to crate-private #121920

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 13 additions & 104 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1501,116 +1501,25 @@ impl<T: ?Sized> *const T {
/// For non-`Sized` pointees this operation considers only the data pointer,
/// ignoring the metadata.
///
/// # Panics
///
/// The function panics if `align` is not a power-of-two (this includes 0).
///
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
/// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// This is an internal implementation detail of the stdlib, for implementing
/// low-level things like assert_unsafe_precondition.
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *const u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
/// # Safety
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
/// The return value is unspecified if `align` isn't a power of two.
#[must_use]
#[inline]
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {
panic!("is_aligned_to: align is not a power-of-two");
}

pub(crate) const fn is_aligned_to(self, align: usize) -> bool {
#[inline]
fn runtime_impl(ptr: *const (), align: usize) -> bool {
// classic bitmath magic trick:
//
// * a power of two is a single bit set like 00001000
// * multiples of that must have all those low 0's also clear
// * subtracting one from the power gets you 00000111
// * so if we AND that with a multiple, we should get 0
//
// Note we get to assume align is a power of two
ptr.addr() & (align - 1) == 0
}

Expand Down
135 changes: 1 addition & 134 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1764,140 +1764,7 @@ impl<T: ?Sized> *mut T {
where
T: Sized,
{
self.is_aligned_to(mem::align_of::<T>())
}

/// Returns whether the pointer is aligned to `align`.
///
/// For non-`Sized` pointees this operation considers only the data pointer,
/// ignoring the metadata.
///
/// # Panics
///
/// The function panics if `align` is not a power-of-two (this includes 0).
///
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// let mut data = AlignedI32(42);
/// let ptr = &mut data as *mut AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
/// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
/// #![feature(const_mut_refs)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let mut data = AlignedI32(42);
/// let ptr = &mut data as *mut AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// // Also, note that mutable references are not allowed in the final value of constants.
/// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut();
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *mut u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[must_use]
#[inline]
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
pub const fn is_aligned_to(self, align: usize) -> bool {
if !align.is_power_of_two() {
panic!("is_aligned_to: align is not a power-of-two");
}

#[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) }
(self as *const T).is_aligned()
}
}

Expand Down
112 changes: 0 additions & 112 deletions library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1405,118 +1405,6 @@ impl<T: ?Sized> NonNull<T> {
{
self.pointer.is_aligned()
}

/// Returns whether the pointer is aligned to `align`.
///
/// For non-`Sized` pointees this operation considers only the data pointer,
/// ignoring the metadata.
///
/// # Panics
///
/// The function panics if `align` is not a power-of-two (this includes 0).
///
/// # Examples
///
/// ```
/// #![feature(pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
/// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
///
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
/// ```
///
/// # At compiletime
/// **Note: Alignment at compiletime is experimental and subject to change. See the
/// [tracking issue] for details.**
///
/// At compiletime, the compiler may not know where a value will end up in memory.
/// Calling this function on a pointer created from a reference at compiletime will only
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// const _: () = {
/// let data = AlignedI32(42);
/// let ptr = &data as *const AlignedI32;
///
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
///
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
/// assert!(!ptr.is_aligned_to(8));
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
/// };
/// ```
///
/// 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.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// // On some platforms, the alignment of i32 is less than 4.
/// #[repr(align(4))]
/// struct AlignedI32(i32);
///
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
///
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
/// let runtime_ptr = COMPTIME_PTR;
/// assert_ne!(
/// runtime_ptr.is_aligned_to(8),
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
/// );
/// ```
///
/// If a pointer is created from a fixed address, this function behaves the same during
/// runtime and compiletime.
///
/// ```
/// #![feature(pointer_is_aligned)]
/// #![feature(const_pointer_is_aligned)]
///
/// const _: () = {
/// let ptr = 40 as *const u8;
/// assert!(ptr.is_aligned_to(1));
/// assert!(ptr.is_aligned_to(2));
/// assert!(ptr.is_aligned_to(4));
/// assert!(ptr.is_aligned_to(8));
/// assert!(!ptr.is_aligned_to(16));
/// };
/// ```
///
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
#[must_use]
#[inline]
pub const fn is_aligned_to(self, align: usize) -> bool {
self.pointer.is_aligned_to(align)
}
}

impl<T> NonNull<[T]> {
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/slice/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ const fn is_ascii(s: &[u8]) -> bool {
// have alignment information it should have given a `usize::MAX` for
// `align_offset` earlier, sending things through the scalar path instead of
// this one, so this check should pass if it's reachable.
debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
debug_assert!(word_ptr.is_aligned());

// Read subsequent words until the last aligned word, excluding the last
// aligned word by itself to be done in tail check later, to ensure that
Expand Down
Loading
Loading