#![feature(unsize, coerce_unsized)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; use std::ptr; fn test_basic() { #[repr(packed)] struct S { fill: u8, a: i32, b: i64, } #[repr(packed)] #[allow(dead_code)] struct Test1<'a> { x: u8, other: &'a u32, } #[repr(packed)] #[allow(dead_code)] struct Test2<'a> { x: u8, other: &'a Test1<'a>, } fn test(t: Test2) { let x = *t.other.other; assert_eq!(x, 42); } let mut x = S { fill: 0, a: 42, b: 99, }; let a = x.a; let b = x.b; assert_eq!(a, 42); assert_eq!(b, 99); assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference assert_eq!({x.a}, 42); assert_eq!({x.b}, 99); // but we *can* take a raw pointer! assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42); assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); } fn test_unsizing() { #[repr(packed)] #[allow(dead_code)] struct UnalignedPtr<'a, T: ?Sized> where T: 'a, { data: &'a T, } impl<'a, T, U> std::ops::CoerceUnsized> for UnalignedPtr<'a, T> where T: std::marker::Unsize + ?Sized, U: ?Sized, { } let arr = [1, 2, 3]; let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr }; let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned; let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors } fn test_drop() { struct Wrap(u32); impl Drop for Wrap { fn drop(&mut self) { // Do an (aligned) load let _test = self.0; // For the fun of it, test alignment assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::(), 0); } } #[repr(packed,C)] struct Packed { f1: u8, // this should move the second field to something not very aligned f2: T, } let p = Packed { f1: 42, f2: Wrap(23) }; drop(p); } fn test_inner_packed() { // Even if just the inner struct is packed, accesses to the outer field can get unaligned. // Make sure that works. #[repr(packed)] #[derive(Clone,Copy)] struct Inner(u32); #[derive(Clone,Copy)] struct Outer(u8, Inner); let o = Outer(0, Inner(42)); let _x = o.1; let _y = (o.1).0; let _o2 = o.clone(); } fn test_static() { #[repr(packed)] struct Foo { i: i32 } static FOO: Foo = Foo { i: 42 }; assert_eq!({FOO.i}, 42); } fn test_derive() { #[repr(packed)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] struct P { a: usize, b: u8, c: usize, } let x = P {a: 1usize, b: 2u8, c: 3usize}; let y = P {a: 1usize, b: 2u8, c: 4usize}; let _clone = x.clone(); assert!(x != y); assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y)); x.hash(&mut DefaultHasher::new()); P::default(); format!("{:?}", x); } fn main() { test_basic(); test_unsizing(); test_drop(); test_inner_packed(); test_static(); test_derive(); }