//@ 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(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::(), 16); assert_eq!(mem::size_of::(), 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::(), 4); assert_eq!(mem::size_of::(), 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::(), 16); assert_eq!(mem::size_of::(), 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::(), 8); assert_eq!(mem::size_of::(), 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::(), 16); assert_eq!(mem::size_of::(), 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::(), 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::(), 16); assert_eq!(mem::size_of::(), 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::(), 16); assert_eq!(mem::size_of::(), 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::(), 16); assert_eq!(mem::size_of::(), 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::()); 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::(), 0x10000); assert_eq!(mem::align_of_val(&*large), 0x10000); assert!(is_aligned_to(&*large, 0x10000)); }