// run-pass // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck #![allow(dead_code)] // Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations. // // For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no // bit-value that an `Option` could reuse as `None`; this test makes sure that isn't done. // // Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such // optimizations to types containing unions even if they're theoretically possible. (discussion: // https://github.com/rust-lang/rust/issues/36394) // // Notably this nails down part of the behavior that `MaybeUninit` assumes: that an // `Option>` does not take advantage of non-zero optimization, and thus is a safe // construct. use std::mem::{size_of, transmute}; union U1 { a: A, } union U2 { a: A, b: B, } // Option uses a value other than 0 and 1 as None #[derive(Clone,Copy)] enum E { A = 0, B = 1, } fn main() { // Unions do not participate in niche-filling/non-zero optimization... assert!(size_of::>>() > size_of::>()); assert!(size_of::>>() > size_of::>()); assert!(size_of::>>() > size_of::>()); // ...even when theoretically possible: assert!(size_of::>>() > size_of::>()); assert!(size_of::>>() > size_of::>()); // The unused bits of the () variant can have any value. let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::()) }; if let None = Some(zeroed) { panic!() } }