]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | // For rust-lang/rust#68303: the contents of `UnsafeCell<T>` cannot |
2 | // participate in the niche-optimization for enum discriminants. This | |
3 | // test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same | |
4 | // size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes). | |
5 | ||
064997fb FG |
6 | // check-pass |
7 | // compile-flags: --crate-type=lib | |
8 | // only-x86 | |
74b04a01 | 9 | |
064997fb | 10 | #![feature(repr_simd)] |
74b04a01 | 11 | |
064997fb | 12 | use std::cell::{UnsafeCell, RefCell, Cell}; |
74b04a01 XL |
13 | use std::mem::size_of; |
14 | use std::num::NonZeroU32 as N32; | |
064997fb | 15 | use std::sync::{Mutex, RwLock}; |
74b04a01 | 16 | |
064997fb | 17 | struct Wrapper<T>(#[allow(unused_tuple_struct_fields)] T); |
74b04a01 XL |
18 | |
19 | #[repr(transparent)] | |
064997fb | 20 | struct Transparent<T>(#[allow(unused_tuple_struct_fields)] T); |
74b04a01 | 21 | |
064997fb | 22 | struct NoNiche<T>(UnsafeCell<T>); |
74b04a01 | 23 | |
064997fb | 24 | struct Size<const S: usize>; |
74b04a01 | 25 | |
064997fb FG |
26 | macro_rules! check_sizes { |
27 | (check_one_specific_size: $ty:ty, $size:expr) => { | |
28 | const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; | |
29 | }; | |
30 | // Any tests run on `UnsafeCell` must be the same for `Cell` | |
31 | (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => { | |
32 | check_sizes!(Cell<$ty>: $size => $optioned_size); | |
33 | check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size); | |
34 | }; | |
35 | ($ty:ty: $size:expr => $optioned_size:expr) => { | |
36 | check_sizes!(@actual_check: $ty: $size => $optioned_size); | |
37 | }; | |
38 | // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish | |
39 | // it from other branches and not accidentally match any. | |
40 | (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => { | |
41 | check_sizes!(check_one_specific_size: $ty, $size); | |
42 | check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); | |
43 | check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); | |
44 | }; | |
45 | // only check that there is no niche (size goes up when wrapped in an option), | |
46 | // don't check actual sizes | |
47 | ($ty:ty) => { | |
48 | check_sizes!(check_no_niche_opt: true, $ty); | |
49 | }; | |
50 | (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => { | |
51 | const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); }; | |
52 | }; | |
74b04a01 | 53 | } |
064997fb FG |
54 | |
55 | const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); | |
56 | ||
57 | check_sizes!(Wrapper<u32>: 4 => 8); | |
58 | check_sizes!(Wrapper<N32>: 4 => 4); // (✓ niche opt) | |
59 | check_sizes!(Transparent<u32>: 4 => 8); | |
60 | check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt) | |
61 | check_sizes!(NoNiche<u32>: 4 => 8); | |
62 | check_sizes!(NoNiche<N32>: 4 => 8); | |
63 | ||
64 | check_sizes!(UnsafeCell<u32>: 4 => 8); | |
65 | check_sizes!(UnsafeCell<N32>: 4 => 8); | |
66 | ||
67 | check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); | |
68 | check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); | |
69 | ||
70 | check_sizes!(RwLock<&()>); | |
71 | check_sizes!(Mutex<&()>); | |
72 | ||
73 | check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3); | |
74 | check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3); | |
75 | ||
76 | trait Trait {} | |
77 | check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); | |
78 | ||
79 | #[repr(simd)] | |
80 | pub struct Vec4<T>([T; 4]); | |
81 | ||
82 | check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32); |