// For rust-lang/rust#68303: the contents of `UnsafeCell` cannot // participate in the niche-optimization for enum discriminants. This // test checks that an `Option>>` has the same // size in memory as an `Option>` (namely, 8 bytes). // //@ check-pass //@ compile-flags: --crate-type=lib //@ only-x86 #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZero; use std::sync::{Mutex, RwLock}; struct Wrapper(#[allow(dead_code)] T); #[repr(transparent)] struct Transparent(T); struct NoNiche(UnsafeCell); struct Size; macro_rules! check_sizes { (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; // Any tests run on `UnsafeCell` must be the same for `Cell` (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => { check_sizes!(Cell<$ty>: $size => $optioned_size); check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size); }; ($ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(@actual_check: $ty: $size => $optioned_size); }; // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish // it from other branches and not accidentally match any. (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(check_one_specific_size: $ty, $size); check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); }; // only check that there is no niche (size goes up when wrapped in an option), // don't check actual sizes ($ty:ty) => { check_sizes!(check_no_niche_opt: true, $ty); }; (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => { const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::>()); }; }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); check_sizes!(Wrapper: 4 => 8); check_sizes!(Wrapper>: 4 => 4); // (✓ niche opt) check_sizes!(Transparent: 4 => 8); check_sizes!(Transparent>: 4 => 4); // (✓ niche opt) check_sizes!(NoNiche: 4 => 8); check_sizes!(NoNiche>: 4 => 8); check_sizes!(UnsafeCell: 4 => 8); check_sizes!(UnsafeCell>: 4 => 8); check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(RwLock<&()>); check_sizes!(Mutex<&()>); check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3); trait Trait {} check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); check_sizes!(UnsafeCell>>: 16 => 32);