Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

&[!] should have zero size #2754

Closed
ssbr opened this issue Aug 27, 2019 · 6 comments
Closed

&[!] should have zero size #2754

ssbr opened this issue Aug 27, 2019 · 6 comments

Comments

@ssbr
Copy link
Contributor

ssbr commented Aug 27, 2019

I'm not sure how reasonable this is, but since &[!] can only ever be the empty slice, I was hoping it would be represented the same way as &[!; 0] and (), with zero size and knowledge that it must be empty.

e.g. I was hoping this would become a function taking a parameter of zero size and executing xor eax, eax:

pub fn length_never_slice(x: &[!]) -> usize { x.len() }

I have no real use case except showing off cool tricks with !. Maybe this would be useful in generic code, although at least for simple cases where the actual value can get threaded through, it already optimizes fine. (e.g. a call of length_never_slice(&vec![]) will become a hardcoded constant as one expects.)

@ExpHP
Copy link

ExpHP commented Aug 30, 2019

Surely there is unsafe code out there which relies on the fact that &[T] is a fat pointer, regardless of T?

@ssbr
Copy link
Contributor Author

ssbr commented Aug 30, 2019

Is there somewhere I should look to see the guarantees of object layout (before filing bugs like this)?

edit: or is it the case that regardless of written guarantee, as a rule Rust doesn't change object layout in ways like this?

@Ixrec
Copy link
Contributor

Ixrec commented Aug 31, 2019

Unfortunately layout guarantees are still a work in progress. https://doc.rust-lang.org/beta/reference/type-layout.html is the closest thing to an official source, but it's explicitly marked as non-authoritative, and is far from comprehensive. Work to improve this situation is mostly being done at the UCG repo https://github.com/rust-lang/unsafe-code-guidelines. In particular, I believe this specific issue is a partial duplicate of rust-lang/unsafe-code-guidelines#165.

If I'm interpreting arrays-and-slices.md and pointers.md correctly, these draft documents (which are also not authoritative and would need to go through an RFC to become official guarantees of the language, but do represent the "state of the discussion" so far) together imply that &[!] would be guaranteed to be "fat pointer-sized". That seems like the correct policy to me. Since &[T] clearly has to be a fat pointer for any inhabited type, any other decision for &[!] (guaranteeing zero size, not guaranteeing anything) would effectively make all generic unsafe code involving slices UB unless it explicitly checks whether T is uninhabited (and AFAIK there's no way to do such a check today).

@Mark-Simulacrum
Copy link
Member

I personally think this is getting too much into unspecified details so I'm going to move this over to the RFCs repo (and even that, IMO, is a bit questionable).

@Mark-Simulacrum Mark-Simulacrum transferred this issue from rust-lang/rust Aug 31, 2019
@Ixrec
Copy link
Contributor

Ixrec commented Aug 31, 2019

I also just noticed a subtle mistake in the original post, which in this context might be helpful to point out:

I'm not sure how reasonable this is, but since &[!] can only ever be the empty slice, I was hoping it would be represented the same way as &[!; 0] and (), with zero size and knowledge that it must be empty.

You might have gotten [!; 0] and &[!; 0] mixed up. &[!; 0] does not have zero size in Rust today. () and [!; 0] are zero-sized, but &[!; 0] is thin pointer-sized, and &[!] is fat pointer-sized.

@ssbr
Copy link
Contributor Author

ssbr commented Sep 1, 2019

Oops, I meant without the &, yes. :)

arrays-and-slices.md and pointers.md correctl [...] imply that &[!] would be guaranteed to be "fat pointer-sized"

I agree. It outright says "The size of &[T] is two words." which IMO is enough to close this issue. I hope nobody minds if I do that myself.

would effectively make all generic unsafe code involving slices UB unless it explicitly checks whether T is uninhabited (and AFAIK there's no way to do such a check today).

Well, you could check if it has a size of 0.

Almost anything unsafe you do with a slice of uninhabited (except for just copying / writing / reading in-place with no changes) will be UB already. And exact knowledge of the layout is actually more difficult: transmute instead of from_raw_parts/len/as_ptr, or a hardcoded constant instead of size_of... I would expect generic unsafe code to use the provided APIs rather than transmuting all over the place, because it's easier, clearer, safer, and doesn't rely on un-finalized documentation. Maybe I am being optimistic.

In particular, I believe this specific issue is a partial duplicate of rust-lang/unsafe-code-guidelines#165.

I think so -- the result of this issue would be substantially informed by what the decision is on the layout of (!, i32), which I don't think anyone is looking at changing to be of zero size? Given also that there is already draft documentation contradicting this issue, I'd rather close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants