-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Clarify cast rules, especially regarding fat pointers. #1052
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
Conversation
@@ -321,18 +321,26 @@ following holds: | |||
|
|||
* `e` has type `T` and `T` coerces to `U`; | |||
|
|||
* `e` has type `*T` and `U` is `*U_0` (i.e., between any raw pointers); | |||
* `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or | |||
unsize_kind(`T`) = unsize_kind(`U_0`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I.e. a fat pointer (*const Trait
) can be truncated to thin pointer (*const u8
)? I don't think it should be done with as
. Fat pointers definitely should have some methods for extracting their components without shady transmutes, but as
should convert only between pointers of the same kind IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If U_0: Sized
then the cast is legal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that it's legal, it's written clearly, I don't understand why it should be legal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It throws away the DST info - that's a perfectly good cast (same as u32 -> u8
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that as
is one of the most overloaded entities in the language and now you are throwing even more semantics into it without sufficient reasons. Ideally even u32 -> u8
would be done with a specialized method, like truncate()
and not with omnipotent as
.
LGTM! |
Are bool -> numeric casts ( |
Assume we have an empty slice or an empty array:
They are perfectly safe per se, but what does happen when we cast them to pointers?
As a result |
You can also do |
Yeah, I see, |
Anyway, do we want to allow usize/ptr -> fn casts? They are not currently allowed and not in any rule. |
I guess they are disallowed because |
Questions remaining: |
I think yes, but there are valid reasons for no
no this should at the least be a double cast usize -> ptr -> fn (but see below)
I'm not sure about how/if this should work, ping @nikomatsakis for an opinion
yes, they should be, it's often useful and is C-like |
Also, there is a char -> integer cast, which is also allowed |
Today's rustc allows fn -> usize, fn -> *ptr casts. Also, it allows ptr -> any int casts, which are used rather often. |
I think this should remain illegal, for the reason that @petrochenkov highlighted. That is, casts into safe types like |
but fn -> thin ptr/usize casts should be legal (they are, currently). |
@arielb1 right, that seems ok to me. |
I notice that we actually allow casting of raw pointers to and from any integral type, not just usize. I expect this is not what we intend (and of course its backwards incompatible). Does anyone think we should be allow to do this? |
IMO, the conversions to/from any integral type except for |
liblibc defines |
@arielb1 |
liblibc does this a lot, through. And I think changing |
Another way is to postulate that Update: making |
A mix of the original RFC and facts on the ground.
I now have something that works. |
|
||
where `&.T` and `*T` are references of either mutability, | ||
and where unsize_kind(`T`) is the kind of the unsize info | ||
in `T` - a vtable or a length (or `()` if `T: Sized`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are potentially two ways to interpret this "definition" for unsize_kind
... either:
unsize_kind
says whether the type is a trait, or a slice, or a sized type (i.e. there are only three possible values that it returns), orunsize_kind
says the same thing but also includes which trait (i.e. which vtable) for the first case, and which particular length for the second case (i.e. that its a much larger range of potential values).
I infer that the intention is the latter; i.e. that it is not legal e.g. to cast from one trait-object to another with an unrelated vtable via as
, nor is it legal to cast from one array to another with a different length. But it still would be nice if the text didn't require any thinking on this point.
Anyway, I wouldn't block this change based on this detail; we can always come up with a later PR to try to clarify this later.
I also took the latter interpretation. |
Our interpretation was the former (iirc). If you're casting its up to you to ensure you aren't doing something stupid. |
Hmm. I'm getting a bit worried about this trait casting point. In particular, if we permit |
Hmm, based on the outstanding questions concerning trait object casts and |
We discussed a bit further on IRC, we agreed that while casting pointer to array seems reasonable, we couldn't come up with a good use case for casting trait objects. I propose we disallow casting trait objects entirely. We allow casts from |
I realize now that my note, or at least my inferred interpretation, did not make much sense.
(I suppose we might consider at least lint-warning that
|
@arielb1 As the RFC author, do you have any thoughts on the last minute back-and-forth on the details of trait-objects and It seems like this RFC is likely to be accepted with amendments, but I am not sure whether you would prefer to make such amendments yourself, or if you are okay with the person doing the merge doing such amendments, or if you in fact disagree with the proposed amendments? |
I am not sure casts between arrays of different types should try to compensate for the length difference - the sizes can be non-multiples of each-other, making it unclear which way the rounding should go. I expect raw fat pointer casting to be used in the same way as raw thin pointer casting - i.e., the pointer will either be cast back to the right type before being used, or the cast-type is sufficiently representation-equivalent to the expr-type (e.g. casting I am fine with making the vtable kind include the trait id (i.e. being |
I feel pretty strongly that we should not permit I'm of two minds about the slice casts. It's hard for me to imagine a scenario where it makes sense to do the cast unless the sizes are equal -- this is a bit different from |
An actual case for casting things of different sizes? I don't think there is really any, but we don't know the sizes at typeck time of course. |
@arielb1 for casting |
@arielb1 I can easily imagine converting e.g. to |
to be clear, I don't really have a problem with allowing |
So it seems to be me that everyone is roughly on the same page that:
Is this an accurate summary? If so, @arielb1, would you prefer to edit the text appropriately, or should I do so when merging? cc @rust-lang/lang |
Changed. |
It's official... the language subteam has decided to accept this RFC. |
It seems that there is at least some impl work remaining here, in that the compiler currently accepts a bit too much, at least with regard to object casts (though I see trans errors, which is nice): |
Tracking issue: rust-lang/rust#26391 |
This argument is no longer valid. |
Fixes issue #1046.