@@ -252,6 +252,54 @@ use crate::{fmt, intrinsics, ptr, slice};
252252/// std::process::exit(*code); // UB! Accessing uninitialized memory.
253253/// }
254254/// ```
255+ ///
256+ /// # Validity
257+ ///
258+ /// A `MaybeUninit<T>` has no validity requirement – any sequence of
259+ /// [bytes][reference-byte] of the appropriate length, initialized or
260+ /// uninitialized, are a valid representation of `MaybeUninit<T>`.
261+ ///
262+ /// However, "round-tripping" via `MaybeUninit` does not always result in the
263+ /// original value. `MaybeUninit` can have padding, and the contents of that
264+ /// padding are not preserved. Concretely, given distinct `T` and `U` where
265+ /// `size_of::<T>() == size_of::<U>()`, the following code is not guaranteed to
266+ /// be sound:
267+ ///
268+ /// ```rust,no_run
269+ /// # use core::mem::{MaybeUninit, transmute};
270+ /// # struct T; struct U;
271+ /// fn identity(t: T) -> T {
272+ /// unsafe {
273+ /// let u: MaybeUninit<U> = transmute(t);
274+ /// transmute(u)
275+ /// }
276+ /// }
277+ /// ```
278+ ///
279+ /// If the representation of `t` contains initialized bytes at byte offsets
280+ /// where `U` contains padding bytes, these may not be preserved in
281+ /// `MaybeUninit<U>`. Transmuting `u` back to `T` (i.e., `transmute(u)` above)
282+ /// may thus be undefined behavior or yield a value different from `t` due to
283+ /// those bytes being lost. This is an active area of discussion, and this code
284+ /// may become sound in the future.
285+ ///
286+ /// However, so long as no such byte offsets exist, then the preceding
287+ /// `identity` example *is* sound. In particular, since `[u8; N]` has no padding
288+ /// bytes, transmuting `t` to `MaybeUninit<[u8; size_of::<T>]>` and back will
289+ /// always produce the original value `t` again. This is true even if `t`
290+ /// contains [provenance]: the resulting value will have the same provenance as
291+ /// the original `t`.
292+ ///
293+ /// Note a potential footgun: if `t` contains a reference, then there may be
294+ /// implicit reborrows of the reference any time it is copied, which may alter
295+ /// its provenance. In that case, the value returned by `identity` may not be
296+ /// exactly the same as its argument. However, even in this case, it remains
297+ /// true that `identity` behaves the same as a function that just returns `t`
298+ /// immediately (i.e., `fn identity<T>(t: T) -> T { t }`).
299+ ///
300+ /// [provenance]: crate::ptr#provenance
301+ ///
302+ /// [reference-byte]: ../../reference/memory-model.html#bytes
255303#[ stable( feature = "maybe_uninit" , since = "1.36.0" ) ]
256304// Lang item so we can wrap other types in it. This is useful for coroutines.
257305#[ lang = "maybe_uninit" ]
0 commit comments