Rollup merge of #102072 - scottmcm:ptr-alignment-type, r=thomcc

Add `ptr::Alignment` type

Essentially no new code here, just exposing the previously-`pub(crate)` `ValidAlign` type under the name from the ACP.

ACP: https://github.com/rust-lang/libs-team/issues/108
Tracking Issue: https://github.com/rust-lang/rust/issues/102070

r? ``@ghost``
This commit is contained in:
Yuki Okushi 2022-10-10 00:09:40 +09:00 committed by GitHub
commit 38db483af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 64 deletions

View File

@ -64,6 +64,7 @@ impl Layout {
#[stable(feature = "alloc_layout", since = "1.28.0")] #[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[inline] #[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> { pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if !align.is_power_of_two() { if !align.is_power_of_two() {
return Err(LayoutError); return Err(LayoutError);
@ -113,6 +114,7 @@ impl Layout {
#[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")] #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
#[must_use] #[must_use]
#[inline] #[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
// SAFETY: the caller is required to uphold the preconditions. // SAFETY: the caller is required to uphold the preconditions.
unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } } unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } }
@ -133,6 +135,7 @@ impl Layout {
#[must_use = "this returns the minimum alignment, \ #[must_use = "this returns the minimum alignment, \
without modifying the layout"] without modifying the layout"]
#[inline] #[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn align(&self) -> usize { pub const fn align(&self) -> usize {
self.align.as_usize() self.align.as_usize()
} }

View File

@ -152,6 +152,7 @@
#![feature(core_panic)] #![feature(core_panic)]
#![feature(duration_consts_float)] #![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array)]
#![feature(ptr_alignment_type)]
#![feature(ptr_metadata)] #![feature(ptr_metadata)]
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(slice_split_at_unchecked)] #![feature(slice_split_at_unchecked)]

View File

@ -21,11 +21,10 @@ mod maybe_uninit;
#[stable(feature = "maybe_uninit", since = "1.36.0")] #[stable(feature = "maybe_uninit", since = "1.36.0")]
pub use maybe_uninit::MaybeUninit; pub use maybe_uninit::MaybeUninit;
mod valid_align; // FIXME: This is left here for now to avoid complications around pending reverts.
// For now this type is left crate-local. It could potentially make sense to expose // Once <https://github.com/rust-lang/rust/issues/101899> is fully resolved,
// it publicly, as it would be a nice parameter type for methods which need to take // this should be removed and the references in `alloc::Layout` updated.
// alignment as a parameter, such as `Layout::padding_needed_for`. pub(crate) use ptr::Alignment as ValidAlign;
pub(crate) use valid_align::ValidAlign;
mod transmutability; mod transmutability;
#[unstable(feature = "transmutability", issue = "99571")] #[unstable(feature = "transmutability", issue = "99571")]

View File

@ -1,4 +1,4 @@
use crate::convert::TryFrom; use crate::convert::{TryFrom, TryInto};
use crate::intrinsics::assert_unsafe_precondition; use crate::intrinsics::assert_unsafe_precondition;
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::{cmp, fmt, hash, mem, num}; use crate::{cmp, fmt, hash, mem, num};
@ -8,16 +8,62 @@ use crate::{cmp, fmt, hash, mem, num};
/// ///
/// Note that particularly large alignments, while representable in this type, /// Note that particularly large alignments, while representable in this type,
/// are likely not to be supported by actual allocators and linkers. /// are likely not to be supported by actual allocators and linkers.
#[derive(Copy, Clone)] #[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct ValidAlign(ValidAlignEnum); pub struct Alignment(AlignmentEnum);
// ValidAlign is `repr(usize)`, but via extra steps. // Alignment is `repr(usize)`, but via extra steps.
const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>()); const _: () = assert!(mem::size_of::<Alignment>() == mem::size_of::<usize>());
const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>()); const _: () = assert!(mem::align_of::<Alignment>() == mem::align_of::<usize>());
impl ValidAlign { fn _alignment_can_be_structurally_matched(a: Alignment) -> bool {
/// Creates a `ValidAlign` from a power-of-two `usize`. matches!(a, Alignment::MIN)
}
impl Alignment {
/// The smallest possible alignment, 1.
///
/// All addresses are always aligned at least this much.
///
/// # Examples
///
/// ```
/// #![feature(ptr_alignment_type)]
/// use std::ptr::Alignment;
///
/// assert_eq!(Alignment::MIN.as_usize(), 1);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
pub const MIN: Self = Self(AlignmentEnum::_Align1Shl0);
/// Returns the alignment for a type.
///
/// This provides the same numerical value as [`mem::align_of`],
/// but in an `Alignment` instead of a `usize.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
unsafe { Alignment::new_unchecked(mem::align_of::<T>()) }
}
/// Creates an `Alignment` from a `usize`, or returns `None` if it's
/// not a power of two.
///
/// Note that `0` is not a power of two, nor a valid alignment.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
// SAFETY: Just checked it only has one bit set
Some(unsafe { Self::new_unchecked(align) })
} else {
None
}
}
/// Creates an `Alignment` from a power-of-two `usize`.
/// ///
/// # Safety /// # Safety
/// ///
@ -25,101 +71,99 @@ impl ValidAlign {
/// ///
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
/// It must *not* be zero. /// It must *not* be zero.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline] #[inline]
pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { pub const unsafe fn new_unchecked(align: usize) -> Self {
// SAFETY: Precondition passed to the caller. // SAFETY: Precondition passed to the caller.
unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) };
// SAFETY: By precondition, this must be a power of two, and // SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two. // our variants encompass all possible powers of two.
unsafe { mem::transmute::<usize, ValidAlign>(align) } unsafe { mem::transmute::<usize, Alignment>(align) }
} }
/// Returns the alignment as a [`NonZeroUsize`]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline] #[inline]
pub(crate) const fn as_usize(self) -> usize { pub const fn as_usize(self) -> usize {
self.0 as usize self.0 as usize
} }
/// Returns the alignment as a [`usize`]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline] #[inline]
pub(crate) const fn as_nonzero(self) -> NonZeroUsize { pub const fn as_nonzero(self) -> NonZeroUsize {
// SAFETY: All the discriminants are non-zero. // SAFETY: All the discriminants are non-zero.
unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
} }
/// Returns the base 2 logarithm of the alignment. /// Returns the base-2 logarithm of the alignment.
/// ///
/// This is always exact, as `self` represents a power of two. /// This is always exact, as `self` represents a power of two.
///
/// # Examples
///
/// ```
/// #![feature(ptr_alignment_type)]
/// use std::ptr::Alignment;
///
/// assert_eq!(Alignment::of::<u8>().log2(), 0);
/// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline] #[inline]
pub(crate) fn log2(self) -> u32 { pub fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros() self.as_nonzero().trailing_zeros()
} }
/// Returns the alignment for a type.
#[inline]
pub(crate) fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) }
}
} }
impl fmt::Debug for ValidAlign { #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::Debug for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2()) write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
} }
} }
impl TryFrom<NonZeroUsize> for ValidAlign { #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl TryFrom<NonZeroUsize> for Alignment {
type Error = num::TryFromIntError; type Error = num::TryFromIntError;
#[inline] #[inline]
fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> { fn try_from(align: NonZeroUsize) -> Result<Alignment, Self::Error> {
if align.is_power_of_two() { align.get().try_into()
// SAFETY: Just checked for power-of-two
unsafe { Ok(ValidAlign::new_unchecked(align.get())) }
} else {
Err(num::TryFromIntError(()))
}
} }
} }
impl TryFrom<usize> for ValidAlign { #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl TryFrom<usize> for Alignment {
type Error = num::TryFromIntError; type Error = num::TryFromIntError;
#[inline] #[inline]
fn try_from(align: usize) -> Result<ValidAlign, Self::Error> { fn try_from(align: usize) -> Result<Alignment, Self::Error> {
if align.is_power_of_two() { Self::new(align).ok_or(num::TryFromIntError(()))
// SAFETY: Just checked for power-of-two
unsafe { Ok(ValidAlign::new_unchecked(align)) }
} else {
Err(num::TryFromIntError(()))
}
} }
} }
impl cmp::Eq for ValidAlign {} #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl cmp::Ord for Alignment {
impl cmp::PartialEq for ValidAlign {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_nonzero() == other.as_nonzero()
}
}
impl cmp::Ord for ValidAlign {
#[inline] #[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering { fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_nonzero().cmp(&other.as_nonzero()) self.as_nonzero().cmp(&other.as_nonzero())
} }
} }
impl cmp::PartialOrd for ValidAlign { #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl cmp::PartialOrd for Alignment {
#[inline] #[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl hash::Hash for ValidAlign { #[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl hash::Hash for Alignment {
#[inline] #[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_nonzero().hash(state) self.as_nonzero().hash(state)
@ -127,15 +171,15 @@ impl hash::Hash for ValidAlign {
} }
#[cfg(target_pointer_width = "16")] #[cfg(target_pointer_width = "16")]
type ValidAlignEnum = ValidAlignEnum16; type AlignmentEnum = AlignmentEnum16;
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
type ValidAlignEnum = ValidAlignEnum32; type AlignmentEnum = AlignmentEnum32;
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
type ValidAlignEnum = ValidAlignEnum64; type AlignmentEnum = AlignmentEnum64;
#[derive(Copy, Clone)] #[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u16)] #[repr(u16)]
enum ValidAlignEnum16 { enum AlignmentEnum16 {
_Align1Shl0 = 1 << 0, _Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1, _Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2, _Align1Shl2 = 1 << 2,
@ -154,9 +198,9 @@ enum ValidAlignEnum16 {
_Align1Shl15 = 1 << 15, _Align1Shl15 = 1 << 15,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u32)] #[repr(u32)]
enum ValidAlignEnum32 { enum AlignmentEnum32 {
_Align1Shl0 = 1 << 0, _Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1, _Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2, _Align1Shl2 = 1 << 2,
@ -191,9 +235,9 @@ enum ValidAlignEnum32 {
_Align1Shl31 = 1 << 31, _Align1Shl31 = 1 << 31,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u64)] #[repr(u64)]
enum ValidAlignEnum64 { enum AlignmentEnum64 {
_Align1Shl0 = 1 << 0, _Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1, _Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2, _Align1Shl2 = 1 << 2,

View File

@ -377,6 +377,10 @@ use crate::intrinsics::{
use crate::mem::{self, MaybeUninit}; use crate::mem::{self, MaybeUninit};
mod alignment;
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
pub use alignment::Alignment;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)] #[doc(inline)]
pub use crate::intrinsics::copy_nonoverlapping; pub use crate::intrinsics::copy_nonoverlapping;