Skip to content

Commit b806b5e

Browse files
committed
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
1 parent 91376f4 commit b806b5e

File tree

1 file changed

+104
-4
lines changed

1 file changed

+104
-4
lines changed

library/core/src/mem/transmutability.rs

+104-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,63 @@
11
use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
22

3-
/// Are values of a type transmutable into values of another type?
3+
/// Marks that `Src` is transmutable into `Self`.
44
///
5-
/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
6-
/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
7-
/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
5+
/// # Implementation
6+
///
7+
/// This trait cannot be implemented explicitly. It is implemented on-the-fly by
8+
/// the compiler for all types `Src` and `Self` such that, given a set of safety
9+
/// obligations on the programmer (see [`Assume`]), the compiler has proved that
10+
/// the bits of a value of type `Src` can be soundly reinterpreted as `Self`.
11+
///
12+
/// Specifically, this trait models (and
13+
/// [implements](BikeshedIntrinsicFrom::transmute)) the semantics of
14+
/// transmute-via-union; i.e.:
15+
///
16+
/// ```rust
17+
/// pub unsafe fn transmute_via_union<Src, Dst>(src: Src) -> Dst {
18+
/// use core::mem::ManuallyDrop;
19+
///
20+
/// #[repr(C)]
21+
/// union Transmute<T, U> {
22+
/// src: ManuallyDrop<T>,
23+
/// dst: ManuallyDrop<U>,
24+
/// }
25+
///
26+
/// let transmute = Transmute {
27+
/// src: ManuallyDrop::new(src),
28+
/// };
29+
///
30+
/// let dst = transmute.dst;
31+
///
32+
/// ManuallyDrop::into_inner(dst)
33+
/// }
34+
/// ```
35+
///
36+
/// Note that this construction supports some transmutations forbidden by
37+
/// [`mem::transmute_copy`](super::transmute_copy), namely transmutations that
38+
/// extend the trailing padding of `Src` to fill `Dst`.
39+
///
40+
/// ## Portability
41+
///
42+
/// Implementations of this trait do provide any guarantee of portability across
43+
/// toolchains or compilations. This trait may be implemented for certain
44+
/// combinations of `Src`, `Self` and `ASSUME` on some toolchains, but not
45+
/// others. For example, if the layouts of `Src` or `Self` are
46+
/// non-deterministic, the presence or absence of an implementation of this
47+
/// trait may also be non-deterministic. Even if `Src` and `Self` have
48+
/// deterministic layouts (e.g., they are `repr(C)` structs), Rust does not
49+
/// specify the alignments of its primitive integer types, and layouts that
50+
/// involve these types may vary across toolchains.
51+
///
52+
/// ## Stability
53+
///
54+
/// Implementations of this trait do not provide any guarantee of SemVer
55+
/// stability across the crate versions that define the `Src` and `Self` types.
56+
/// If SemVer stability is crucial to your application, you must consult the
57+
/// documentation of `Src` and `Self`s' defining crates. Note that the presence
58+
/// of `repr(C)`, alone, does not carry a safety invariant of SemVer stability.
59+
/// Furthermore, stability does not imply portability. For example, the size of
60+
/// `usize` is stable, but not portable.
861
#[unstable(feature = "transmutability", issue = "99571")]
962
#[lang = "transmute_trait"]
1063
#[rustc_deny_explicit_impl(implement_via_object = false)]
@@ -13,6 +66,53 @@ pub unsafe trait BikeshedIntrinsicFrom<Src, const ASSUME: Assume = { Assume::NOT
1366
where
1467
Src: ?Sized,
1568
{
69+
/// Transmutes a `Src` value into a `Self`.
70+
///
71+
/// # Safety
72+
///
73+
/// The safety obligations of the caller depend on the value of `ASSUME`:
74+
/// - If [`ASSUME.alignment`](Assume::alignment), the caller must prove that
75+
/// all references in `src` (including `src` itself, if `Src` is a
76+
/// reference type) have well-aligned referents upon transmutation into
77+
/// `Self`.
78+
/// - If [`ASSUME.lifetimes`](Assume::lifetimes), the caller must prove that
79+
/// all references in `src` (including `src` itself, if `Src` is a
80+
/// reference type) have referents that live as long as `Self`.
81+
/// - If [`ASSUME.safety`](Assume::safety), the caller must prove that the
82+
/// value `src` transmuted into `Self` satisfies all library safety
83+
/// invariants of `Self`.
84+
/// - If [`ASSUME.validity`](Assume::validity), the caller must prove that
85+
/// `src` is a bit-valid instance of `Self`.
86+
///
87+
/// When satisfying the above obligations (if any), the caller must *not*
88+
/// assume that this trait provides any inherent guarantee of layout
89+
/// [portability](#portability) or [stability](#stability).
90+
unsafe fn transmute(src: Src) -> Self
91+
where
92+
Src: Sized,
93+
Self: Sized,
94+
{
95+
use super::ManuallyDrop;
96+
97+
#[repr(C)]
98+
union Transmute<T, U> {
99+
src: ManuallyDrop<T>,
100+
dst: ManuallyDrop<U>,
101+
}
102+
103+
let transmute = Transmute { src: ManuallyDrop::new(src) };
104+
105+
// SAFETY: It is safe to reinterpret the bits of `src` as a value of
106+
// type `Self`, because, by combination of invariant on this trait and
107+
// contract on the caller, `src` has been proven to satisfy both the
108+
// language and library invariants of `Self`. For all invariants not
109+
// `ASSUME`'d by the caller, the safety obligation is supplied by the
110+
// compiler. Conversely, for all invariants `ASSUME`'d by the caller,
111+
// the safety obligation is supplied by contract on the caller.
112+
let dst = unsafe { transmute.dst };
113+
114+
ManuallyDrop::into_inner(dst)
115+
}
16116
}
17117

18118
/// What transmutation safety conditions shall the compiler assume that *you* are checking?

0 commit comments

Comments
 (0)