@@ -253,6 +253,89 @@ use crate::{fmt, intrinsics, ptr, slice};
253253/// std::process::exit(*code); // UB! Accessing uninitialized memory.
254254/// }
255255/// ```
256+ ///
257+ /// # Validity
258+ ///
259+ /// `MaybeUninit<T>` has no validity requirements –- any sequence of [bytes] of
260+ /// the appropriate length, initialized or uninitialized, are a valid
261+ /// representation.
262+ ///
263+ /// Moving or copying a value of type `MaybeUninit<T>` (i.e., performing a
264+ /// "typed copy") will exactly preserve the contents, including the
265+ /// [provenance], of all non-padding bytes of type `T` in the value's
266+ /// representation.
267+ ///
268+ /// Therefore `MaybeUninit` can be used to perform a round trip of a value from
269+ /// type `T` to type `MaybeUninit<U>` then back to type `T`, while preserving
270+ /// the original value, if two conditions are met. One, type `U` must have the
271+ /// same size as type `T`. Two, for all byte offsets where type `U` has padding,
272+ /// the corresponding bytes in the representation of the value must be
273+ /// uninitialized.
274+ ///
275+ /// For example, due to the fact that the type `[u8; size_of::<T>]` has no
276+ /// padding, the following is sound for any type `T` and will return the
277+ /// original value:
278+ ///
279+ /// ```rust,no_run
280+ /// # use core::mem::{MaybeUninit, transmute};
281+ /// # struct T;
282+ /// fn identity(t: T) -> T {
283+ /// unsafe {
284+ /// let u: MaybeUninit<[u8; size_of::<T>()]> = transmute(t);
285+ /// transmute(u) // OK.
286+ /// }
287+ /// }
288+ /// ```
289+ ///
290+ /// Note: Copying a value that contains references may implicitly reborrow them
291+ /// causing the provenance of the returned value to differ from that of the
292+ /// original. This applies equally to the trivial identity function:
293+ ///
294+ /// ```rust,no_run
295+ /// fn trivial_identity<T>(t: T) -> T { t }
296+ /// ```
297+ ///
298+ /// Note: Moving or copying a value whose representation has initialized bytes
299+ /// at byte offsets where the type has padding may lose the value of those
300+ /// bytes, so while the original value will be preserved, the original
301+ /// *representation* of that value as bytes may not be. Again, this applies
302+ /// equally to `trivial_identity`.
303+ ///
304+ /// Note: Performing this round trip when type `U` has padding at byte offsets
305+ /// where the representation of the original value has initialized bytes may
306+ /// produce undefined behavior or a different value. For example, the following
307+ /// is unsound since `T` requires all bytes to be initialized:
308+ ///
309+ /// ```rust,no_run
310+ /// # use core::mem::{MaybeUninit, transmute};
311+ /// #[repr(C)] struct T([u8; 4]);
312+ /// #[repr(C)] struct U(u8, u16);
313+ /// fn unsound_identity(t: T) -> T {
314+ /// unsafe {
315+ /// let u: MaybeUninit<U> = transmute(t);
316+ /// transmute(u) // UB.
317+ /// }
318+ /// }
319+ /// ```
320+ ///
321+ /// Conversely, the following is sound since `T` allows uninitialized bytes in
322+ /// the representation of a value, but the round trip may alter the value:
323+ ///
324+ /// ```rust,no_run
325+ /// # use core::mem::{MaybeUninit, transmute};
326+ /// #[repr(C)] struct T(MaybeUninit<[u8; 4]>);
327+ /// #[repr(C)] struct U(u8, u16);
328+ /// fn non_identity(t: T) -> T {
329+ /// unsafe {
330+ /// // May lose an initialized byte.
331+ /// let u: MaybeUninit<U> = transmute(t);
332+ /// transmute(u)
333+ /// }
334+ /// }
335+ /// ```
336+ ///
337+ /// [bytes]: ../../reference/memory-model.html#bytes
338+ /// [provenance]: crate::ptr#provenance
256339#[ stable( feature = "maybe_uninit" , since = "1.36.0" ) ]
257340// Lang item so we can wrap other types in it. This is useful for coroutines.
258341#[ lang = "maybe_uninit" ]
0 commit comments