Skip to content

Can an Option<T> with a niche be treated as if it were a T for initialization? #583

Description

@ruriww

See the following example code

let mut x = None::<&str>;

const { assert!(
  size_of::<&str>() == size_of::<Option<&str>>() &&
  align_of::<&str>() == align_of::<Option<&str>>()
) };

unsafe {
  // because Option contains a &str and their sizes are equal, the field offset is zero
  let ptr = &mut x as *mut Option<_> as *mut &str;

  // use ptr::write if T needs drop
  // rationale: &str has a niche at null, and since `&mut Option<T>` can produce `&mut T`
  // the option must contain `T` exactly,  given their sizes are the same there cannot be 
  // hidden padding/discriminant bytes, and the `None` value must use a value invalid for `&str`
  *ptr = "hello world";
}

assert_eq!(x, Some("hello world"));

Currently, I can only imagine the comment above to be a logical proof and not a guarantee.

Activity

  1. RalfJung commented on Sep 20, 2025

    @RalfJung
    Member

    Note that we do in fact guarantee that Option<&str> and &str have the same size, alignment, and ABI.

    What you are now asking is whether one can take an &str and transmute it to Option<&str> and get the right behavior. (You're not calling mem::transmute but doing the equivalent via raw pointer casts, so we still call this a transmute.) I would argue this is an intended consequence of what we already guarantee, and in rust-lang/rust#146509 work is on the way to make this explicit in the docs.

    Note however that this only applies to the types listed in the Option docs, not to any other type that may happen to get a niche today. For any other type, where you just observe the sizes to be equal, you have to still rely on arguments like the ones you are making in your comment... and there's not really a way to make those arguments fully watertight I think, since we haven't specified yet what the space of layouts of an enum is.

  2. ruriww commented on Sep 20, 2025

    @ruriww
    Author

    Thanks for the quick response and extra resources! However, I did not see &str being documented in the table (nor in str). It is nice to see some extra guarantees for Result as well :). What I'm getting is that there are no gaping holes in my argument (which is great because I haven't studied proofs much) and for some types with niches, it's possible to make these sound.

  3. RalfJung commented on Sep 20, 2025

    @RalfJung
    Member
  4. ruriww commented on Sep 20, 2025

    @ruriww
    Author

    Ah, my bad I was confusing myself with the right hand side.

  5. RalfJung commented on Oct 18, 2025

    @RalfJung
    Member

    Closing as fixed by rust-lang/rust#146509.

    I would change the comment to something along the lines of:

    unsafe {
      // This is storing an `&str` into a place of type `Option<&str>`, effectively transmuting
      // the former into the latter. Since `&str` is eligible for the `Option` layout guarantee,
      // this transmute is guaranteed to be sound.
      let ptr = &mut x as *mut Option<_> as *mut &str;
      *ptr = "hello world";
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions