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