From c8c91f757ab82b4ccb5bed42927163cca6fbf90a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 4 Apr 2022 14:36:49 +0400 Subject: [PATCH 1/5] Add convenience functions to pointers The functions added: - {*const T,*mut T}::{wrapping_,}byte_{offset,add,sub} - {*const T,*mut T}::{byte_offset_from,is_aligned,is_aligned_to} --- library/core/src/ptr/const_ptr.rs | 161 +++++++++++++++++++++++++++++- library/core/src/ptr/mut_ptr.rs | 161 +++++++++++++++++++++++++++++- 2 files changed, 320 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 028adc796e5..8e127c350cc 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -455,6 +455,25 @@ pub const fn to_raw_parts(self) -> (*const (), ::Metadata) unsafe { intrinsics::offset(self, count) } } + /// Calculates the offset from a pointer in bytes. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset][pointer::offset] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_offset(self, count: isize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.cast::().offset(count).cast::() } + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -517,6 +536,24 @@ pub const fn wrapping_offset(self, count: isize) -> *const T unsafe { intrinsics::arith_offset(self, count) } } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method + /// for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_offset(self, count: isize) -> Self + where + T: Sized, + { + self.cast::().wrapping_offset(count).cast::() + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::()`. /// @@ -611,6 +648,23 @@ pub const fn wrapping_offset(self, count: isize) -> *const T unsafe { intrinsics::ptr_offset_from(self, origin) } } + /// Calculates the distance between two pointers. The returned value is in + /// units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset_from][pointer::offset_from] on it. See that method for + /// documentation and safety requirements. + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { self.cast::().offset_from(origin.cast::()) } + } + /// Calculates the distance between two pointers, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. @@ -813,6 +867,25 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool unsafe { self.offset(count as isize) } } + /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [add][pointer::add] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_add(self, count: usize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `add`. + unsafe { self.cast::().add(count).cast::() } + } + /// Calculates the offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// @@ -877,6 +950,26 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool unsafe { self.offset((count as isize).wrapping_neg()) } } + /// Calculates the offset from a pointer in bytes (convenience for + /// `.byte_offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [sub][pointer::sub] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_sub(self, count: usize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `sub`. + unsafe { self.cast::().sub(count).cast::() } + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset(count as isize)`) /// @@ -939,6 +1032,24 @@ pub const fn wrapping_add(self, count: usize) -> Self self.wrapping_offset(count as isize) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_add(self, count: usize) -> Self + where + T: Sized, + { + self.cast::().wrapping_add(count).cast::() + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// @@ -1001,6 +1112,24 @@ pub const fn wrapping_sub(self, count: usize) -> Self self.wrapping_offset((count as isize).wrapping_neg()) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_sub(self, count: usize) -> Self + where + T: Sized, + { + self.cast::().wrapping_sub(count).cast::() + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// @@ -1154,12 +1283,42 @@ const fn ctfe_impl(_: *const T, _: usize) -> usize { } // SAFETY: - // It is permisseble for `align_offset` to always return `usize::MAX`, + // 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) } } + + /// Returns whether the pointer is properly aligned for `T`. + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "none")] + pub fn is_aligned(self) -> bool + where + T: Sized, + { + self.addr() % core::mem::align_of::() == 0 + } + + /// Returns whether the pointer is aligned to `align`. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two (this includes 0). + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "none")] + pub fn is_aligned_to(self, align: usize) -> bool + where + T: Sized, + { + if !align.is_power_of_two() { + panic!("is_aligned_to: align is not a power-of-two"); + } + + self.addr() % align == 0 + } } impl *const [T] { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 1a32dd62dfd..20a757101e4 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -467,6 +467,25 @@ pub const fn to_raw_parts(self) -> (*mut (), ::Metadata) { unsafe { intrinsics::offset(self, count) as *mut T } } + /// Calculates the offset from a pointer in bytes. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset][pointer::offset] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_offset(self, count: isize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.cast::().offset(count).cast::() } + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -528,6 +547,24 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T unsafe { intrinsics::arith_offset(self, count) as *mut T } } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method + /// for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_offset(self, count: isize) -> Self + where + T: Sized, + { + self.cast::().wrapping_offset(count).cast::() + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] /// must be used instead. @@ -787,6 +824,23 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool unsafe { (self as *const T).offset_from(origin) } } + /// Calculates the distance between two pointers. The returned value is in + /// units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset_from][pointer::offset_from] on it. See that method for + /// documentation and safety requirements. + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { self.cast::().offset_from(origin.cast::()) } + } + /// Calculates the distance between two pointers, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. @@ -922,6 +976,25 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool unsafe { self.offset(count as isize) } } + /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [add][pointer::add] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_add(self, count: usize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `add`. + unsafe { self.cast::().add(count).cast::() } + } + /// Calculates the offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// @@ -986,6 +1059,26 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool unsafe { self.offset((count as isize).wrapping_neg()) } } + /// Calculates the offset from a pointer in bytes (convenience for + /// `.byte_offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [sub][pointer::sub] on it. See that method for documentation + /// and safety requirements. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const unsafe fn byte_sub(self, count: usize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `sub`. + unsafe { self.cast::().sub(count).cast::() } + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset(count as isize)`) /// @@ -1048,6 +1141,24 @@ pub const fn wrapping_add(self, count: usize) -> Self self.wrapping_offset(count as isize) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_add(self, count: usize) -> Self + where + T: Sized, + { + self.cast::().wrapping_add(count).cast::() + } + /// Calculates the offset from a pointer using wrapping arithmetic. /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) /// @@ -1110,6 +1221,24 @@ pub const fn wrapping_sub(self, count: usize) -> Self self.wrapping_offset((count as isize).wrapping_neg()) } + /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + #[must_use] + #[inline(always)] + #[unstable(feature = "pointer_byte_offsets", issue = "none")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + pub const fn wrapping_byte_sub(self, count: usize) -> Self + where + T: Sized, + { + self.cast::().wrapping_sub(count).cast::() + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// @@ -1420,12 +1549,42 @@ const fn ctfe_impl(_: *mut T, _: usize) -> usize { } // SAFETY: - // It is permisseble for `align_offset` to always return `usize::MAX`, + // 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) } } + + /// Returns whether the pointer is properly aligned for `T`. + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "none")] + pub fn is_aligned(self) -> bool + where + T: Sized, + { + self.addr() % core::mem::align_of::() == 0 + } + + /// Returns whether the pointer is aligned to `align`. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two (this includes 0). + #[must_use] + #[inline] + #[unstable(feature = "pointer_is_aligned", issue = "none")] + pub fn is_aligned_to(self, align: usize) -> bool + where + T: Sized, + { + if !align.is_power_of_two() { + panic!("is_aligned_to: align is not a power-of-two"); + } + + self.addr() % align == 0 + } } impl *mut [T] { From a908eec4389137bcaefb2bad6eb1efb34cb1be2d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 4 Apr 2022 15:11:16 +0400 Subject: [PATCH 2/5] Lift the `Sized` requirement from convenience ptr fns Since they work on byte pointers (by `.cast::()`ing them), there is no need to know the size of `T` and so there is no need for `T: Sized`. The `is_aligned_to` is similar, though it doesn't need the _alignment_ of `T`. --- library/core/src/ptr/const_ptr.rs | 82 +++++++++++++++-------------- library/core/src/ptr/mut_ptr.rs | 85 +++++++++++++++++-------------- 2 files changed, 89 insertions(+), 78 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8e127c350cc..0d936eacc51 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -462,16 +462,17 @@ pub const fn to_raw_parts(self) -> (*const (), ::Metadata) /// This is purely a convenience for casting to a `u8` pointer and /// using [offset][pointer::offset] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_offset(self, count: isize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { self.cast::().offset(count).cast::() } + let this = unsafe { self.cast::().offset(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -543,15 +544,15 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method /// for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_offset(self, count: isize) -> Self - where - T: Sized, - { - self.cast::().wrapping_offset(count).cast::() + pub const fn wrapping_byte_offset(self, count: isize) -> Self { + from_raw_parts::(self.cast::().wrapping_offset(count).cast::<()>(), metadata(self)) } /// Calculates the distance between two pointers. The returned value is in @@ -654,13 +655,13 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self /// This is purely a convenience for casting to a `u8` pointer and /// using [offset_from][pointer::offset_from] on it. See that method for /// documentation and safety requirements. + /// + /// For non-`Sized` pointees this operation considers only the data pointers, + /// ignoring the metadata. #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } } @@ -874,16 +875,17 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool /// This is purely a convenience for casting to a `u8` pointer and /// using [add][pointer::add] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_add(self, count: usize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. - unsafe { self.cast::().add(count).cast::() } + let this = unsafe { self.cast::().add(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) } /// Calculates the offset from a pointer (convenience for @@ -958,16 +960,17 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool /// This is purely a convenience for casting to a `u8` pointer and /// using [sub][pointer::sub] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_sub(self, count: usize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. - unsafe { self.cast::().sub(count).cast::() } + let this = unsafe { self.cast::().sub(count).cast::<()>() }; + from_raw_parts::(this, metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -1039,15 +1042,15 @@ pub const fn wrapping_add(self, count: usize) -> Self /// /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_add(self, count: usize) -> Self - where - T: Sized, - { - self.cast::().wrapping_add(count).cast::() + pub const fn wrapping_byte_add(self, count: usize) -> Self { + from_raw_parts::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -1119,15 +1122,15 @@ pub const fn wrapping_sub(self, count: usize) -> Self /// /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_sub(self, count: usize) -> Self - where - T: Sized, - { - self.cast::().wrapping_sub(count).cast::() + pub const fn wrapping_byte_sub(self, count: usize) -> Self { + from_raw_parts::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) } /// Reads the value from `self` without moving it. This leaves the @@ -1303,21 +1306,22 @@ pub fn is_aligned(self) -> bool /// 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). #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned", issue = "none")] - pub fn is_aligned_to(self, align: usize) -> bool - where - T: Sized, - { + pub 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"); } - self.addr() % align == 0 + // Cast is needed for `T: !Sized` + self.cast::().addr() % align == 0 } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 20a757101e4..d223d76ac3a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -474,16 +474,17 @@ pub const fn to_raw_parts(self) -> (*mut (), ::Metadata) { /// This is purely a convenience for casting to a `u8` pointer and /// using [offset][pointer::offset] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_offset(self, count: isize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { self.cast::().offset(count).cast::() } + let this = unsafe { self.cast::().offset(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -554,15 +555,18 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_offset][pointer::wrapping_offset] on it. See that method /// for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_offset(self, count: isize) -> Self - where - T: Sized, - { - self.cast::().wrapping_offset(count).cast::() + pub const fn wrapping_byte_offset(self, count: isize) -> Self { + from_raw_parts_mut::( + self.cast::().wrapping_offset(count).cast::<()>(), + metadata(self), + ) } /// Returns `None` if the pointer is null, or else returns a unique reference to @@ -830,13 +834,13 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// This is purely a convenience for casting to a `u8` pointer and /// using [offset_from][pointer::offset_from] on it. See that method for /// documentation and safety requirements. + /// + /// For non-`Sized` pointees this operation considers only the data pointers, + /// ignoring the metadata. #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize - where - T: Sized, - { + pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } } @@ -983,16 +987,17 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// This is purely a convenience for casting to a `u8` pointer and /// using [add][pointer::add] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_add(self, count: usize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. - unsafe { self.cast::().add(count).cast::() } + let this = unsafe { self.cast::().add(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) } /// Calculates the offset from a pointer (convenience for @@ -1067,16 +1072,17 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// This is purely a convenience for casting to a `u8` pointer and /// using [sub][pointer::sub] on it. See that method for documentation /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const unsafe fn byte_sub(self, count: usize) -> Self - where - T: Sized, - { + pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. - unsafe { self.cast::().sub(count).cast::() } + let this = unsafe { self.cast::().sub(count).cast::<()>() }; + from_raw_parts_mut::(this, metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -1148,15 +1154,15 @@ pub const fn wrapping_add(self, count: usize) -> Self /// /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_add][pointer::wrapping_add] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_add(self, count: usize) -> Self - where - T: Sized, - { - self.cast::().wrapping_add(count).cast::() + pub const fn wrapping_byte_add(self, count: usize) -> Self { + from_raw_parts_mut::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -1228,15 +1234,15 @@ pub const fn wrapping_sub(self, count: usize) -> Self /// /// This is purely a convenience for casting to a `u8` pointer and /// using [wrapping_sub][pointer::wrapping_sub] on it. See that method for documentation. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. #[must_use] #[inline(always)] #[unstable(feature = "pointer_byte_offsets", issue = "none")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] - pub const fn wrapping_byte_sub(self, count: usize) -> Self - where - T: Sized, - { - self.cast::().wrapping_sub(count).cast::() + pub const fn wrapping_byte_sub(self, count: usize) -> Self { + from_raw_parts_mut::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) } /// Reads the value from `self` without moving it. This leaves the @@ -1569,21 +1575,22 @@ pub fn is_aligned(self) -> bool /// 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). #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned", issue = "none")] - pub fn is_aligned_to(self, align: usize) -> bool - where - T: Sized, - { + pub 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"); } - self.addr() % align == 0 + // Cast is needed for `T: !Sized` + self.cast::().addr() % align == 0 } } From 6c1ebff59e5c92eadd1ed5d986c36e34791d6ed3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 15 Apr 2022 01:58:59 +0400 Subject: [PATCH 3/5] Implement `ptr.is_aligned()` in terms of `.is_aligned_to()` --- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mut_ptr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 0d936eacc51..9bbdfd1cbb5 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1301,7 +1301,7 @@ pub fn is_aligned(self) -> bool where T: Sized, { - self.addr() % core::mem::align_of::() == 0 + self.is_aligned_to(core::mem::align_of::()) } /// Returns whether the pointer is aligned to `align`. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d223d76ac3a..21220e2a486 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1570,7 +1570,7 @@ pub fn is_aligned(self) -> bool where T: Sized, { - self.addr() % core::mem::align_of::() == 0 + self.is_aligned_to(core::mem::align_of::()) } /// Returns whether the pointer is aligned to `align`. From 5a5d62aeb2a7be83bff34d6f4db4e1bbe7bd5a93 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 15 Apr 2022 02:00:45 +0400 Subject: [PATCH 4/5] Optimize `ptr.is_aligned_to()` Apparently LLVM is unable to understand that if count_ones() == 1 then self != 0. Adding `assume(align != 0)` helps generating better asm: https://rust.godbolt.org/z/ja18YKq91 --- library/core/src/ptr/const_ptr.rs | 3 +++ library/core/src/ptr/mut_ptr.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 9bbdfd1cbb5..824b3fad6c3 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1320,6 +1320,9 @@ pub fn is_aligned_to(self, align: usize) -> bool { panic!("is_aligned_to: align is not a power-of-two"); } + // SAFETY: `is_power_of_two()` will return `false` for zero. + unsafe { core::intrinsics::assume(align != 0) }; + // Cast is needed for `T: !Sized` self.cast::().addr() % align == 0 } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 21220e2a486..4613262dad9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1589,6 +1589,9 @@ pub fn is_aligned_to(self, align: usize) -> bool { panic!("is_aligned_to: align is not a power-of-two"); } + // SAFETY: `is_power_of_two()` will return `false` for zero. + unsafe { core::intrinsics::assume(align != 0) }; + // Cast is needed for `T: !Sized` self.cast::().addr() % align == 0 } From 03d45699390421d6a27f5ae2dc10077b38d950fe Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 21 Apr 2022 20:57:48 +0400 Subject: [PATCH 5/5] Fill-in tracking issues for features pointer_byte_offsets, const_pointer_byte_offsets and pointer_is_aligned --- library/core/src/ptr/const_ptr.rs | 32 +++++++++++++++---------------- library/core/src/ptr/mut_ptr.rs | 32 +++++++++++++++---------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 824b3fad6c3..f26fdc74ce1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -467,8 +467,8 @@ pub const fn to_raw_parts(self) -> (*const (), ::Metadata) /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. let this = unsafe { self.cast::().offset(count).cast::<()>() }; @@ -549,8 +549,8 @@ pub const fn wrapping_offset(self, count: isize) -> *const T /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_offset(self, count: isize) -> Self { from_raw_parts::(self.cast::().wrapping_offset(count).cast::<()>(), metadata(self)) } @@ -659,8 +659,8 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self { /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } @@ -880,8 +880,8 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. let this = unsafe { self.cast::().add(count).cast::<()>() }; @@ -965,8 +965,8 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. let this = unsafe { self.cast::().sub(count).cast::<()>() }; @@ -1047,8 +1047,8 @@ pub const fn wrapping_add(self, count: usize) -> Self /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_add(self, count: usize) -> Self { from_raw_parts::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) } @@ -1127,8 +1127,8 @@ pub const fn wrapping_sub(self, count: usize) -> Self /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_sub(self, count: usize) -> Self { from_raw_parts::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) } @@ -1296,7 +1296,7 @@ const fn ctfe_impl(_: *const T, _: usize) -> usize { /// Returns whether the pointer is properly aligned for `T`. #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "none")] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] pub fn is_aligned(self) -> bool where T: Sized, @@ -1314,7 +1314,7 @@ pub fn is_aligned(self) -> bool /// The function panics if `align` is not a power-of-two (this includes 0). #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "none")] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] pub 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"); diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 4613262dad9..37cf2ef4bfb 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -479,8 +479,8 @@ pub const fn to_raw_parts(self) -> (*mut (), ::Metadata) { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. let this = unsafe { self.cast::().offset(count).cast::<()>() }; @@ -560,8 +560,8 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_offset(self, count: isize) -> Self { from_raw_parts_mut::( self.cast::().wrapping_offset(count).cast::<()>(), @@ -838,8 +838,8 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::().offset_from(origin.cast::()) } @@ -992,8 +992,8 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. let this = unsafe { self.cast::().add(count).cast::<()>() }; @@ -1077,8 +1077,8 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. let this = unsafe { self.cast::().sub(count).cast::<()>() }; @@ -1159,8 +1159,8 @@ pub const fn wrapping_add(self, count: usize) -> Self /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_add(self, count: usize) -> Self { from_raw_parts_mut::(self.cast::().wrapping_add(count).cast::<()>(), metadata(self)) } @@ -1239,8 +1239,8 @@ pub const fn wrapping_sub(self, count: usize) -> Self /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "none")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "none")] + #[unstable(feature = "pointer_byte_offsets", issue = "96283")] + #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] pub const fn wrapping_byte_sub(self, count: usize) -> Self { from_raw_parts_mut::(self.cast::().wrapping_sub(count).cast::<()>(), metadata(self)) } @@ -1565,7 +1565,7 @@ const fn ctfe_impl(_: *mut T, _: usize) -> usize { /// Returns whether the pointer is properly aligned for `T`. #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "none")] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] pub fn is_aligned(self) -> bool where T: Sized, @@ -1583,7 +1583,7 @@ pub fn is_aligned(self) -> bool /// The function panics if `align` is not a power-of-two (this includes 0). #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "none")] + #[unstable(feature = "pointer_is_aligned", issue = "96284")] pub 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");