-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Stabilize derive(CoercePointee)
#133820
base: master
Are you sure you want to change the base?
Stabilize derive(CoercePointee)
#133820
Conversation
8baca16
to
7865ddb
Compare
This comment has been minimized.
This comment has been minimized.
derive(CoercePointee)
7865ddb
to
208e5bb
Compare
@rustbot ready
|
This comment has been minimized.
This comment has been minimized.
208e5bb
to
d9f6c00
Compare
@rustbot label +F-derive_smart_pointer |
#[rustc_builtin_macro(CoercePointee, attributes(pointee))] | ||
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] | ||
#[unstable(feature = "derive_coerce_pointee", issue = "123430")] | ||
#[cfg(not(bootstrap))] |
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.
Question:
Do we need to condition on bootstrap
? No standard library item depends on this macro yet.
The RFC for this feature said that it depends on the arbitrary self types feature, but it is not a full blocker to stabilizing this feature. There are two things that the macro enables: The first thing is coercions from The second thing is making traits such as this one object safe: trait MyTrait {
fn func(self: MySmartPtr<Self>);
} Without arbitrary self types, it's not legal to declare this trait because So if we stabilize the macro now, then we gain the ability to make coercions and call trait methods via deref, but we don't gain the ability to declare traits that take the smart pointer without a deref coercion. We would gain that ability once arbitrary self types are stabilized. |
@rfcbot fcp merge Thanks @dingxiangfei2009. We talked about this in our triage call today. Let's ship it. |
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
Given the discussion here, it seems safe to say that we should re-FCP this with t-types. I'll recheck the boxes of everyone on lang. @rustbot labels -finished-final-comment-period +T-types |
@rfcbot fcp merge |
@rfcbot fcp cancel |
@compiler-errors proposal cancelled. |
@rfcbot fcp merge |
Team member @compiler-errors has proposed to merge this. The next step is review by the rest of the tagged team members:
Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
@rfcbot reviewed |
(Noting here that I started the merge so my box is checked and rfcbot doesn't give a way to uncheck my box afaict, but I'd still like to see the type system and compiler side of this stabilization -- not just the macro itself but the traits that it exposes indirectly -- noted clearly in the stabilization report before this merges. I won't file this as a concern just yet, because I don't want to immediately block this, but if anyone else on T-types feels more strongly they can file a concern before me.) |
I'd expect just manually editing its comment to work 🤔 😁 |
Lookiong at the unstable emitted impls, we've got:
|
pub(crate) fn coerce_unsized_info<'tcx>( |
DispatchFromDyn
Again, the requirements are checked in
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
Now, given that all invariants of the trait are actually checked by the compiler, this derive is sound as long as these two traits are :3
Both traits don't have builtin impls, so there's no worry about incorrect overlap. They simply recursively walk ADTs until they reach a ptr, at which point we rely on Unsize
(at least for CoerceUnsized
) which checks the pointee. The Unsize
check does not depend on CoerceUnsized
.
I assume that an impl which soundly works for Arc
will also soundly work for other user-defined types.
One concern is that we add a requirement T: Unsize<U>
even if the pointer is not necessarily pointing to T
directly, e.g. we leak some of the existing Unsize
impls
#![feature(derive_coerce_pointee)]
use std::marker::PhantomData;
use std::marker::CoercePointee;
#[derive(CoercePointee)] #[repr(transparent)]
struct MyPointer<'a, T, #[pointee] U: ?Sized> {
ptr: &'a (T, U),
}
Leaking currently unstable impls:
rust/compiler/rustc_hir_typeck/src/coercion.rs
Lines 716 to 724 in 66bb586
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() { | |
feature_err( | |
&self.tcx.sess, | |
sym::unsized_tuple_coercion, | |
self.cause.span, | |
"unsized tuple coercion is not stable enough for use and is subject to change", | |
) | |
.emit(); | |
} |
#![feature(derive_coerce_pointee)]
use std::marker::PhantomData;
use std::marker::CoercePointee;
#[derive(CoercePointee)] #[repr(transparent)]
struct MyPointer<'a, T, #[pointee] U: ?Sized> {
ptr: &'a (T, U),
}
fn main() {
let x = MyPointer { ptr: &(1u32, 1u32) };
let _: MyPointer<u32, dyn Send> = x;
} @rfcbot concern leaking unstable |
@compiler-errors my preferred way to manage that is not unchecking my box but filing a concern |
Yeah, at this point @lcnr has already begun to do a good job at characterizing the types-level surface of what is being stabilized here, and funny enough that they found an interesting quirk in the process :D |
In practice I don't think this is exploitable, regardless I don't think we should stabilize the ability for semi-user-written impls or trait bounds to be written involving this trait until the builtin checks are brought in line with edit: thanks to @steffahn for pointing this out @rfcbot concern |
The @rfcbot concern |
I've moved some of the concerns out to separate issues where people can assign themselves and |
☔ The latest upstream changes (presumably #135286) made this pull request unmergeable. Please resolve the merge conflicts. |
What is being proposed for stabilization
This stabilization report concerns the macro specified by RFC3621, now called
CoercePointee
.This macro enables the derivation of trait implementation of
Unsize
,CoerceUnsize
andDispatchFromDyn
traits, both of which are unstable at the moment, under a well-defined and structured schema, so that the users who would like to allow their custom type to admit unsizing coercion and use ofdyn
DST in one of its generic type parameter in a safe way. The greatest use case of this macro is to allow users to equip their types with this behaviour without dependence onalloc
crate, or whenalloc
is not available and a custom implementation of pointer-like data structure in the likes ofRc
andArc
is highly desirable. The most prominent example is thekernel
crate by Rust-for-Linux, which would greatly benefit from this macro due to reduction of boilerplate, and reduce the project's dependence on unstable features behindUnsize
,CoerceUnsize
andDispatchFromDyn
.In a nutshell,
derive(CoercePointee)
derives the implementation ofCoerceUnsize
andDispatchFromDyn
traits on the targetstruct
definition with all the necessary trait bounds. It identifies one generic type variable in the generic list of the targetstruct
, that is either uniquely annotated with the#[pointee]
attribute or is the only type variable among the generics. This identified generic, which is called source type in this document, will be treated as the target of unsizing operation anddyn
trait object dispatch. Correspondingly, the resultant type after the unsizing coercion will be called target type in this document. In case additional trait bounds applies on the source type, the said trait bounds will be migrated to both the source type and the target type in the trait implementation.Out of necessity of unsizing coercion, the macro requires the
struct
to adopt therepr(transparent)
layout. The only data field in thestruct
definition, which is required by this layout, should also implementCoerceUnsize
andDispatchFromDyn
at the moment, or at least conform to requirement of the unsizing coercion and trait object dispatching protocol.As an example, here is how the generated code would look like after expanding the macro. The following is a user source that invokes this macro.
This is the expansion result. The source type
T
after the unsizing coercion is assumed to be__S
and the trait bounds requested by the original definition are migrated for__S
as well throughtout.Future interaction
This stabilization of this macro does not require the stabilization of any of the unstable traits mentioned. This macro aims at stabilising a subset of features thereof, which has widely proliferated in the ecosystem, without blocking further development of DSTs and unsizing coercion. In case of change in the design of these language features, as long as basic provision of the coercion operation remains the same, the macro should be updated to use the new facility inside its implementation when necessary, to preserve only the semantics and capabilities that this macro exposes users to.
Tracking:
derive(CoercePointee)
#123430cc @rust-lang/lang