Skip to content

Commit 48d1be4

Browse files
committed
Test interaction of unions with non-zero/niche-filling optimization
Notably this nails down part of the behavior that MaybeUninit assumes, e.g. that a Option<MaybeUninit<&u8>> does not take advantage of non-zero optimization, and thus is a safe construct.
1 parent c3b8ab5 commit 48d1be4

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// run-pass
2+
#![allow(dead_code)]
3+
4+
use std::mem::{size_of, transmute};
5+
6+
union U1<A: Copy> {
7+
a: A,
8+
}
9+
10+
union U2<A: Copy, B: Copy> {
11+
a: A,
12+
b: B,
13+
}
14+
15+
fn main() {
16+
// Unions do not participate in niche-filling/non-zero optimization...
17+
assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
18+
assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
19+
20+
// ...even when theoretically possible:
21+
assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
22+
assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
23+
24+
// The unused bits of the () variant can have any value.
25+
let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
26+
27+
if let None = Some(zeroed) {
28+
panic!()
29+
}
30+
}

src/test/ui/print_type_sizes/niche-filling.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ pub enum Enum4<A, B, C, D> {
5757
Four(D)
5858
}
5959

60+
pub union Union1<A: Copy> {
61+
a: A,
62+
}
63+
64+
pub union Union2<A: Copy, B: Copy> {
65+
a: A,
66+
b: B,
67+
}
68+
6069
#[start]
6170
fn start(_: isize, _: *const *const u8) -> isize {
6271
let _x: MyOption<NonZeroU32> = Default::default();
@@ -69,5 +78,13 @@ fn start(_: isize, _: *const *const u8) -> isize {
6978
let _e: Enum4<(), char, (), ()> = Enum4::One(());
7079
let _f: Enum4<(), (), bool, ()> = Enum4::One(());
7180
let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());
81+
82+
// Unions do not currently participate in niche filling.
83+
let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();
84+
85+
// ...even when theoretically possible.
86+
let _i: MyOption<Union1<NonZeroU32>> = Default::default();
87+
let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
88+
7289
0
7390
}

src/test/ui/print_type_sizes/niche-filling.stdout

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ print-type-size field `.post`: 2 bytes
1414
print-type-size field `.pre`: 1 bytes
1515
print-type-size variant `None`: 0 bytes
1616
print-type-size end padding: 1 bytes
17+
print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
18+
print-type-size discriminant: 4 bytes
19+
print-type-size variant `Some`: 4 bytes
20+
print-type-size field `.0`: 4 bytes
21+
print-type-size variant `None`: 0 bytes
22+
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
23+
print-type-size discriminant: 4 bytes
24+
print-type-size variant `Some`: 4 bytes
25+
print-type-size field `.0`: 4 bytes
26+
print-type-size variant `None`: 0 bytes
27+
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
28+
print-type-size discriminant: 4 bytes
29+
print-type-size variant `Some`: 4 bytes
30+
print-type-size field `.0`: 4 bytes
31+
print-type-size variant `None`: 0 bytes
1732
print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
1833
print-type-size field `.val`: 4 bytes
1934
print-type-size field `.post`: 2 bytes
@@ -36,6 +51,17 @@ print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 by
3651
print-type-size variant `Some`: 4 bytes
3752
print-type-size field `.0`: 4 bytes
3853
print-type-size variant `None`: 0 bytes
54+
print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
55+
print-type-size variant `Union1`: 4 bytes
56+
print-type-size field `.a`: 4 bytes
57+
print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
58+
print-type-size variant `Union2`: 4 bytes
59+
print-type-size field `.a`: 4 bytes
60+
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
61+
print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
62+
print-type-size variant `Union2`: 4 bytes
63+
print-type-size field `.a`: 4 bytes
64+
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
3965
print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
4066
print-type-size field `.0`: 4 bytes
4167
print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes

0 commit comments

Comments
 (0)