-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
[Experimental] Split out an UnsafeCoerceUnsized
trait from CoerceUnsized
#88239
Conversation
Some changes occured to rustc_codegen_cranelift cc @bjorn3 |
cc @ojeda I believe rust-for-linux implements |
The job Click to see the possible cause of the failure (guessed by this bot)
|
/// See the [DST coercion RFC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce] | ||
/// for more details. | ||
/// | ||
/// When this trait is implemented in addition to [`UnsafeCoerceUnsized`](unsafe-coerce-unsized), |
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.
While I understand the reasoning behind it, I think it's confusing to haveCoerceUnsized
be an unsafe trait, and UnsafeCoerceUnsized
be a safe trait.
We've used 'unchecked' in the names of unsafe functions (e.g. get_unchecked
) - I think it might be clearer to rename UnsafeCoerceUnsized
to UncheckedCoerceUnsized
.
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.
Sounds good, thanks!
It seems to me that
However, I'm not sure that combining these two purposes is a good idea in
Instead, I think it would be better to require an explicit opt-in at the call site when using |
Yeah, we implement it in our refcounted pointer: // This is to allow coercion from `Ref<T>` to `Ref<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Ref<U>> for Ref<T> {} |
☔ The latest upstream changes (presumably #87875) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm sorry I will not be able to review this PR. I am not familiar with most of the code it touches, and I am moving which keeps me rather busy currently. |
Cc @rust-lang/lang for this. I think this might need to go through some t-lang process (MCP or so); this sounds like something where a bit of design work is needed. There's also a broader question here: what do the validity and safety invariants of
If we go with the latter choice, all these casts could actually be safe I think. "Non-null" is currently definitely part of the validity invariant, based on the metadata that rustc generates for LLVM (but do we really want this?). The But my thinking is that we should make a choice here for the validity and safety of raw ptr metadata, and only adjust the unsizing trait family if that is still needed after we made a choice. |
@RalfJung indeed! I discussed this a bit with niko today on Zulip. we decide to create a separate repo for this initiative: https://github.com/nikomatsakis/dyn-upcasting-coercion-initiative to collect the design questions and discussions. There's a dedicated page on this: https://github.com/nikomatsakis/dyn-upcasting-coercion-initiative/blob/master/design-questions/upcast-safety.md and we're trying to collect thoughts here. We also want to write this up into something like a lang-team design meeting proposal after some preparation. |
This experiment has fulfilled its goals, and this is likely not the preferred approach. But the feedbacks are valuable. Closing this PR for now, and will reopen if needed later. |
This is taking a more aggressive but more neutral approach than #88010.
Currently this doesn't fully work, and it's just a prototype meant for discussion.
Motivation
In current rust, this code compiles:
However, there's no guarentee at all that v points to a valid
A
typed value. What's more, when v is a fat pointer, it's pointee metadata might be any scalar value, if the pointer is created with something likestd::ptr::from_raw_parts
.On the other hand, the unsizing coercion itself is based on the proof of
A: Unsize<B>
, basically saying that this is a typeA
that can be “unsized” to a dynamically-sized typeB
. It's reasonable to base this onA
value is valid.In recently implemented trait upcasting coercion feature(see #65991) we especially need this assumption to hold, because during the actual conversioin, we'll read the vtable metadata to retrieve the new metadata after the conversion. This is impossible if the input is not a valid pointer for A type (we need the metadata be valid, including when the pointer itself is a null pointer).
So i'm experimentally make this change, by marking raw pointer unsizing operations unsafe. It's up to the user to guarentee the pointer validity before performing the unsizing conversion. The code fragment above will need an unsafe block to pass compilation.
Changes in this PR
CoerceUnsized
trait intotrait UnsafeCoerceUnsized{}
andunsafe trait CoerceUnsized: UnsafeCoerceUnsized{}
, the former for typechecking and the later for user-facing usages and unsafety checking.UnsafeCoerceUnsized
CoerceUnsized
for raw pointers, leaving onlyUnsafeCoerceUnsized
implementation for them.CoerceUnsized
obligation is fulfilled, if not, raise unsafety violation, so if it's not in an unsafe block environment, it will create a compilation error.Status
Remaining issues if this approach is taken:
UncheckedCoerceUnsized
is suggested in review.the coercion cast of the tail expression should be considered "inside" the unsafe block, but it doesn't, and report an unsafe block needed error. (This is blocking CI).
is currently an unsizing cast at MIR level: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e99e4181ea4edcfbb74e56352b899572
CoerceUnsized
toUnsafeCoerceUnsized
in the ir code that chalk is using.I think this will need a broader discussion first.
r? @RalfJung