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