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