summaryrefslogtreecommitdiffstats
path: root/src/test/ui/union/union-nonzero.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/union/union-nonzero.rs
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/union/union-nonzero.rs')
-rw-r--r--src/test/ui/union/union-nonzero.rs54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/test/ui/union/union-nonzero.rs b/src/test/ui/union/union-nonzero.rs
new file mode 100644
index 000000000..3f4f7ea1c
--- /dev/null
+++ b/src/test/ui/union/union-nonzero.rs
@@ -0,0 +1,54 @@
+// 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<U>` 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<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
+// construct.
+
+use std::mem::{size_of, transmute};
+
+union U1<A: Copy> {
+ a: A,
+}
+
+union U2<A: Copy, B: Copy> {
+ a: A,
+ b: B,
+}
+
+// Option<E> 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::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
+ assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
+ assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
+
+ // ...even when theoretically possible:
+ assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
+ assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
+
+ // The unused bits of the () variant can have any value.
+ let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
+
+ if let None = Some(zeroed) {
+ panic!()
+ }
+}