| //@ run-pass | |
| #![allow(dead_code, unused_allocation)] | |
| use std::mem; | |
| // Raising alignment | |
| #[repr(align(16))] | |
| #[derive(Clone, Copy, Debug)] | |
| struct Align16(i32); | |
| // Lowering has no effect | |
| #[repr(align(1))] | |
| struct Align1(i32); | |
| // Multiple attributes take the max | |
| #[repr(align(4))] | |
| #[repr(align(16))] | |
| #[repr(align(8))] | |
| struct AlignMany(i32); | |
| // Raising alignment may not alter size. | |
| #[repr(align(8))] | |
| struct Align8Many { | |
| a: i32, | |
| b: i32, | |
| c: i32, | |
| d: u8, | |
| } | |
| enum Enum { | |
| A(i32), | |
| B(Align16), | |
| } | |
| // Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test | |
| #[repr(C)] | |
| struct Nested { | |
| a: i32, | |
| b: i32, | |
| c: Align16, | |
| d: i8, | |
| } | |
| #[repr(packed)] | |
| struct Packed(i32); | |
| #[repr(align(16))] | |
| struct AlignContainsPacked { | |
| a: Packed, | |
| b: Packed, | |
| } | |
| #[repr(C, packed(4))] | |
| struct Packed4C { | |
| a: u32, | |
| b: u64, | |
| } | |
| #[repr(align(16))] | |
| struct AlignContainsPacked4C { | |
| a: Packed4C, | |
| b: u64, | |
| } | |
| // The align limit was originally smaller (2^15). | |
| // Check that it works with big numbers. | |
| #[repr(align(0x10000))] | |
| struct AlignLarge { | |
| stuff: [u8; 0x10000], | |
| } | |
| union UnionContainsAlign { | |
| a: Align16, | |
| b: f32, | |
| } | |
| impl Align16 { | |
| // return aligned type | |
| pub fn new(i: i32) -> Align16 { | |
| Align16(i) | |
| } | |
| // pass aligned type | |
| pub fn consume(a: Align16) -> i32 { | |
| a.0 | |
| } | |
| } | |
| const CONST_ALIGN16: Align16 = Align16(7); | |
| static STATIC_ALIGN16: Align16 = Align16(8); | |
| // Check the actual address is aligned | |
| fn is_aligned_to<T>(p: &T, align: usize) -> bool { | |
| let addr = p as *const T as usize; | |
| (addr & (align - 1)) == 0 | |
| } | |
| pub fn main() { | |
| // check alignment and size by type and value | |
| assert_eq!(mem::align_of::<Align16>(), 16); | |
| assert_eq!(mem::size_of::<Align16>(), 16); | |
| let a = Align16(7); | |
| assert_eq!(a.0, 7); | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::size_of_val(&a), 16); | |
| assert!(is_aligned_to(&a, 16)); | |
| // lowering should have no effect | |
| assert_eq!(mem::align_of::<Align1>(), 4); | |
| assert_eq!(mem::size_of::<Align1>(), 4); | |
| let a = Align1(7); | |
| assert_eq!(a.0, 7); | |
| assert_eq!(mem::align_of_val(&a), 4); | |
| assert_eq!(mem::size_of_val(&a), 4); | |
| assert!(is_aligned_to(&a, 4)); | |
| // when multiple attributes are specified the max should be used | |
| assert_eq!(mem::align_of::<AlignMany>(), 16); | |
| assert_eq!(mem::size_of::<AlignMany>(), 16); | |
| let a = AlignMany(7); | |
| assert_eq!(a.0, 7); | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::size_of_val(&a), 16); | |
| assert!(is_aligned_to(&a, 16)); | |
| // raising alignment should not reduce size | |
| assert_eq!(mem::align_of::<Align8Many>(), 8); | |
| assert_eq!(mem::size_of::<Align8Many>(), 16); | |
| let a = Align8Many { a: 1, b: 2, c: 3, d: 4 }; | |
| assert_eq!(a.a, 1); | |
| assert_eq!(mem::align_of_val(&a), 8); | |
| assert_eq!(mem::size_of_val(&a), 16); | |
| assert!(is_aligned_to(&a, 8)); | |
| // return type | |
| let a = Align16::new(1); | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::size_of_val(&a), 16); | |
| assert_eq!(a.0, 1); | |
| assert!(is_aligned_to(&a, 16)); | |
| assert_eq!(Align16::consume(a), 1); | |
| // check const alignment, size and value | |
| assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16); | |
| assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16); | |
| assert_eq!(CONST_ALIGN16.0, 7); | |
| assert!(is_aligned_to(&CONST_ALIGN16, 16)); | |
| // check global static alignment, size and value | |
| assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16); | |
| assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16); | |
| assert_eq!(STATIC_ALIGN16.0, 8); | |
| assert!(is_aligned_to(&STATIC_ALIGN16, 16)); | |
| // Note that the size of Nested may change if struct field re-ordering is enabled | |
| assert_eq!(mem::align_of::<Nested>(), 16); | |
| assert_eq!(mem::size_of::<Nested>(), 48); | |
| let a = Nested { a: 1, b: 2, c: Align16(3), d: 4 }; | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::align_of_val(&a.b), 4); | |
| assert_eq!(mem::align_of_val(&a.c), 16); | |
| assert_eq!(mem::size_of_val(&a), 48); | |
| assert!(is_aligned_to(&a, 16)); | |
| // check the correct fields are indexed | |
| assert_eq!(a.a, 1); | |
| assert_eq!(a.b, 2); | |
| assert_eq!(a.c.0, 3); | |
| assert_eq!(a.d, 4); | |
| // enum should be aligned to max alignment | |
| assert_eq!(mem::align_of::<Enum>(), 16); | |
| assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16); | |
| let e = Enum::B(Align16(15)); | |
| match e { | |
| Enum::B(ref a) => { | |
| assert_eq!(a.0, 15); | |
| assert_eq!(mem::align_of_val(a), 16); | |
| assert_eq!(mem::size_of_val(a), 16); | |
| } | |
| _ => (), | |
| } | |
| assert!(is_aligned_to(&e, 16)); | |
| // check union alignment | |
| assert_eq!(mem::align_of::<UnionContainsAlign>(), 16); | |
| assert_eq!(mem::size_of::<UnionContainsAlign>(), 16); | |
| let u = UnionContainsAlign { a: Align16(10) }; | |
| unsafe { | |
| assert_eq!(mem::align_of_val(&u.a), 16); | |
| assert_eq!(mem::size_of_val(&u.a), 16); | |
| assert_eq!(u.a.0, 10); | |
| let UnionContainsAlign { a } = u; | |
| assert_eq!(a.0, 10); | |
| } | |
| // arrays of aligned elements should also be aligned | |
| assert_eq!(mem::align_of::<[Align16; 2]>(), 16); | |
| assert_eq!(mem::size_of::<[Align16; 2]>(), 32); | |
| let a = [Align16(0), Align16(1)]; | |
| assert_eq!(mem::align_of_val(&a[0]), 16); | |
| assert_eq!(mem::align_of_val(&a[1]), 16); | |
| assert!(is_aligned_to(&a, 16)); | |
| // check heap value is aligned | |
| assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16); | |
| // check heap array is aligned | |
| let a = vec![Align16(0), Align16(1)]; | |
| assert_eq!(mem::align_of_val(&a[0]), 16); | |
| assert_eq!(mem::align_of_val(&a[1]), 16); | |
| assert_eq!(mem::align_of::<AlignContainsPacked>(), 16); | |
| assert_eq!(mem::size_of::<AlignContainsPacked>(), 16); | |
| let a = AlignContainsPacked { a: Packed(1), b: Packed(2) }; | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::align_of_val(&a.a), 1); | |
| assert_eq!(mem::align_of_val(&a.b), 1); | |
| assert_eq!(mem::size_of_val(&a), 16); | |
| assert!(is_aligned_to(&a, 16)); | |
| assert_eq!(mem::align_of::<AlignContainsPacked4C>(), 16); | |
| assert_eq!(mem::size_of::<AlignContainsPacked4C>(), 32); | |
| let a = AlignContainsPacked4C { a: Packed4C { a: 1, b: 2 }, b: 3 }; | |
| assert_eq!(mem::align_of_val(&a), 16); | |
| assert_eq!(mem::align_of_val(&a.a), 4); | |
| assert_eq!(mem::align_of_val(&a.b), mem::align_of::<u64>()); | |
| assert_eq!(mem::size_of_val(&a), 32); | |
| assert!(is_aligned_to(&a, 16)); | |
| let mut large = Box::new(AlignLarge { stuff: [0; 0x10000] }); | |
| large.stuff[0] = 132; | |
| *large.stuff.last_mut().unwrap() = 102; | |
| assert_eq!(large.stuff[0], 132); | |
| assert_eq!(large.stuff.last(), Some(&102)); | |
| assert_eq!(mem::align_of::<AlignLarge>(), 0x10000); | |
| assert_eq!(mem::align_of_val(&*large), 0x10000); | |
| assert!(is_aligned_to(&*large, 0x10000)); | |
| } |