]>
Commit | Line | Data |
---|---|---|
48663c56 | 1 | // run-pass |
136023e0 XL |
2 | // revisions: mirunsafeck thirunsafeck |
3 | // [thirunsafeck]compile-flags: -Z thir-unsafeck | |
4 | ||
48663c56 XL |
5 | #![allow(dead_code)] |
6 | ||
7 | // Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations. | |
8 | // | |
9 | // For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no | |
10 | // bit-value that an `Option<U>` could reuse as `None`; this test makes sure that isn't done. | |
11 | // | |
12 | // Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such | |
13 | // optimizations to types containing unions even if they're theoretically possible. (discussion: | |
14 | // https://github.com/rust-lang/rust/issues/36394) | |
15 | // | |
16 | // Notably this nails down part of the behavior that `MaybeUninit` assumes: that a | |
17 | // `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe | |
18 | // construct. | |
19 | ||
20 | use std::mem::{size_of, transmute}; | |
21 | ||
22 | union U1<A: Copy> { | |
23 | a: A, | |
24 | } | |
25 | ||
26 | union U2<A: Copy, B: Copy> { | |
27 | a: A, | |
28 | b: B, | |
29 | } | |
30 | ||
31 | // Option<E> uses a value other than 0 and 1 as None | |
32 | #[derive(Clone,Copy)] | |
33 | enum E { | |
34 | A = 0, | |
35 | B = 1, | |
36 | } | |
37 | ||
38 | fn main() { | |
39 | // Unions do not participate in niche-filling/non-zero optimization... | |
40 | assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>()); | |
41 | assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>()); | |
42 | assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>()); | |
43 | ||
44 | // ...even when theoretically possible: | |
45 | assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>()); | |
46 | assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>()); | |
47 | ||
48 | // The unused bits of the () variant can have any value. | |
49 | let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) }; | |
50 | ||
51 | if let None = Some(zeroed) { | |
52 | panic!() | |
53 | } | |
54 | } |