@@ -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