Two Kinds of Invariants: Safety and Validity

That is what I am proposing, yes. The terminology of validity vs. safety I think is useful independent of what we decide for references, (a) to be able to even have this discussion and (b) because there will be other differences between validity and safety.

I do not think we want the extent of the unsafe block to have any direct consequences.

However, I think this distinction is useful to define what unsafe code is. It is essentially code that works with unsafe data (data that is valid, but not safe). This goes back to what I wrote two years ago about how far out unsafe "leaks".

All of these discussions, as far as I am concerned, are happening on the MIR -- so autoderef is just a method call like any other.

See what I wrote above about it being hard to define where unsafe code ends. :slight_smile:

Yes! Maybe I should clarify in the post :slight_smile:

I cannot think of any.

I have been sitting on these thoughts for quite a while and wished I had them already spelled out for that discussion -- but then, that discussion certainly helped me to sharpen my thoughts and make them more precise.

Agreed.

Notice, however, that I glossed over one issue in that post: When I said all data must always be valid, I was only referring to data the compiler considers initialized. In

let x : &'static i32;

Certainly x must not be valid.

It is quite a burden. Unsafe code does things like calling size_of_val on uninitialized references -- I found an instance of this in Arc::drop_slow and I am sure I would have found more if I would have went on looking. See the PR implementing MaybeUninit for a whole bunch of examples where passing &mut T pointing to uninitialized data to known safe functions is very useful.

I am a fan of saying that a safe function must only be called with safe data, ever -- but first of all we still cannot make violations of this UB (because safety cannot be checked), and secondly this is surprising to lot of people.

That is totally the case. You can only move a value if the compiler thinks it is initialized, which means at this point is must be valid or else you have UB.

If you want to write a function that receives uninhabited values, stop what you are doing.

If you want to write a function that receives uninitialized values, e.g. to initialize them, use &mut T. This will usually be generic code. (That is assuming we adapt my proposal for validity, so your &mut T must be valid but that does not require you to find a valid T.)