diff options
Diffstat (limited to '')
-rw-r--r-- | library/core/src/mem/maybe_uninit.rs | 54 | ||||
-rw-r--r-- | library/core/src/mem/mod.rs | 95 | ||||
-rw-r--r-- | library/core/src/mem/transmutability.rs | 88 | ||||
-rw-r--r-- | library/core/src/mem/valid_align.rs | 247 |
4 files changed, 188 insertions, 296 deletions
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4ea53608..7757c95de 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -54,9 +54,6 @@ use crate::slice; /// // The equivalent code with `MaybeUninit<i32>`: /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`] /// is considered initialized (under the current implementation; this does not constitute @@ -130,11 +127,8 @@ use crate::slice; /// MaybeUninit::uninit().assume_init() /// }; /// -/// // Dropping a `MaybeUninit` does nothing. Thus using raw pointer -/// // assignment instead of `ptr::write` does not cause the old -/// // uninitialized value to be dropped. Also if there is a panic during -/// // this loop, we have a memory leak, but there is no memory safety -/// // issue. +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. /// for elem in &mut data[..] { /// elem.write(vec![42]); /// } @@ -152,7 +146,6 @@ use crate::slice; /// /// ``` /// use std::mem::MaybeUninit; -/// use std::ptr; /// /// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is /// // safe because the type we are claiming to have initialized here is a @@ -168,7 +161,7 @@ use crate::slice; /// /// // For each item in the array, drop if we allocated it. /// for elem in &mut data[0..data_len] { -/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } +/// unsafe { elem.assume_init_drop(); } /// } /// ``` /// @@ -653,7 +646,7 @@ impl<T> MaybeUninit<T> { /// implements the [`Copy`] trait or not. When using multiple copies of the /// data (by calling `assume_init_read` multiple times, or first calling /// `assume_init_read` and then [`assume_init`]), it is your responsibility - /// to ensure that that data may indeed be duplicated. + /// to ensure that data may indeed be duplicated. /// /// [inv]: #initialization-invariant /// [`assume_init`]: MaybeUninit::assume_init @@ -1290,3 +1283,42 @@ impl<T> MaybeUninit<T> { } } } + +impl<T, const N: usize> MaybeUninit<[T; N]> { + /// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_uninit_array_transpose)] + /// # use std::mem::MaybeUninit; + /// + /// let data: [MaybeUninit<u8>; 1000] = MaybeUninit::uninit().transpose(); + /// ``` + #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")] + #[inline] + pub const fn transpose(self) -> [MaybeUninit<T>; N] { + // SAFETY: T and MaybeUninit<T> have the same layout + unsafe { super::transmute_copy(&ManuallyDrop::new(self)) } + } +} + +impl<T, const N: usize> [MaybeUninit<T>; N] { + /// Transposes a `[MaybeUninit<T>; N]` into a `MaybeUninit<[T; N]>`. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_uninit_array_transpose)] + /// # use std::mem::MaybeUninit; + /// + /// let data = [MaybeUninit::<u8>::uninit(); 1000]; + /// let data: MaybeUninit<[u8; 1000]> = data.transpose(); + /// ``` + #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")] + #[inline] + pub const fn transpose(self) -> MaybeUninit<[T; N]> { + // SAFETY: T and MaybeUninit<T> have the same layout + unsafe { super::transmute_copy(&ManuallyDrop::new(self)) } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 20b2d5e26..9195da5a4 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -21,11 +21,10 @@ mod maybe_uninit; #[stable(feature = "maybe_uninit", since = "1.36.0")] pub use maybe_uninit::MaybeUninit; -mod valid_align; -// For now this type is left crate-local. It could potentially make sense to expose -// it publicly, as it would be a nice parameter type for methods which need to take -// alignment as a parameter, such as `Layout::padding_needed_for`. -pub(crate) use valid_align::ValidAlign; +// FIXME: This is left here for now to avoid complications around pending reverts. +// Once <https://github.com/rust-lang/rust/issues/101899> is fully resolved, +// this should be removed and the references in `alloc::Layout` updated. +pub(crate) use ptr::Alignment as ValidAlign; mod transmutability; #[unstable(feature = "transmutability", issue = "99571")] @@ -665,14 +664,14 @@ pub unsafe fn zeroed<T>() -> T { /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit]. /// As the [`assume_init` documentation][assume_init] explains, /// [the Rust compiler assumes][inv] that values are properly initialized. -/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate -/// undefined behavior for returning a `bool` that is not definitely either `true` -/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// +/// Truly uninitialized memory like what gets returned here /// is special in that the compiler knows that it does not have a fixed value. /// This makes it undefined behavior to have uninitialized data in a variable even /// if that variable has an integer type. -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) +/// +/// Therefore, it is immediate undefined behavior to call this function on nearly all types, +/// including integer types and arrays of integer types, and even if the result is unused. /// /// [uninit]: MaybeUninit::uninit /// [assume_init]: MaybeUninit::assume_init @@ -1009,18 +1008,18 @@ pub fn copy<T: Copy>(x: &T) -> T { *x } -/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// Interprets `src` as having type `&Dst`, and then reads `src` without moving /// the contained value. /// -/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of] -/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way -/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also -/// unsafely create a copy of the contained value instead of moving out of `src`. +/// This function will unsafely assume the pointer `src` is valid for [`size_of::<Dst>`][size_of] +/// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done +/// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`). +/// It will also unsafely create a copy of the contained value instead of moving out of `src`. /// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers [undefined behavior][ub] if `U` is larger than -/// `T`. +/// It is not a compile-time error if `Src` and `Dst` have different sizes, but it +/// is highly encouraged to only invoke this function where `Src` and `Dst` have the +/// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than +/// `Src`. /// /// [ub]: ../../reference/behavior-considered-undefined.html /// @@ -1053,19 +1052,22 @@ pub fn copy<T: Copy>(x: &T) -> T { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] -pub const unsafe fn transmute_copy<T, U>(src: &T) -> U { - assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T"); +pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { + assert!( + size_of::<Src>() >= size_of::<Dst>(), + "cannot transmute_copy if Dst is larger than Src" + ); - // If U has a higher alignment requirement, src might not be suitably aligned. - if align_of::<U>() > align_of::<T>() { + // If Dst has a higher alignment requirement, src might not be suitably aligned. + if align_of::<Dst>() > align_of::<Src>() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read_unaligned(src as *const T as *const U) } + unsafe { ptr::read_unaligned(src as *const Src as *const Dst) } } else { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. - // We just checked that `src as *const U` was properly aligned. + // We just checked that `src as *const Dst` was properly aligned. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read(src as *const T as *const U) } + unsafe { ptr::read(src as *const Src as *const Dst) } } } @@ -1178,3 +1180,44 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> { pub const fn variant_count<T>() -> usize { intrinsics::variant_count::<T>() } + +/// Provides associated constants for various useful properties of types, +/// to give them a canonical form in our code and make them easier to read. +/// +/// This is here only to simplify all the ZST checks we need in the library. +/// It's not on a stabilization track right now. +#[doc(hidden)] +#[unstable(feature = "sized_type_properties", issue = "none")] +pub trait SizedTypeProperties: Sized { + /// `true` if this type requires no storage. + /// `false` if its [size](size_of) is greater than zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(sized_type_properties)] + /// use core::mem::SizedTypeProperties; + /// + /// fn do_something_with<T>() { + /// if T::IS_ZST { + /// // ... special approach ... + /// } else { + /// // ... the normal thing ... + /// } + /// } + /// + /// struct MyUnit; + /// assert!(MyUnit::IS_ZST); + /// + /// // For negative checks, consider using UFCS to emphasize the negation + /// assert!(!<i32>::IS_ZST); + /// // As it can sometimes hide in the type otherwise + /// assert!(!String::IS_ZST); + /// ``` + #[doc(hidden)] + #[unstable(feature = "sized_type_properties", issue = "none")] + const IS_ZST: bool = size_of::<Self>() == 0; +} +#[doc(hidden)] +#[unstable(feature = "sized_type_properties", issue = "none")] +impl<T> SizedTypeProperties for T {} diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index b59a5b89d..3b98efff2 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -4,25 +4,20 @@ /// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`, /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] -#[cfg_attr(not(bootstrap), lang = "transmute_trait")] +#[lang = "transmute_trait"] #[rustc_on_unimplemented( message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." )] -pub unsafe trait BikeshedIntrinsicFrom< - Src, - Context, - const ASSUME_ALIGNMENT: bool, - const ASSUME_LIFETIMES: bool, - const ASSUME_VALIDITY: bool, - const ASSUME_VISIBILITY: bool, -> where +pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> +where Src: ?Sized, { } /// What transmutation safety conditions shall the compiler assume that *you* are checking? #[unstable(feature = "transmutability", issue = "99571")] +#[lang = "transmute_opts"] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that @@ -33,11 +28,80 @@ pub struct Assume { /// that violates Rust's memory model. pub lifetimes: bool, + /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the + /// type and field privacy of the destination type (and sometimes of the source type, too). + pub safety: bool, + /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid /// instance of the destination type. pub validity: bool, +} - /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the - /// type and field privacy of the destination type (and sometimes of the source type, too). - pub visibility: bool, +impl Assume { + /// Do not assume that *you* have ensured any safety properties are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const NOTHING: Self = + Self { alignment: false, lifetimes: false, safety: false, validity: false }; + + /// Assume only that alignment conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING }; + + /// Assume only that lifetime conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING }; + + /// Assume only that safety conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING }; + + /// Assume only that dynamically-satisfiable validity conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING }; + + /// Assume both `self` and `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn and(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment || other_assumptions.alignment, + lifetimes: self.lifetimes || other_assumptions.lifetimes, + safety: self.safety || other_assumptions.safety, + validity: self.validity || other_assumptions.validity, + } + } + + /// Assume `self`, excepting `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn but_not(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment && !other_assumptions.alignment, + lifetimes: self.lifetimes && !other_assumptions.lifetimes, + safety: self.safety && !other_assumptions.safety, + validity: self.validity && !other_assumptions.validity, + } + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Add for Assume { + type Output = Assume; + + fn add(self, other_assumptions: Assume) -> Assume { + self.and(other_assumptions) + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Sub for Assume { + type Output = Assume; + + fn sub(self, other_assumptions: Assume) -> Assume { + self.but_not(other_assumptions) + } } diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs deleted file mode 100644 index fcfa95120..000000000 --- a/library/core/src/mem/valid_align.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::convert::TryFrom; -use crate::num::NonZeroUsize; -use crate::{cmp, fmt, hash, mem, num}; - -/// A type storing a `usize` which is a power of two, and thus -/// represents a possible alignment in the rust abstract machine. -/// -/// Note that particularly large alignments, while representable in this type, -/// are likely not to be supported by actual allocators and linkers. -#[derive(Copy, Clone)] -#[repr(transparent)] -pub(crate) struct ValidAlign(ValidAlignEnum); - -// ValidAlign is `repr(usize)`, but via extra steps. -const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>()); -const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>()); - -impl ValidAlign { - /// Creates a `ValidAlign` from a power-of-two `usize`. - /// - /// # Safety - /// - /// `align` must be a power of two. - /// - /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. - /// It must *not* be zero. - #[inline] - pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - debug_assert!(align.is_power_of_two()); - - // SAFETY: By precondition, this must be a power of two, and - // our variants encompass all possible powers of two. - unsafe { mem::transmute::<usize, ValidAlign>(align) } - } - - #[inline] - pub(crate) const fn as_nonzero(self) -> NonZeroUsize { - // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.0 as usize) } - } - - /// Returns the base 2 logarithm of the alignment. - /// - /// This is always exact, as `self` represents a power of two. - #[inline] - pub(crate) fn log2(self) -> u32 { - self.as_nonzero().trailing_zeros() - } -} - -impl fmt::Debug for ValidAlign { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2()) - } -} - -impl TryFrom<NonZeroUsize> for ValidAlign { - type Error = num::TryFromIntError; - - #[inline] - fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> { - if align.is_power_of_two() { - // SAFETY: Just checked for power-of-two - unsafe { Ok(ValidAlign::new_unchecked(align.get())) } - } else { - Err(num::TryFromIntError(())) - } - } -} - -impl TryFrom<usize> for ValidAlign { - type Error = num::TryFromIntError; - - #[inline] - fn try_from(align: usize) -> Result<ValidAlign, Self::Error> { - if align.is_power_of_two() { - // SAFETY: Just checked for power-of-two - unsafe { Ok(ValidAlign::new_unchecked(align)) } - } else { - Err(num::TryFromIntError(())) - } - } -} - -impl cmp::Eq for ValidAlign {} - -impl cmp::PartialEq for ValidAlign { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_nonzero() == other.as_nonzero() - } -} - -impl cmp::Ord for ValidAlign { - #[inline] - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.as_nonzero().cmp(&other.as_nonzero()) - } -} - -impl cmp::PartialOrd for ValidAlign { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl hash::Hash for ValidAlign { - #[inline] - fn hash<H: hash::Hasher>(&self, state: &mut H) { - self.as_nonzero().hash(state) - } -} - -#[cfg(target_pointer_width = "16")] -type ValidAlignEnum = ValidAlignEnum16; -#[cfg(target_pointer_width = "32")] -type ValidAlignEnum = ValidAlignEnum32; -#[cfg(target_pointer_width = "64")] -type ValidAlignEnum = ValidAlignEnum64; - -#[derive(Copy, Clone)] -#[repr(u16)] -enum ValidAlignEnum16 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, -} - -#[derive(Copy, Clone)] -#[repr(u32)] -enum ValidAlignEnum32 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, - _Align1Shl16 = 1 << 16, - _Align1Shl17 = 1 << 17, - _Align1Shl18 = 1 << 18, - _Align1Shl19 = 1 << 19, - _Align1Shl20 = 1 << 20, - _Align1Shl21 = 1 << 21, - _Align1Shl22 = 1 << 22, - _Align1Shl23 = 1 << 23, - _Align1Shl24 = 1 << 24, - _Align1Shl25 = 1 << 25, - _Align1Shl26 = 1 << 26, - _Align1Shl27 = 1 << 27, - _Align1Shl28 = 1 << 28, - _Align1Shl29 = 1 << 29, - _Align1Shl30 = 1 << 30, - _Align1Shl31 = 1 << 31, -} - -#[derive(Copy, Clone)] -#[repr(u64)] -enum ValidAlignEnum64 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, - _Align1Shl16 = 1 << 16, - _Align1Shl17 = 1 << 17, - _Align1Shl18 = 1 << 18, - _Align1Shl19 = 1 << 19, - _Align1Shl20 = 1 << 20, - _Align1Shl21 = 1 << 21, - _Align1Shl22 = 1 << 22, - _Align1Shl23 = 1 << 23, - _Align1Shl24 = 1 << 24, - _Align1Shl25 = 1 << 25, - _Align1Shl26 = 1 << 26, - _Align1Shl27 = 1 << 27, - _Align1Shl28 = 1 << 28, - _Align1Shl29 = 1 << 29, - _Align1Shl30 = 1 << 30, - _Align1Shl31 = 1 << 31, - _Align1Shl32 = 1 << 32, - _Align1Shl33 = 1 << 33, - _Align1Shl34 = 1 << 34, - _Align1Shl35 = 1 << 35, - _Align1Shl36 = 1 << 36, - _Align1Shl37 = 1 << 37, - _Align1Shl38 = 1 << 38, - _Align1Shl39 = 1 << 39, - _Align1Shl40 = 1 << 40, - _Align1Shl41 = 1 << 41, - _Align1Shl42 = 1 << 42, - _Align1Shl43 = 1 << 43, - _Align1Shl44 = 1 << 44, - _Align1Shl45 = 1 << 45, - _Align1Shl46 = 1 << 46, - _Align1Shl47 = 1 << 47, - _Align1Shl48 = 1 << 48, - _Align1Shl49 = 1 << 49, - _Align1Shl50 = 1 << 50, - _Align1Shl51 = 1 << 51, - _Align1Shl52 = 1 << 52, - _Align1Shl53 = 1 << 53, - _Align1Shl54 = 1 << 54, - _Align1Shl55 = 1 << 55, - _Align1Shl56 = 1 << 56, - _Align1Shl57 = 1 << 57, - _Align1Shl58 = 1 << 58, - _Align1Shl59 = 1 << 59, - _Align1Shl60 = 1 << 60, - _Align1Shl61 = 1 << 61, - _Align1Shl62 = 1 << 62, - _Align1Shl63 = 1 << 63, -} |