-
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -319,20 +319,23 @@ descriptions are equivalent. | |
Casting is indicated by the `as` keyword. A cast `e as U` is valid if one of the | ||
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` and `U` is `uint` , or vice versa; | ||
|
||
* `e` has type `T` and `T` and `U` are any numeric types; | ||
|
||
* `e` is a C-like enum and `U` is any integer type, `bool`; | ||
|
||
* `e` has type `T` and `T == u8` and `U == char`; | ||
|
||
* `e` has type `T` and `T == &[V, ..n]` or `T == &V` and `U == *const V`, and | ||
similarly for the mutable variants to either `*const V` or `*mut V`. | ||
* `e` has type `T` and `T` coerces to `U`; *coercion-cast* | ||
* `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or | ||
unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast* | ||
* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* | ||
* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* | ||
* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* | ||
* `e` is a C-like enum and `U` is an integer type; *enum-cast* | ||
* `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast* | ||
* `e` has type `u8` and `U` is `char`; *u8-char-cast* | ||
* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* | ||
* `e` is a function pointer type and `U` has type `*T`, | ||
while `T: Sized`; *fptr-ptr-cast* | ||
* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* | ||
|
||
where `&.T` and `*T` are references of either mutability, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo: the period in |
||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Oh sorry, here is why you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are potentially two ways to interpret this "definition" for
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 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. |
||
|
||
Casting is not transitive, that is, even if `e as U1 as U2` is a valid | ||
expression, `e as U2` is not necessarily so (in fact it will only be valid if | ||
|
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.
presumably the same holds
&mut [T;n]
and*T
?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 didn't originally.
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.
Is there any reason for the mut version not to be here? Feels to me it ought to be for the sake of completeness, unless there is a good reason not to.
Is it worth specifying what happens if n == 0 for this kind of cast? I assume the cast succeeds, but what is the value of the pointer? (null? undefined? a valid pointer to something?)
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.
@nrc
I can't think of a reason to exclude
mut
here. After all, you can certainly do&mut foo[0] as *T
. Regarding 0, I think the answer is probably "an undefined value" (not UB) for the time being, but in general we actually are more limiting than you might think here. (Specifically, we have be careful because of zero-sized types; we used to usenull
more often, but often now useheap::EMPTY
, because of interactions with the null-pointer-optimizations and so forth. A specific example is escaping me at this moment.)