From b806b5e052cd78ffedcffb6484c62cde9250ac7c Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Mon, 12 Aug 2024 22:52:59 +0000 Subject: [PATCH] document & impl the transmutation modeled by `BikeshedIntrinsicFrom` Documents that `BikeshedIntrinsicFrom` models transmute-via-union, which is slightly more expressive than the transmute-via-cast implemented by `transmute_copy`. Additionally, we provide an implementation of transmute-via-union as a method on the `BikeshedIntrinsicFrom` trait with additional documentation on the boundary between trait invariants and caller obligations. Whether or not transmute-via-union is the right kind of transmute to model remains up for discussion [1]. Regardless, it seems wise to document the present behavior. [1] https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/What.20'kind'.20of.20transmute.20to.20model.3F/near/426331967 --- library/core/src/mem/transmutability.rs | 108 +++++++++++++++++++++++- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index ea73c5b80ba44..9dca337b30010 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -1,10 +1,63 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; -/// Are values of a type transmutable into values of another type? +/// Marks that `Src` is transmutable into `Self`. /// -/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of -/// 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. +/// # Implementation +/// +/// This trait cannot be implemented explicitly. It is implemented on-the-fly by +/// the compiler for all types `Src` and `Self` such that, given a set of safety +/// obligations on the programmer (see [`Assume`]), the compiler has proved that +/// the bits of a value of type `Src` can be soundly reinterpreted as `Self`. +/// +/// Specifically, this trait models (and +/// [implements](BikeshedIntrinsicFrom::transmute)) the semantics of +/// transmute-via-union; i.e.: +/// +/// ```rust +/// pub unsafe fn transmute_via_union(src: Src) -> Dst { +/// use core::mem::ManuallyDrop; +/// +/// #[repr(C)] +/// union Transmute { +/// src: ManuallyDrop, +/// dst: ManuallyDrop, +/// } +/// +/// let transmute = Transmute { +/// src: ManuallyDrop::new(src), +/// }; +/// +/// let dst = transmute.dst; +/// +/// ManuallyDrop::into_inner(dst) +/// } +/// ``` +/// +/// Note that this construction supports some transmutations forbidden by +/// [`mem::transmute_copy`](super::transmute_copy), namely transmutations that +/// extend the trailing padding of `Src` to fill `Dst`. +/// +/// ## Portability +/// +/// Implementations of this trait do provide any guarantee of portability across +/// toolchains or compilations. This trait may be implemented for certain +/// combinations of `Src`, `Self` and `ASSUME` on some toolchains, but not +/// others. For example, if the layouts of `Src` or `Self` are +/// non-deterministic, the presence or absence of an implementation of this +/// trait may also be non-deterministic. Even if `Src` and `Self` have +/// deterministic layouts (e.g., they are `repr(C)` structs), Rust does not +/// specify the alignments of its primitive integer types, and layouts that +/// involve these types may vary across toolchains. +/// +/// ## Stability +/// +/// Implementations of this trait do not provide any guarantee of SemVer +/// stability across the crate versions that define the `Src` and `Self` types. +/// If SemVer stability is crucial to your application, you must consult the +/// documentation of `Src` and `Self`s' defining crates. Note that the presence +/// of `repr(C)`, alone, does not carry a safety invariant of SemVer stability. +/// Furthermore, stability does not imply portability. For example, the size of +/// `usize` is stable, but not portable. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] #[rustc_deny_explicit_impl(implement_via_object = false)] @@ -13,6 +66,53 @@ pub unsafe trait BikeshedIntrinsicFrom Self + where + Src: Sized, + Self: Sized, + { + use super::ManuallyDrop; + + #[repr(C)] + union Transmute { + src: ManuallyDrop, + dst: ManuallyDrop, + } + + let transmute = Transmute { src: ManuallyDrop::new(src) }; + + // SAFETY: It is safe to reinterpret the bits of `src` as a value of + // type `Self`, because, by combination of invariant on this trait and + // contract on the caller, `src` has been proven to satisfy both the + // language and library invariants of `Self`. For all invariants not + // `ASSUME`'d by the caller, the safety obligation is supplied by the + // compiler. Conversely, for all invariants `ASSUME`'d by the caller, + // the safety obligation is supplied by contract on the caller. + let dst = unsafe { transmute.dst }; + + ManuallyDrop::into_inner(dst) + } } /// What transmutation safety conditions shall the compiler assume that *you* are checking?