summaryrefslogtreecommitdiffstats
path: root/src/test/ui/structs-enums/align-struct.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/structs-enums/align-struct.rs')
-rw-r--r--src/test/ui/structs-enums/align-struct.rs245
1 files changed, 245 insertions, 0 deletions
diff --git a/src/test/ui/structs-enums/align-struct.rs b/src/test/ui/structs-enums/align-struct.rs
new file mode 100644
index 000000000..27ef990aa
--- /dev/null
+++ b/src/test/ui/structs-enums/align-struct.rs
@@ -0,0 +1,245 @@
+// run-pass
+#![allow(dead_code)]
+#![feature(box_syntax)]
+
+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))]
+#[allow(dead_code)]
+struct Align8Many {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: u8,
+}
+
+enum Enum {
+ #[allow(dead_code)]
+ 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 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));
+}