about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-22 11:50:40 +0000
committerbors <bors@rust-lang.org>2017-04-22 11:50:40 +0000
commit6d841da4a0d7629f826117f99052e3d4a7997a7e (patch)
tree27e04604a86c867e8146bf75ff0c1ea973aaf47c /src/test
parentff13b7c91813eb178c98a7abc661acaf5c41dc31 (diff)
parent946f8e6a59242a8112c6983d1336fef54bc55b9a (diff)
Auto merge of #39999 - bitshifter:struct_align, r=eddyb
Implementation of repr struct alignment RFC 1358.

The main changes around rustc::ty::Layout::struct:
* Added abi_align field which stores abi alignment before repr align is applied
* align field contains transitive repr alignment
* Added padding vec which stores padding required after fields

The main user of this information is rustc_trans::adt::struct_llfields
which determines the LLVM fields to be used by LLVM, including padding
fields.

A possible future optimisation would be to put the padding Vec in an Option, since it will be unused unless you are using repr align.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/compile-fail/attr-usage-repr.rs4
-rw-r--r--src/test/compile-fail/conflicting-repr-hints.rs9
-rw-r--r--src/test/compile-fail/feature-gate-repr_align.rs15
-rw-r--r--src/test/compile-fail/repr-align.rs23
-rw-r--r--src/test/compile-fail/repr-packed-contains-align.rs25
-rw-r--r--src/test/run-pass/align-struct.rs196
-rw-r--r--src/test/ui/print_type_sizes/repr-align.rs43
-rw-r--r--src/test/ui/print_type_sizes/repr-align.stdout16
8 files changed, 328 insertions, 3 deletions
diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs
index b07d3e2f906..c0bfd3690c8 100644
--- a/src/test/compile-fail/attr-usage-repr.rs
+++ b/src/test/compile-fail/attr-usage-repr.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![allow(dead_code)]
+#![feature(attr_literals)]
 #![feature(repr_simd)]
 
 #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
@@ -29,6 +30,9 @@ struct SInt(f64, f64);
 #[repr(C)]
 enum EExtern { A, B }
 
+#[repr(align(8))] //~ ERROR: attribute should be applied to struct
+enum EAlign { A, B }
+
 #[repr(packed)] //~ ERROR: attribute should be applied to struct
 enum EPacked { A, B }
 
diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs
index 9e0c0d845ca..01fa3ffbaa6 100644
--- a/src/test/compile-fail/conflicting-repr-hints.rs
+++ b/src/test/compile-fail/conflicting-repr-hints.rs
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
 #![allow(dead_code)]
+#![feature(attr_literals)]
+#![feature(repr_align)]
 
 #[repr(C)]
 enum A { A }
@@ -26,5 +27,7 @@ enum D { D }
 #[repr(C, packed)]
 struct E(i32);
 
-#[rustc_error]
-fn main() {} //~ ERROR compilation successful
+#[repr(packed, align(8))] //~ ERROR conflicting packed and align representation hints
+struct F(i32);
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-repr_align.rs b/src/test/compile-fail/feature-gate-repr_align.rs
new file mode 100644
index 00000000000..8e986e197f2
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-repr_align.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(attr_literals)]
+
+#[repr(align(64))]
+struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental
+
+fn main() {}
diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs
new file mode 100644
index 00000000000..eb0b27fe9c0
--- /dev/null
+++ b/src/test/compile-fail/repr-align.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![allow(dead_code)]
+#![feature(attr_literals)]
+#![feature(repr_align)]
+
+#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
+struct A(i32);
+
+#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+struct B(i32);
+
+#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768
+struct C(i32);
+
+fn main() {}
diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs
new file mode 100644
index 00000000000..c584dcf3e59
--- /dev/null
+++ b/src/test/compile-fail/repr-packed-contains-align.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+#![allow(dead_code)]
+
+#[repr(align(16))]
+struct A(i32);
+
+struct B(A);
+
+#[repr(packed)]
+struct C(A); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
+
+#[repr(packed)]
+struct D(B); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct
+
+fn main() {}
diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs
new file mode 100644
index 00000000000..0b9a3594502
--- /dev/null
+++ b/src/test/run-pass/align-struct.rs
@@ -0,0 +1,196 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+
+use std::mem;
+
+// Raising alignment
+#[repr(align(16))]
+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,
+}
+
+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));
+
+    // 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));
+}
diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs
new file mode 100644
index 00000000000..e9b43145de4
--- /dev/null
+++ b/src/test/ui/print_type_sizes/repr-align.rs
@@ -0,0 +1,43 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how padding is handled: alignment
+// requirements can lead to the introduction of padding, either before
+// fields or at the end of the structure as a whole.
+//
+// It avoids using u64/i64 because on some targets that is only 4-byte
+// aligned (while on most it is 8-byte aligned) and so the resulting
+// padding and overall computed sizes can be quite different.
+#![feature(attr_literals)]
+#![feature(repr_align)]
+#![allow(dead_code)]
+
+#[repr(align(16))]
+#[derive(Default)]
+struct A(i32);
+
+enum E {
+    A(i32),
+    B(A)
+}
+
+#[derive(Default)]
+struct S {
+    a: i32,
+    b: i32,
+    c: A,
+    d: i8,
+}
+
+fn main() {
+    let _s: S = Default::default();
+}
diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout
new file mode 100644
index 00000000000..7df12f040b1
--- /dev/null
+++ b/src/test/ui/print_type_sizes/repr-align.stdout
@@ -0,0 +1,16 @@
+print-type-size type: `E`: 32 bytes, alignment: 16 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `A`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `B`: 28 bytes
+print-type-size         padding: 12 bytes
+print-type-size         field `.0`: 16 bytes, alignment: 16 bytes
+print-type-size type: `S`: 32 bytes, alignment: 16 bytes
+print-type-size     field `.c`: 16 bytes
+print-type-size     field `.a`: 4 bytes
+print-type-size     field `.b`: 4 bytes
+print-type-size     field `.d`: 1 bytes
+print-type-size     end padding: 7 bytes
+print-type-size type: `A`: 16 bytes, alignment: 16 bytes
+print-type-size     field `.0`: 4 bytes
+print-type-size     end padding: 12 bytes