google / zerocopy

https://docs.rs/zerocopy
Apache License 2.0
1.03k stars 77 forks source link

Relax `Immutable` semantics #1155

Open joshlf opened 1 month ago

joshlf commented 1 month ago

Overview

Progress

Details

Intuitive definition of interior mutability + compiler optimizations

TODO:

Interior mutability vs UnsafeCells

TODO: Describe how interior mutability is implemented via UnsafeCells today, and justify our intention to relax Immutable's requirements in the future to only mention interior mutability, not UnsafeCells in particular.

Stacked Borrows, UnsafeCell overlap, and Ralf's future plans

TODO:

Immutable vs Freeze

EDIT: Maybe not? https://github.com/google/zerocopy/issues/1155#issuecomment-2098750570

TODO:

josephlr commented 1 month ago

@joshlf I'm a little confused why we need the different semantics from Freeze. If we have a type like:

struct Foo<'a> {
  a: u32,
  b: &'a UnsafeCell<u64>,
}

It will be Immutable, but not FromBytes or IntoBytes, so it doesn't seem like we would run into problems with the various transmute methods? Or am I missing something?

Second unrelated question: do we need a Self: Immutable bound for something like IntoBytes::as_mut_bytes()? It seems like IntoBytes and FromBytes would be enough. Obviously, Immutable is needed for something like IntoBytes::as_bytes().

EDIT: Are the current bounds related to https://github.com/rust-lang/unsafe-code-guidelines/issues/495 ?

joshlf commented 1 month ago

@joshlf I'm a little confused why we need the different semantics from Freeze. If we have a type like:

struct Foo<'a> {
  a: u32,
  b: &'a UnsafeCell<u64>,
}

It will be Immutable, but not FromBytes or IntoBytes, so it doesn't seem like we would run into problems with the various transmute methods? Or am I missing something?

TLDR: You've prompted @jswrenn and me to reconsider, and we might actually go back to considering Immutable to be shallow, and thus equivalent to Freeze.

The reason has to do with future compatibility with safe transmute, which will permit T -> U transmutation on types which are not IntoBytes or FromBytes on their own. E.g. while your Foo is not FromBytes, safe transmute would permit transmuting some types into Foo, and so we'd need a way of banning certain transmutations which are valid except for interior mutability.

The reason we've considered walking this back is that safe transmute will have its own trait (such as this one) which is completely separate from FromBytes/IntoBytes/etc, and the interior mutability analysis will be built-in to the compiler support for that trait. For that reason, Immutable/Freeze will be entirely redundant in the context of full safe transmute, and so we only need to consider Immutable in relation to the traits we have today. In today's world, your argument holds, so we're considering reverting to shallow rather than recursive analysis.

Second unrelated question: do we need a Self: Immutable bound for something like IntoBytes::as_mut_bytes()? It seems like IntoBytes and FromBytes would be enough. Obviously, Immutable is needed for something like IntoBytes::as_bytes().

EDIT: Are the current bounds related to rust-lang/unsafe-code-guidelines#495 ?

Exactly. In particular: