]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | use core::mem::*; |
487cf647 | 2 | use core::ptr; |
1a4d82fc | 3 | |
fc512014 XL |
4 | #[cfg(panic = "unwind")] |
5 | use std::rc::Rc; | |
6 | ||
1a4d82fc JJ |
7 | #[test] |
8 | fn size_of_basic() { | |
85aaf69f SL |
9 | assert_eq!(size_of::<u8>(), 1); |
10 | assert_eq!(size_of::<u16>(), 2); | |
11 | assert_eq!(size_of::<u32>(), 4); | |
12 | assert_eq!(size_of::<u64>(), 8); | |
1a4d82fc JJ |
13 | } |
14 | ||
3157f602 XL |
15 | #[test] |
16 | #[cfg(target_pointer_width = "16")] | |
17 | fn size_of_16() { | |
18 | assert_eq!(size_of::<usize>(), 2); | |
19 | assert_eq!(size_of::<*const usize>(), 2); | |
20 | } | |
21 | ||
1a4d82fc | 22 | #[test] |
85aaf69f | 23 | #[cfg(target_pointer_width = "32")] |
1a4d82fc | 24 | fn size_of_32() { |
c34b1796 AL |
25 | assert_eq!(size_of::<usize>(), 4); |
26 | assert_eq!(size_of::<*const usize>(), 4); | |
1a4d82fc JJ |
27 | } |
28 | ||
29 | #[test] | |
85aaf69f | 30 | #[cfg(target_pointer_width = "64")] |
1a4d82fc | 31 | fn size_of_64() { |
c34b1796 AL |
32 | assert_eq!(size_of::<usize>(), 8); |
33 | assert_eq!(size_of::<*const usize>(), 8); | |
1a4d82fc JJ |
34 | } |
35 | ||
36 | #[test] | |
37 | fn size_of_val_basic() { | |
38 | assert_eq!(size_of_val(&1u8), 1); | |
39 | assert_eq!(size_of_val(&1u16), 2); | |
40 | assert_eq!(size_of_val(&1u32), 4); | |
41 | assert_eq!(size_of_val(&1u64), 8); | |
42 | } | |
43 | ||
44 | #[test] | |
45 | fn align_of_basic() { | |
85aaf69f SL |
46 | assert_eq!(align_of::<u8>(), 1); |
47 | assert_eq!(align_of::<u16>(), 2); | |
48 | assert_eq!(align_of::<u32>(), 4); | |
1a4d82fc JJ |
49 | } |
50 | ||
3157f602 XL |
51 | #[test] |
52 | #[cfg(target_pointer_width = "16")] | |
53 | fn align_of_16() { | |
54 | assert_eq!(align_of::<usize>(), 2); | |
55 | assert_eq!(align_of::<*const usize>(), 2); | |
56 | } | |
57 | ||
1a4d82fc | 58 | #[test] |
85aaf69f | 59 | #[cfg(target_pointer_width = "32")] |
1a4d82fc | 60 | fn align_of_32() { |
c34b1796 AL |
61 | assert_eq!(align_of::<usize>(), 4); |
62 | assert_eq!(align_of::<*const usize>(), 4); | |
1a4d82fc JJ |
63 | } |
64 | ||
65 | #[test] | |
85aaf69f | 66 | #[cfg(target_pointer_width = "64")] |
1a4d82fc | 67 | fn align_of_64() { |
c34b1796 AL |
68 | assert_eq!(align_of::<usize>(), 8); |
69 | assert_eq!(align_of::<*const usize>(), 8); | |
1a4d82fc JJ |
70 | } |
71 | ||
72 | #[test] | |
73 | fn align_of_val_basic() { | |
85aaf69f SL |
74 | assert_eq!(align_of_val(&1u8), 1); |
75 | assert_eq!(align_of_val(&1u16), 2); | |
76 | assert_eq!(align_of_val(&1u32), 4); | |
1a4d82fc JJ |
77 | } |
78 | ||
487cf647 | 79 | #[test] |
487cf647 FG |
80 | fn align_of_val_raw_packed() { |
81 | #[repr(C, packed)] | |
82 | struct B { | |
83 | f: [u32], | |
84 | } | |
85 | let storage = [0u8; 4]; | |
86 | let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); | |
87 | assert_eq!(unsafe { align_of_val_raw(b) }, 1); | |
88 | ||
89 | const ALIGN_OF_VAL_RAW: usize = { | |
90 | let storage = [0u8; 4]; | |
91 | let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); | |
92 | unsafe { align_of_val_raw(b) } | |
93 | }; | |
94 | assert_eq!(ALIGN_OF_VAL_RAW, 1); | |
95 | } | |
96 | ||
1a4d82fc JJ |
97 | #[test] |
98 | fn test_swap() { | |
85aaf69f SL |
99 | let mut x = 31337; |
100 | let mut y = 42; | |
1a4d82fc JJ |
101 | swap(&mut x, &mut y); |
102 | assert_eq!(x, 42); | |
103 | assert_eq!(y, 31337); | |
104 | } | |
105 | ||
106 | #[test] | |
107 | fn test_replace() { | |
108 | let mut x = Some("test".to_string()); | |
109 | let y = replace(&mut x, None); | |
110 | assert!(x.is_none()); | |
111 | assert!(y.is_some()); | |
112 | } | |
113 | ||
114 | #[test] | |
115 | fn test_transmute_copy() { | |
85aaf69f | 116 | assert_eq!(1, unsafe { transmute_copy(&1) }); |
1a4d82fc JJ |
117 | } |
118 | ||
064997fb FG |
119 | #[test] |
120 | fn test_transmute_copy_shrink() { | |
121 | assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); | |
122 | } | |
123 | ||
124 | #[test] | |
125 | fn test_transmute_copy_unaligned() { | |
126 | #[repr(C)] | |
127 | #[derive(Default)] | |
128 | struct Unaligned { | |
129 | a: u8, | |
130 | b: [u8; 8], | |
131 | } | |
132 | ||
133 | let u = Unaligned::default(); | |
134 | assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); | |
135 | } | |
136 | ||
137 | #[test] | |
138 | #[cfg(panic = "unwind")] | |
139 | fn test_transmute_copy_grow_panics() { | |
140 | use std::panic; | |
141 | ||
142 | let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { | |
143 | let _unused: u64 = transmute_copy(&1_u8); | |
144 | })); | |
145 | ||
146 | match err { | |
147 | Ok(_) => unreachable!(), | |
148 | Err(payload) => { | |
149 | payload | |
150 | .downcast::<&'static str>() | |
151 | .and_then(|s| { | |
2b03887a FG |
152 | if *s == "cannot transmute_copy if Dst is larger than Src" { |
153 | Ok(s) | |
154 | } else { | |
155 | Err(s) | |
156 | } | |
064997fb FG |
157 | }) |
158 | .unwrap_or_else(|p| panic::resume_unwind(p)); | |
159 | } | |
160 | } | |
161 | } | |
162 | ||
abe05a73 XL |
163 | #[test] |
164 | #[allow(dead_code)] | |
165 | fn test_discriminant_send_sync() { | |
166 | enum Regular { | |
167 | A, | |
60c5eb7d | 168 | B(i32), |
abe05a73 XL |
169 | } |
170 | enum NotSendSync { | |
60c5eb7d | 171 | A(*const i32), |
abe05a73 XL |
172 | } |
173 | ||
60c5eb7d | 174 | fn is_send_sync<T: Send + Sync>() {} |
abe05a73 XL |
175 | |
176 | is_send_sync::<Discriminant<Regular>>(); | |
177 | is_send_sync::<Discriminant<NotSendSync>>(); | |
178 | } | |
fc512014 XL |
179 | |
180 | #[test] | |
fc512014 XL |
181 | fn assume_init_good() { |
182 | const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() }; | |
183 | ||
184 | assert!(TRUE); | |
185 | } | |
186 | ||
5869c6ff XL |
187 | #[test] |
188 | fn uninit_array_assume_init() { | |
2b03887a | 189 | let mut array = [MaybeUninit::<i16>::uninit(); 5]; |
5869c6ff XL |
190 | array[0].write(3); |
191 | array[1].write(1); | |
192 | array[2].write(4); | |
193 | array[3].write(1); | |
194 | array[4].write(5); | |
195 | ||
2b03887a | 196 | let array = unsafe { array.transpose().assume_init() }; |
5869c6ff XL |
197 | |
198 | assert_eq!(array, [3, 1, 4, 1, 5]); | |
199 | ||
2b03887a | 200 | let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].transpose().assume_init() }; |
5869c6ff XL |
201 | } |
202 | ||
fc512014 XL |
203 | #[test] |
204 | fn uninit_write_slice() { | |
205 | let mut dst = [MaybeUninit::new(255); 64]; | |
206 | let src = [0; 64]; | |
207 | ||
208 | assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src); | |
209 | } | |
210 | ||
211 | #[test] | |
212 | #[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] | |
213 | fn uninit_write_slice_panic_lt() { | |
214 | let mut dst = [MaybeUninit::uninit(); 64]; | |
215 | let src = [0; 32]; | |
216 | ||
217 | MaybeUninit::write_slice(&mut dst, &src); | |
218 | } | |
219 | ||
220 | #[test] | |
221 | #[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] | |
222 | fn uninit_write_slice_panic_gt() { | |
223 | let mut dst = [MaybeUninit::uninit(); 64]; | |
224 | let src = [0; 128]; | |
225 | ||
226 | MaybeUninit::write_slice(&mut dst, &src); | |
227 | } | |
228 | ||
229 | #[test] | |
230 | fn uninit_clone_from_slice() { | |
231 | let mut dst = [MaybeUninit::new(255); 64]; | |
232 | let src = [0; 64]; | |
233 | ||
234 | assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src); | |
235 | } | |
236 | ||
237 | #[test] | |
238 | #[should_panic(expected = "destination and source slices have different lengths")] | |
239 | fn uninit_write_slice_cloned_panic_lt() { | |
240 | let mut dst = [MaybeUninit::uninit(); 64]; | |
241 | let src = [0; 32]; | |
242 | ||
243 | MaybeUninit::write_slice_cloned(&mut dst, &src); | |
244 | } | |
245 | ||
246 | #[test] | |
247 | #[should_panic(expected = "destination and source slices have different lengths")] | |
248 | fn uninit_write_slice_cloned_panic_gt() { | |
249 | let mut dst = [MaybeUninit::uninit(); 64]; | |
250 | let src = [0; 128]; | |
251 | ||
252 | MaybeUninit::write_slice_cloned(&mut dst, &src); | |
253 | } | |
254 | ||
255 | #[test] | |
256 | #[cfg(panic = "unwind")] | |
257 | fn uninit_write_slice_cloned_mid_panic() { | |
258 | use std::panic; | |
259 | ||
260 | enum IncrementOrPanic { | |
261 | Increment(Rc<()>), | |
262 | ExpectedPanic, | |
263 | UnexpectedPanic, | |
264 | } | |
265 | ||
266 | impl Clone for IncrementOrPanic { | |
267 | fn clone(&self) -> Self { | |
268 | match self { | |
269 | Self::Increment(rc) => Self::Increment(rc.clone()), | |
270 | Self::ExpectedPanic => panic!("expected panic on clone"), | |
271 | Self::UnexpectedPanic => panic!("unexpected panic on clone"), | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | let rc = Rc::new(()); | |
277 | ||
278 | let mut dst = [ | |
279 | MaybeUninit::uninit(), | |
280 | MaybeUninit::uninit(), | |
281 | MaybeUninit::uninit(), | |
282 | MaybeUninit::uninit(), | |
283 | ]; | |
284 | ||
285 | let src = [ | |
286 | IncrementOrPanic::Increment(rc.clone()), | |
287 | IncrementOrPanic::Increment(rc.clone()), | |
288 | IncrementOrPanic::ExpectedPanic, | |
289 | IncrementOrPanic::UnexpectedPanic, | |
290 | ]; | |
291 | ||
292 | let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { | |
293 | MaybeUninit::write_slice_cloned(&mut dst, &src); | |
294 | })); | |
295 | ||
296 | drop(src); | |
297 | ||
298 | match err { | |
299 | Ok(_) => unreachable!(), | |
300 | Err(payload) => { | |
301 | payload | |
302 | .downcast::<&'static str>() | |
303 | .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) | |
304 | .unwrap_or_else(|p| panic::resume_unwind(p)); | |
305 | ||
306 | assert_eq!(Rc::strong_count(&rc), 1) | |
307 | } | |
308 | } | |
309 | } | |
310 | ||
311 | #[test] | |
312 | fn uninit_write_slice_cloned_no_drop() { | |
313 | #[derive(Clone)] | |
314 | struct Bomb; | |
315 | ||
316 | impl Drop for Bomb { | |
317 | fn drop(&mut self) { | |
318 | panic!("dropped a bomb! kaboom") | |
319 | } | |
320 | } | |
321 | ||
322 | let mut dst = [MaybeUninit::uninit()]; | |
323 | let src = [Bomb]; | |
324 | ||
325 | MaybeUninit::write_slice_cloned(&mut dst, &src); | |
326 | ||
327 | forget(src); | |
328 | } | |
5869c6ff XL |
329 | |
330 | #[test] | |
5869c6ff XL |
331 | fn uninit_const_assume_init_read() { |
332 | const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() }; | |
333 | assert_eq!(FOO, 42); | |
334 | } | |
a2a8927a XL |
335 | |
336 | #[test] | |
337 | fn const_maybe_uninit() { | |
338 | use std::ptr; | |
339 | ||
340 | #[derive(Debug, PartialEq)] | |
341 | struct Foo { | |
342 | x: u8, | |
343 | y: u8, | |
344 | } | |
345 | ||
346 | const FIELD_BY_FIELD: Foo = unsafe { | |
347 | let mut val = MaybeUninit::uninit(); | |
348 | init_y(&mut val); // order shouldn't matter | |
349 | init_x(&mut val); | |
350 | val.assume_init() | |
351 | }; | |
352 | ||
353 | const fn init_x(foo: &mut MaybeUninit<Foo>) { | |
354 | unsafe { | |
355 | *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1; | |
356 | } | |
357 | } | |
358 | ||
359 | const fn init_y(foo: &mut MaybeUninit<Foo>) { | |
360 | unsafe { | |
361 | *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2; | |
362 | } | |
363 | } | |
364 | ||
365 | assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 }); | |
366 | } | |
49aad941 FG |
367 | |
368 | #[test] | |
49aad941 FG |
369 | fn offset_of() { |
370 | #[repr(C)] | |
371 | struct Foo { | |
372 | x: u8, | |
373 | y: u16, | |
374 | z: Bar, | |
375 | } | |
376 | ||
377 | #[repr(C)] | |
378 | struct Bar(u8, u8); | |
379 | ||
380 | assert_eq!(offset_of!(Foo, x), 0); | |
381 | assert_eq!(offset_of!(Foo, y), 2); | |
382 | assert_eq!(offset_of!(Foo, z.0), 4); | |
383 | assert_eq!(offset_of!(Foo, z.1), 5); | |
384 | ||
385 | // Layout of tuples is unstable | |
386 | assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1); | |
387 | assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2); | |
388 | ||
389 | #[repr(C)] | |
390 | struct Generic<T> { | |
391 | x: u8, | |
392 | y: u32, | |
fe692bf9 | 393 | z: T, |
49aad941 FG |
394 | } |
395 | ||
396 | trait Trait {} | |
397 | ||
398 | // Ensure that this type of generics works | |
399 | fn offs_of_z<T>() -> usize { | |
400 | offset_of!(Generic<T>, z) | |
401 | } | |
402 | ||
403 | assert_eq!(offset_of!(Generic<u8>, z), 8); | |
404 | assert_eq!(offs_of_z::<u8>(), 8); | |
405 | ||
406 | // Ensure that it works with the implicit lifetime in `Box<dyn Trait + '_>`. | |
407 | assert_eq!(offset_of!(Generic<Box<dyn Trait>>, z), 8); | |
408 | } | |
409 | ||
410 | #[test] | |
49aad941 FG |
411 | fn offset_of_union() { |
412 | #[repr(C)] | |
413 | union Foo { | |
414 | x: u8, | |
415 | y: u16, | |
416 | z: Bar, | |
417 | } | |
418 | ||
419 | #[repr(C)] | |
420 | #[derive(Copy, Clone)] | |
421 | struct Bar(u8, u8); | |
422 | ||
423 | assert_eq!(offset_of!(Foo, x), 0); | |
424 | assert_eq!(offset_of!(Foo, y), 0); | |
425 | assert_eq!(offset_of!(Foo, z.0), 0); | |
426 | assert_eq!(offset_of!(Foo, z.1), 1); | |
427 | } | |
428 | ||
429 | #[test] | |
49aad941 FG |
430 | fn offset_of_dst() { |
431 | #[repr(C)] | |
432 | struct Alpha { | |
433 | x: u8, | |
434 | y: u16, | |
435 | z: [u8], | |
436 | } | |
437 | ||
438 | trait Trait {} | |
439 | ||
440 | #[repr(C)] | |
441 | struct Beta { | |
442 | x: u8, | |
443 | y: u16, | |
444 | z: dyn Trait, | |
445 | } | |
446 | ||
447 | extern "C" { | |
448 | type Extern; | |
449 | } | |
450 | ||
451 | #[repr(C)] | |
452 | struct Gamma { | |
453 | x: u8, | |
454 | y: u16, | |
455 | z: Extern, | |
456 | } | |
457 | ||
458 | assert_eq!(offset_of!(Alpha, x), 0); | |
459 | assert_eq!(offset_of!(Alpha, y), 2); | |
460 | ||
461 | assert_eq!(offset_of!(Beta, x), 0); | |
462 | assert_eq!(offset_of!(Beta, y), 2); | |
463 | ||
464 | assert_eq!(offset_of!(Gamma, x), 0); | |
465 | assert_eq!(offset_of!(Gamma, y), 2); | |
466 | } | |
467 | ||
468 | #[test] | |
49aad941 FG |
469 | fn offset_of_packed() { |
470 | #[repr(C, packed)] | |
471 | struct Foo { | |
472 | x: u8, | |
473 | y: u16, | |
474 | } | |
475 | ||
476 | assert_eq!(offset_of!(Foo, x), 0); | |
477 | assert_eq!(offset_of!(Foo, y), 1); | |
478 | } | |
479 | ||
480 | #[test] | |
49aad941 FG |
481 | fn offset_of_projection() { |
482 | #[repr(C)] | |
483 | struct Foo { | |
484 | x: u8, | |
485 | y: u16, | |
486 | } | |
487 | ||
488 | trait Projector { | |
489 | type Type; | |
490 | } | |
491 | ||
492 | impl Projector for () { | |
493 | type Type = Foo; | |
494 | } | |
495 | ||
496 | assert_eq!(offset_of!(<() as Projector>::Type, x), 0); | |
497 | assert_eq!(offset_of!(<() as Projector>::Type, y), 2); | |
498 | } | |
499 | ||
500 | #[test] | |
49aad941 FG |
501 | fn offset_of_alias() { |
502 | #[repr(C)] | |
503 | struct Foo { | |
504 | x: u8, | |
505 | y: u16, | |
506 | } | |
507 | ||
508 | type Bar = Foo; | |
509 | ||
510 | assert_eq!(offset_of!(Bar, x), 0); | |
511 | assert_eq!(offset_of!(Bar, y), 2); | |
512 | } | |
513 | ||
514 | #[test] | |
49aad941 FG |
515 | fn const_offset_of() { |
516 | #[repr(C)] | |
517 | struct Foo { | |
518 | x: u8, | |
519 | y: u16, | |
520 | } | |
521 | ||
522 | const X_OFFSET: usize = offset_of!(Foo, x); | |
523 | const Y_OFFSET: usize = offset_of!(Foo, y); | |
524 | ||
525 | assert_eq!(X_OFFSET, 0); | |
526 | assert_eq!(Y_OFFSET, 2); | |
527 | } | |
528 | ||
529 | #[test] | |
49aad941 FG |
530 | fn offset_of_without_const_promotion() { |
531 | #[repr(C)] | |
532 | struct Foo<SuppressConstPromotion> { | |
533 | x: u8, | |
534 | y: u16, | |
535 | _scp: SuppressConstPromotion, | |
536 | } | |
537 | ||
538 | // Normally, offset_of is always const promoted. | |
539 | // The generic parameter prevents this from happening. | |
540 | // This is needed to test the codegen impl of offset_of | |
541 | fn inner<SuppressConstPromotion>() { | |
542 | assert_eq!(offset_of!(Foo<SuppressConstPromotion>, x), 0); | |
543 | assert_eq!(offset_of!(Foo<SuppressConstPromotion>, y), 2); | |
544 | } | |
545 | ||
546 | inner::<()>(); | |
547 | } | |
548 | ||
549 | #[test] | |
49aad941 FG |
550 | fn offset_of_addr() { |
551 | #[repr(C)] | |
552 | struct Foo { | |
553 | x: u8, | |
554 | y: u16, | |
555 | z: Bar, | |
556 | } | |
557 | ||
558 | #[repr(C)] | |
559 | struct Bar(u8, u8); | |
560 | ||
561 | let base = Foo { x: 0, y: 0, z: Bar(0, 0) }; | |
562 | ||
563 | assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, x), ptr::addr_of!(base.x).addr()); | |
564 | assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, y), ptr::addr_of!(base.y).addr()); | |
565 | assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr()); | |
566 | assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr()); | |
567 | } | |
ed00b5ec FG |
568 | |
569 | #[test] | |
570 | fn const_maybe_uninit_zeroed() { | |
571 | // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term) | |
572 | #[repr(C)] | |
573 | struct Foo { | |
574 | a: Option<&'static str>, | |
575 | b: Bar, | |
576 | c: f32, | |
577 | d: *const u8, | |
578 | } | |
579 | #[repr(C)] | |
580 | struct Bar(usize); | |
581 | struct FooPtr(*const Foo); | |
582 | unsafe impl Sync for FooPtr {} | |
583 | ||
584 | static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr()); | |
585 | const SIZE: usize = size_of::<Foo>(); | |
586 | ||
587 | assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]); | |
588 | } |