]> git.lizzy.rs Git - rust.git/blob - src/test/ui/structs-enums/align-struct.rs
Rollup merge of #106043 - c410-f3r:moar-errors, r=petrochenkov
[rust.git] / src / test / ui / structs-enums / align-struct.rs
1 // run-pass
2 #![allow(dead_code)]
3
4 use std::mem;
5
6 // Raising alignment
7 #[repr(align(16))]
8 #[derive(Clone, Copy, Debug)]
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
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
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
74 union UnionContainsAlign {
75     a: Align16,
76     b: f32
77 }
78
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
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
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));
224
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
234     let mut large = Box::new(AlignLarge {
235         stuff: [0; 0x10000],
236     });
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));
244 }