@@ -647,42 +647,50 @@ pub unsafe fn read<T>(src: *const T) -> T {
647647/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value
648648/// [valid]: ../ptr/index.html#safety
649649///
650- /// # Examples
650+ /// ## On `packed` structs
651651///
652- /// Access members of a packed struct by reference:
652+ /// It is currently impossible to create raw pointers to unaligned fields
653+ /// of a packed struct.
653654///
654- /// ```
655- /// use std::ptr;
655+ /// Attempting to create a raw pointer to an `unaligned` struct field with
656+ /// an expression such as `&packed.unaligned as *const FieldType` creates an
657+ /// intermediate unaligned reference before converting that to a raw pointer.
658+ /// That this reference is temporary and immediately cast is inconsequential
659+ /// as the compiler always expects references to be properly aligned.
660+ /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
661+ /// *undefined behavior* in your program.
656662///
663+ /// An example of what not to do and how this relates to `read_unaligned` is:
664+ ///
665+ /// ```
657666/// #[repr(packed, C)]
658667/// struct Packed {
659668/// _padding: u8,
660669/// unaligned: u32,
661670/// }
662671///
663- /// let x = Packed {
672+ /// let packed = Packed {
664673/// _padding: 0x00,
665674/// unaligned: 0x01020304,
666675/// };
667676///
668677/// let v = unsafe {
669- /// // Take the address of a 32-bit integer which is not aligned.
670- /// // This must be done as a raw pointer; unaligned references are invalid.
671- /// let unaligned = &x.unaligned as *const u32;
678+ /// // Here we attempt to take the address of a 32-bit integer which is not aligned.
679+ /// let unaligned =
680+ /// // A temporary unaligned reference is created here which results in
681+ /// // undefined behavior regardless of whether the reference is used or not.
682+ /// &packed.unaligned
683+ /// // Casting to a raw pointer doesn't help; the mistake already happened.
684+ /// as *const u32;
672685///
673- /// // Dereferencing normally will emit an aligned load instruction,
674- /// // causing undefined behavior.
675- /// // let v = *unaligned; // ERROR
676- ///
677- /// // Instead, use `read_unaligned` to read improperly aligned values.
678- /// let v = ptr::read_unaligned(unaligned);
686+ /// let v = std::ptr::read_unaligned(unaligned);
679687///
680688/// v
681689/// };
682- ///
683- /// // Accessing unaligned values directly is safe.
684- /// assert!(x.unaligned == v);
685690/// ```
691+ ///
692+ /// Accessing unaligned values directly with e.g. `packed.unaligned` is safe however.
693+ // FIXME: Update docs based on outcome of RFC #2582 and friends.
686694#[ inline]
687695#[ stable( feature = "ptr_unaligned" , since = "1.17.0" ) ]
688696pub unsafe fn read_unaligned < T > ( src : * const T ) -> T {
@@ -811,38 +819,48 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
811819///
812820/// [valid]: ../ptr/index.html#safety
813821///
814- /// # Examples
822+ /// ## On `packed` structs
815823///
816- /// Access fields in a packed struct:
824+ /// It is currently impossible to create raw pointers to unaligned fields
825+ /// of a packed struct.
817826///
818- /// ```
819- /// use std::{mem, ptr};
827+ /// Attempting to create a raw pointer to an `unaligned` struct field with
828+ /// an expression such as `&packed.unaligned as *const FieldType` creates an
829+ /// intermediate unaligned reference before converting that to a raw pointer.
830+ /// That this reference is temporary and immediately cast is inconsequential
831+ /// as the compiler always expects references to be properly aligned.
832+ /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
833+ /// *undefined behavior* in your program.
820834///
835+ /// An example of what not to do and how this relates to `write_unaligned` is:
836+ ///
837+ /// ```
821838/// #[repr(packed, C)]
822- /// #[derive(Default)]
823839/// struct Packed {
824840/// _padding: u8,
825841/// unaligned: u32,
826842/// }
827843///
828844/// let v = 0x01020304;
829- /// let mut x : Packed = unsafe { mem::zeroed() };
845+ /// let mut packed : Packed = unsafe { std:: mem::zeroed() };
830846///
831- /// unsafe {
832- /// // Take a reference to a 32-bit integer which is not aligned.
833- /// let unaligned = &mut x.unaligned as *mut u32;
847+ /// let v = unsafe {
848+ /// // Here we attempt to take the address of a 32-bit integer which is not aligned.
849+ /// let unaligned =
850+ /// // A temporary unaligned reference is created here which results in
851+ /// // undefined behavior regardless of whether the reference is used or not.
852+ /// &mut packed.unaligned
853+ /// // Casting to a raw pointer doesn't help; the mistake already happened.
854+ /// as *mut u32;
834855///
835- /// // Dereferencing normally will emit an aligned store instruction,
836- /// // causing undefined behavior because the pointer is not aligned.
837- /// // *unaligned = v; // ERROR
856+ /// std::ptr::write_unaligned(unaligned, v);
838857///
839- /// // Instead, use `write_unaligned` to write improperly aligned values.
840- /// ptr::write_unaligned(unaligned, v);
841- /// }
842- ///
843- /// // Accessing unaligned values directly is safe.
844- /// assert!(x.unaligned == v);
858+ /// v
859+ /// };
845860/// ```
861+ ///
862+ /// Accessing unaligned values directly with e.g. `packed.unaligned` is safe however.
863+ // FIXME: Update docs based on outcome of RFC #2582 and friends.
846864#[ inline]
847865#[ stable( feature = "ptr_unaligned" , since = "1.17.0" ) ]
848866pub unsafe fn write_unaligned < T > ( dst : * mut T , src : T ) {
0 commit comments