Skip to content

Commit

Permalink
document & impl the transmutation modeled by BikeshedIntrinsicFrom
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jswrenn committed Aug 12, 2024
1 parent 91376f4 commit b806b5e
Showing 1 changed file with 104 additions and 4 deletions.
108 changes: 104 additions & 4 deletions library/core/src/mem/transmutability.rs
Original file line number Diff line number Diff line change
@@ -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, Dst>(src: Src) -> Dst {
/// use core::mem::ManuallyDrop;
///
/// #[repr(C)]
/// union Transmute<T, U> {
/// src: ManuallyDrop<T>,
/// dst: ManuallyDrop<U>,
/// }
///
/// 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)]
Expand All @@ -13,6 +66,53 @@ pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOT
where
Src: ?Sized,
{
/// Transmutes a `Src` value into a `Self`.
///
/// # Safety
///
/// The safety obligations of the caller depend on the value of `ASSUME`:
/// - If [`ASSUME.alignment`](Assume::alignment), the caller must prove that
/// all references in `src` (including `src` itself, if `Src` is a
/// reference type) have well-aligned referents upon transmutation into
/// `Self`.
/// - If [`ASSUME.lifetimes`](Assume::lifetimes), the caller must prove that
/// all references in `src` (including `src` itself, if `Src` is a
/// reference type) have referents that live as long as `Self`.
/// - If [`ASSUME.safety`](Assume::safety), the caller must prove that the
/// value `src` transmuted into `Self` satisfies all library safety
/// invariants of `Self`.
/// - If [`ASSUME.validity`](Assume::validity), the caller must prove that
/// `src` is a bit-valid instance of `Self`.
///
/// When satisfying the above obligations (if any), the caller must *not*
/// assume that this trait provides any inherent guarantee of layout
/// [portability](#portability) or [stability](#stability).
unsafe fn transmute(src: Src) -> Self
where
Src: Sized,
Self: Sized,
{
use super::ManuallyDrop;

#[repr(C)]
union Transmute<T, U> {
src: ManuallyDrop<T>,
dst: ManuallyDrop<U>,
}

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?
Expand Down

0 comments on commit b806b5e

Please sign in to comment.