The standard library reserves the right to change this definition in the future. As a historical note, the definition (or one of a few equivalent definitions) has been in place since commit 0d48f762243, which was included in Rust 1.0.0-alpha. So this program actually prints 16 on my machine when compiled on Rust 0.12.0:
use std::mem;
use std::rc::Weak;
fn main() {
println!("{}", mem::size_of::<Option<Weak<u8>>>());
// prints 8 on Rust 1.0.0-alpha and newer
// prints 16 on Rust 0.12.0 and older
}
That is correct; it requires 16 bytes to store the address (8 bytes) and the length (8 bytes) of the slice. Without the Option niche optimization, an Option<Weak<[u8]>> would require 24 bytes.
Also, if you want to guarantee that an Option<Weak<T>> only takes 8 bytes, you can use Weak::into_raw() + Weak::from_raw() to store it as a raw pointer.
Without #[repr(transparent)], there's no guarantee the Option<_> size optimization goes through
Even if #[repr(transparent)] was added, the lib team doesn't necessarily consider that a guarantee they'll keep it that way either (as it's just sometimes necessary or desired, and there's no private way to add that attribution to a public type)
So in short the lib team is reserving the right to break this optimization