]> git.proxmox.com Git - rustc.git/blob - src/test/ui/run-pass/structs-enums/align-struct.rs
New upstream version 1.30.0+dfsg1
[rustc.git] / src / test / ui / run-pass / structs-enums / align-struct.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // run-pass
12 #![feature(box_syntax)]
13 #![feature(repr_packed)]
14
15 use std::mem;
16
17 // Raising alignment
18 #[repr(align(16))]
19 #[derive(Clone, Copy, Debug)]
20 struct Align16(i32);
21
22 // Lowering has no effect
23 #[repr(align(1))]
24 struct Align1(i32);
25
26 // Multiple attributes take the max
27 #[repr(align(4))]
28 #[repr(align(16))]
29 #[repr(align(8))]
30 struct AlignMany(i32);
31
32 // Raising alignment may not alter size.
33 #[repr(align(8))]
34 #[allow(dead_code)]
35 struct Align8Many {
36 a: i32,
37 b: i32,
38 c: i32,
39 d: u8,
40 }
41
42 enum Enum {
43 #[allow(dead_code)]
44 A(i32),
45 B(Align16)
46 }
47
48 // Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test
49 #[repr(C)]
50 struct Nested {
51 a: i32,
52 b: i32,
53 c: Align16,
54 d: i8,
55 }
56
57 #[repr(packed)]
58 struct Packed(i32);
59
60 #[repr(align(16))]
61 struct AlignContainsPacked {
62 a: Packed,
63 b: Packed,
64 }
65
66 #[repr(C, packed(4))]
67 struct Packed4C {
68 a: u32,
69 b: u64,
70 }
71
72 #[repr(align(16))]
73 struct AlignContainsPacked4C {
74 a: Packed4C,
75 b: u64,
76 }
77
78 // The align limit was originally smaller (2^15).
79 // Check that it works with big numbers.
80 #[repr(align(0x10000))]
81 struct AlignLarge {
82 stuff: [u8; 0x10000],
83 }
84
85 union UnionContainsAlign {
86 a: Align16,
87 b: f32
88 }
89
90 impl Align16 {
91 // return aligned type
92 pub fn new(i: i32) -> Align16 {
93 Align16(i)
94 }
95 // pass aligned type
96 pub fn consume(a: Align16) -> i32 {
97 a.0
98 }
99 }
100
101 const CONST_ALIGN16: Align16 = Align16(7);
102 static STATIC_ALIGN16: Align16 = Align16(8);
103
104 // Check the actual address is aligned
105 fn is_aligned_to<T>(p: &T, align: usize) -> bool {
106 let addr = p as *const T as usize;
107 (addr & (align - 1)) == 0
108 }
109
110 pub fn main() {
111 // check alignment and size by type and value
112 assert_eq!(mem::align_of::<Align16>(), 16);
113 assert_eq!(mem::size_of::<Align16>(), 16);
114
115 let a = Align16(7);
116 assert_eq!(a.0, 7);
117 assert_eq!(mem::align_of_val(&a), 16);
118 assert_eq!(mem::size_of_val(&a), 16);
119
120 assert!(is_aligned_to(&a, 16));
121
122 // lowering should have no effect
123 assert_eq!(mem::align_of::<Align1>(), 4);
124 assert_eq!(mem::size_of::<Align1>(), 4);
125 let a = Align1(7);
126 assert_eq!(a.0, 7);
127 assert_eq!(mem::align_of_val(&a), 4);
128 assert_eq!(mem::size_of_val(&a), 4);
129 assert!(is_aligned_to(&a, 4));
130
131 // when multiple attributes are specified the max should be used
132 assert_eq!(mem::align_of::<AlignMany>(), 16);
133 assert_eq!(mem::size_of::<AlignMany>(), 16);
134 let a = AlignMany(7);
135 assert_eq!(a.0, 7);
136 assert_eq!(mem::align_of_val(&a), 16);
137 assert_eq!(mem::size_of_val(&a), 16);
138 assert!(is_aligned_to(&a, 16));
139
140 // raising alignment should not reduce size
141 assert_eq!(mem::align_of::<Align8Many>(), 8);
142 assert_eq!(mem::size_of::<Align8Many>(), 16);
143 let a = Align8Many { a: 1, b: 2, c: 3, d: 4 };
144 assert_eq!(a.a, 1);
145 assert_eq!(mem::align_of_val(&a), 8);
146 assert_eq!(mem::size_of_val(&a), 16);
147 assert!(is_aligned_to(&a, 8));
148
149 // return type
150 let a = Align16::new(1);
151 assert_eq!(mem::align_of_val(&a), 16);
152 assert_eq!(mem::size_of_val(&a), 16);
153 assert_eq!(a.0, 1);
154 assert!(is_aligned_to(&a, 16));
155 assert_eq!(Align16::consume(a), 1);
156
157 // check const alignment, size and value
158 assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16);
159 assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16);
160 assert_eq!(CONST_ALIGN16.0, 7);
161 assert!(is_aligned_to(&CONST_ALIGN16, 16));
162
163 // check global static alignment, size and value
164 assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16);
165 assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16);
166 assert_eq!(STATIC_ALIGN16.0, 8);
167 assert!(is_aligned_to(&STATIC_ALIGN16, 16));
168
169 // Note that the size of Nested may change if struct field re-ordering is enabled
170 assert_eq!(mem::align_of::<Nested>(), 16);
171 assert_eq!(mem::size_of::<Nested>(), 48);
172 let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4};
173 assert_eq!(mem::align_of_val(&a), 16);
174 assert_eq!(mem::align_of_val(&a.b), 4);
175 assert_eq!(mem::align_of_val(&a.c), 16);
176 assert_eq!(mem::size_of_val(&a), 48);
177 assert!(is_aligned_to(&a, 16));
178 // check the correct fields are indexed
179 assert_eq!(a.a, 1);
180 assert_eq!(a.b, 2);
181 assert_eq!(a.c.0, 3);
182 assert_eq!(a.d, 4);
183
184 // enum should be aligned to max alignment
185 assert_eq!(mem::align_of::<Enum>(), 16);
186 assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16);
187 let e = Enum::B(Align16(15));
188 match e {
189 Enum::B(ref a) => {
190 assert_eq!(a.0, 15);
191 assert_eq!(mem::align_of_val(a), 16);
192 assert_eq!(mem::size_of_val(a), 16);
193 },
194 _ => ()
195 }
196 assert!(is_aligned_to(&e, 16));
197
198 // check union alignment
199 assert_eq!(mem::align_of::<UnionContainsAlign>(), 16);
200 assert_eq!(mem::size_of::<UnionContainsAlign>(), 16);
201 let u = UnionContainsAlign { a: Align16(10) };
202 unsafe {
203 assert_eq!(mem::align_of_val(&u.a), 16);
204 assert_eq!(mem::size_of_val(&u.a), 16);
205 assert_eq!(u.a.0, 10);
206 let UnionContainsAlign { a } = u;
207 assert_eq!(a.0, 10);
208 }
209
210 // arrays of aligned elements should also be aligned
211 assert_eq!(mem::align_of::<[Align16;2]>(), 16);
212 assert_eq!(mem::size_of::<[Align16;2]>(), 32);
213
214 let a = [Align16(0), Align16(1)];
215 assert_eq!(mem::align_of_val(&a[0]), 16);
216 assert_eq!(mem::align_of_val(&a[1]), 16);
217 assert!(is_aligned_to(&a, 16));
218
219 // check heap value is aligned
220 assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16);
221
222 // check heap array is aligned
223 let a = vec!(Align16(0), Align16(1));
224 assert_eq!(mem::align_of_val(&a[0]), 16);
225 assert_eq!(mem::align_of_val(&a[1]), 16);
226
227 assert_eq!(mem::align_of::<AlignContainsPacked>(), 16);
228 assert_eq!(mem::size_of::<AlignContainsPacked>(), 16);
229 let a = AlignContainsPacked { a: Packed(1), b: Packed(2) };
230 assert_eq!(mem::align_of_val(&a), 16);
231 assert_eq!(mem::align_of_val(&a.a), 1);
232 assert_eq!(mem::align_of_val(&a.b), 1);
233 assert_eq!(mem::size_of_val(&a), 16);
234 assert!(is_aligned_to(&a, 16));
235
236 assert_eq!(mem::align_of::<AlignContainsPacked4C>(), 16);
237 assert_eq!(mem::size_of::<AlignContainsPacked4C>(), 32);
238 let a = AlignContainsPacked4C { a: Packed4C{ a: 1, b: 2 }, b: 3 };
239 assert_eq!(mem::align_of_val(&a), 16);
240 assert_eq!(mem::align_of_val(&a.a), 4);
241 assert_eq!(mem::align_of_val(&a.b), mem::align_of::<u64>());
242 assert_eq!(mem::size_of_val(&a), 32);
243 assert!(is_aligned_to(&a, 16));
244
245 let mut large = box AlignLarge {
246 stuff: [0; 0x10000],
247 };
248 large.stuff[0] = 132;
249 *large.stuff.last_mut().unwrap() = 102;
250 assert_eq!(large.stuff[0], 132);
251 assert_eq!(large.stuff.last(), Some(&102));
252 assert_eq!(mem::align_of::<AlignLarge>(), 0x10000);
253 assert_eq!(mem::align_of_val(&*large), 0x10000);
254 assert!(is_aligned_to(&*large, 0x10000));
255 }