Skip to content

Commit

Permalink
Test interaction of unions with non-zero/niche-filling optimization
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
petertodd committed May 6, 2019
1 parent c3b8ab5 commit 48d1be4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/test/run-pass/union/union-nonzero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// run-pass
#![allow(dead_code)]

use std::mem::{size_of, transmute};

union U1<A: Copy> {
a: A,
}

union U2<A: Copy, B: Copy> {
a: A,
b: B,
}

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, ()>>());

// ...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!()
}
}
17 changes: 17 additions & 0 deletions src/test/ui/print_type_sizes/niche-filling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ pub enum Enum4<A, B, C, D> {
Four(D)
}

pub union Union1<A: Copy> {
a: A,
}

pub union Union2<A: Copy, B: Copy> {
a: A,
b: B,
}

#[start]
fn start(_: isize, _: *const *const u8) -> isize {
let _x: MyOption<NonZeroU32> = Default::default();
Expand All @@ -69,5 +78,13 @@ fn start(_: isize, _: *const *const u8) -> isize {
let _e: Enum4<(), char, (), ()> = Enum4::One(());
let _f: Enum4<(), (), bool, ()> = Enum4::One(());
let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());

// Unions do not currently participate in niche filling.
let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();

// ...even when theoretically possible.
let _i: MyOption<Union1<NonZeroU32>> = Default::default();
let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();

0
}
26 changes: 26 additions & 0 deletions src/test/ui/print_type_sizes/niche-filling.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ print-type-size field `.post`: 2 bytes
print-type-size field `.pre`: 1 bytes
print-type-size variant `None`: 0 bytes
print-type-size end padding: 1 bytes
print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
Expand All @@ -36,6 +51,17 @@ print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 by
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union1`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union2`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union2`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes
Expand Down

0 comments on commit 48d1be4

Please sign in to comment.