Description
Original conversation can be found in this IRLO thread, including a request from @RalfJung to file a bug report.
PR 68491 was accepted to hide niches of types that are in an UnsafeCell
. However, experiments show that niches are still exposed within Cell
, Mutex
, and others.
Consider this code, adapted from a playground by @SkiFire13. It currently runs on the playground without panicking and optimizes down to a ret
in the Godbolt explorer.
assert_eq!( 8, mem::size_of::< UnsafeCell<&()> >()); // 8
assert_eq!(16, mem::size_of::<Option<UnsafeCell<&()>>>()); // 16 (✗ niche opt)
assert_eq!( 8, mem::size_of::< Cell<&()> >()); // 8
assert_eq!( 8, mem::size_of::<Option< Cell<&()>>>()); // 8 (✓ niche opt)
assert_eq!(16, mem::size_of::< RefCell<&()> >()); // 16
assert_eq!(24, mem::size_of::<Option< RefCell<&()>>>()); // 24 (✗ niche opt)
assert_eq!(24, mem::size_of::< RwLock<&()> >()); // 24
assert_eq!(24, mem::size_of::<Option< RwLock<&()>>>()); // 24 (✓ niche opt)
assert_eq!(24, mem::size_of::< Mutex<&()> >()); // 24
assert_eq!(24, mem::size_of::<Option< Mutex<&()>>>()); // 24 (✓ niche opt)
I would have expected Option<Cell<&()>>
to not exhibit the niche-exploiting size optimization. The RwLock
and Mutex
cases may or may not be problematic, depending on their platform-specific implementations. But Cell
in particular is a #[repr(transparent)]
wrapper around UnsafeCell
.
Here is another playground by @SkiFire13 from which they observed:
Even more interesting, looks like the current behaviour of a type that contains an
UnsafeCell
is to allow niche optimizations only if it doesn't contains something else before theUnsafeCell
, and that something is not a ZST.
This indicates that the behavior is not Cell
-specific. And although there has been some discussion about revealing the niches for Cell
in particular, the discussion in the PR and in this hackmd seem to indicate that the niches being exploited is not intentional, even for Cell
. The behavior can be observed back until Rust 1.43 when the PR landed.
Meta
Current playground (all versions) and Godbolt on all versions I tried from 1.43 forward.