diff options
Diffstat (limited to 'library/core/src/mem')
-rw-r--r-- | library/core/src/mem/maybe_uninit.rs | 10 | ||||
-rw-r--r-- | library/core/src/mem/mod.rs | 10 | ||||
-rw-r--r-- | library/core/src/mem/transmutability.rs | 86 | ||||
-rw-r--r-- | library/core/src/mem/valid_align.rs | 18 |
4 files changed, 98 insertions, 26 deletions
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4ea53608..2490c0767 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]); /// } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 20b2d5e26..d2dd2941d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -665,14 +665,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 diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index b59a5b89d..87a378631 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -9,20 +9,15 @@ 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")] +#[cfg_attr(not(bootstrap), 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 index fcfa95120..32b2afb72 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -26,7 +27,8 @@ impl ValidAlign { /// It must *not* be zero. #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - debug_assert!(align.is_power_of_two()); + // SAFETY: Precondition passed to the caller. + unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. @@ -34,9 +36,14 @@ impl ValidAlign { } #[inline] + pub(crate) const fn as_usize(self) -> usize { + self.0 as usize + } + + #[inline] pub(crate) const fn as_nonzero(self) -> NonZeroUsize { // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.0 as usize) } + unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } } /// Returns the base 2 logarithm of the alignment. @@ -46,6 +53,13 @@ impl ValidAlign { pub(crate) fn log2(self) -> u32 { 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 { |