]> git.proxmox.com Git - rustc.git/blob - library/core/tests/mem.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / library / core / tests / mem.rs
1 use core::mem::*;
2 use core::ptr;
3
4 #[cfg(panic = "unwind")]
5 use std::rc::Rc;
6
7 #[test]
8 fn size_of_basic() {
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);
13 }
14
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
22 #[test]
23 #[cfg(target_pointer_width = "32")]
24 fn size_of_32() {
25 assert_eq!(size_of::<usize>(), 4);
26 assert_eq!(size_of::<*const usize>(), 4);
27 }
28
29 #[test]
30 #[cfg(target_pointer_width = "64")]
31 fn size_of_64() {
32 assert_eq!(size_of::<usize>(), 8);
33 assert_eq!(size_of::<*const usize>(), 8);
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() {
46 assert_eq!(align_of::<u8>(), 1);
47 assert_eq!(align_of::<u16>(), 2);
48 assert_eq!(align_of::<u32>(), 4);
49 }
50
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
58 #[test]
59 #[cfg(target_pointer_width = "32")]
60 fn align_of_32() {
61 assert_eq!(align_of::<usize>(), 4);
62 assert_eq!(align_of::<*const usize>(), 4);
63 }
64
65 #[test]
66 #[cfg(target_pointer_width = "64")]
67 fn align_of_64() {
68 assert_eq!(align_of::<usize>(), 8);
69 assert_eq!(align_of::<*const usize>(), 8);
70 }
71
72 #[test]
73 fn align_of_val_basic() {
74 assert_eq!(align_of_val(&1u8), 1);
75 assert_eq!(align_of_val(&1u16), 2);
76 assert_eq!(align_of_val(&1u32), 4);
77 }
78
79 #[test]
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
97 #[test]
98 fn test_swap() {
99 let mut x = 31337;
100 let mut y = 42;
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() {
116 assert_eq!(1, unsafe { transmute_copy(&1) });
117 }
118
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| {
152 if *s == "cannot transmute_copy if Dst is larger than Src" {
153 Ok(s)
154 } else {
155 Err(s)
156 }
157 })
158 .unwrap_or_else(|p| panic::resume_unwind(p));
159 }
160 }
161 }
162
163 #[test]
164 #[allow(dead_code)]
165 fn test_discriminant_send_sync() {
166 enum Regular {
167 A,
168 B(i32),
169 }
170 enum NotSendSync {
171 A(*const i32),
172 }
173
174 fn is_send_sync<T: Send + Sync>() {}
175
176 is_send_sync::<Discriminant<Regular>>();
177 is_send_sync::<Discriminant<NotSendSync>>();
178 }
179
180 #[test]
181 fn assume_init_good() {
182 const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };
183
184 assert!(TRUE);
185 }
186
187 #[test]
188 fn uninit_array_assume_init() {
189 let mut array = [MaybeUninit::<i16>::uninit(); 5];
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
196 let array = unsafe { array.transpose().assume_init() };
197
198 assert_eq!(array, [3, 1, 4, 1, 5]);
199
200 let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].transpose().assume_init() };
201 }
202
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 }
329
330 #[test]
331 fn uninit_const_assume_init_read() {
332 const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
333 assert_eq!(FOO, 42);
334 }
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 }
367
368 #[test]
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,
393 z: T,
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]
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]
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]
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]
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]
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]
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]
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]
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 }
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 }