| #![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 requires 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<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T> |
| where |
| T: std::marker::Unsize<U> + ?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::<u32>(), 0); |
| } |
| } |
| |
| #[repr(packed, C)] |
| struct Packed<T> { |
| 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(#[allow(dead_code)] 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(); |
| } |