-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Unsafe derives and attributes #3715
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
base: master
Are you sure you want to change the base?
Conversation
2339301
to
0530e44
Compare
Just my 2¢, but I think that the shorthand for You have to separate out derive traits any time there's some different requirement, e.g. Sure, it's likely it won't make a difference, but I think that only having to check attributes at the top level for unsafe to verify safety is best. |
The greppability is already broken by things like |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
I feel kind of silly for literally alluding to this point in my post and missing it somehow. You're right and I retract my original claim. |
We had a @rust-lang/lang design meeting today on the set of macro RFCs. I've updated the RFC to incorporate the feedback from that design meeting. Per the feedback in that meeting, I'm starting an FCP to start letting people register consensus for this RFC. @rfcbot merge |
Team member @joshtriplett 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. |
@rust-lang/lang I've updated this to match the consensus syntax of |
One thing I thought of was that it might make sense to make a derive maybe-unsafe and branch between whether |
I think that would be a big mistake. The presence or absence of |
In terms of the mental model I find OTOH, the RFC does make some good points in favor of "inner |
Use phrasings that can't be read as implying SAFETY comments are unusual. The previous phrasing could be interpreted as "in the unusual case where you're writing SAFETY comments ...".
I'd go even further: the same attribute could be either safe or |
We could certainly do that, but I think it's reasonable for that to be future work. This proposal introduces always-unsafe derives and always-unsafe attributes. In the future, we could have an RFC for sometimes-unsafe derives and sometimes-unsafe attributes, which would require additional definition and documentation. |
@tmandry facet-rs/facet#80 is a good example of rationale for this. |
@rfcbot reviewed I am happy with the syntax and I think you should write I like the idea of unsafe attributes. I agree that facet-rs/facet#80 would be a nice thing to include in the motivation. |
@rfcbot resolve pick-def-site-name We discussed this in the lang call today and aligned around the def-site syntax that matches the use-site syntax. We also talked about expanding on the motivation section of the document, so as to document more of this for posterity, and @joshtriplett is working on making this update. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
to declare a helper attribute as `unsafe`: | ||
|
||
```rust | ||
#[proc_macro_derive(MyDeriveMacro(, attributes(unsafe(dangerous_helper_attr))] |
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.
#[proc_macro_derive(MyDeriveMacro(, attributes(unsafe(dangerous_helper_attr))] | |
#[proc_macro_derive(MyDeriveMacro, attributes(unsafe(dangerous_helper_attr)))] |
In the meeting today, we also aligned around including |
I still haven't seen a worked example of where and how this will be used. The conclusion of facet-rs/facet#80 was that it was not a good candidate for an unsafe derive.
The problem I see is that the ordinary derive logic doesn't make sense for struct Ref<T>(*const T); Then I most likely want my unsafe impl<T: Sync> Send for Ref<T> {} We don't have a precedent for a built-in derive that works like this. If we go by the way those derives work today, unsafe impl<T: Send> Send for Ref<T> {} which would be subtly wrong (albeit in a conservative direction), and worse, hidden from the user. Overall I'm concerned by combination of the following:
I think many of these challenges can be overcome, but we should have use cases in mind to guide this and related features. That way we will end up shipping a good user experience (at least for those use cases) instead of a feature that's almost-but-not-quite useful. |
@rfcbot concern needs fleshed out use case |
@tmandry A few examples of concrete traits that definitely need unsafe derives (safe derives would not work) and don't have any complexity around bounds:
|
but such a derive would be useful when they're stable, serving the function | ||
of an `unsafe impl`.) | ||
- `pyo3::marker::Ungil` in `pyo3`, in place of the current handling of a | ||
blanket impl for any `Send` type. |
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 these are the only motivation examples, I don't get why these marker traits TrustedLen
, TrustedStep
, DerefPure
, Ungil
require using the #[derive]
mechanism over manual unsafe impl
.
For the first three the advantages are not having to explicitly write the where
bounds, but they have the Iterator
or Deref
supertraits which cannot be derived so you gotta repeat those bounds anyway.
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.
Literally any unsafe trait
that one might wish to derive
is a potential example. These were a few samples. If you have other examples of unsafe trait
that you'd prefer to have cited instead of or in addition to these, I'd be happy to add them.
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.
Literally any
unsafe trait
that one might wish toderive
is a potential example.
Normally if we wish to derive
something it is because we know that it is possible to fill out the impl
programmatically with the type's definition alone, thus saving effort to produce the boilerplate impl.
If all the derive doing is just implementing a marker trait without anything extra there's certainly no point from the supply-side anyone wish to write a proc-macro for it. At least it should be derivable together with its base trait like #[derive(Clone, Copy)]
i.e. #[derive(Iterator, unsafe(TrustedLen))]
, but you can't & can't derive an Iterator.
Another reason we wish to derive
a marker trait is to insert some compile-time checks, such as zerocopy
's macros. But zerocopy
's derive-macro checks at the same proved the conditions required by the unsafe trait
in the first place, making those traits safe to derive even if unsafe to manually implement.
For libstd
the public, documented, non-sealed unsafe traits are:
- Traits with no obvious derivable impl:
- GlobalAlloc
- Allocator
- Searcher
- ReverseSearcher
- Marker traits
- TrustedStep
- TrustedLen
- DerefPure
- PinCoerceUnsized
- TransmuteFrom
- CloneToUninit
Perhaps CloneToUninit
is the one most compatible with #[derive]
:
#[derive(CloneToUninit)]
struct Packet<Tail: ?Sized> {
header: Header,
tail: Tail,
}
but the actual impl can satisfy impl CloneToUninit
's safety condition without user's intervention, meaning #[derive(CloneToUninit)]
itself is actually safe.
unsafe impl<Tail: CloneToUninit + ?Sized> CloneToUninit for Packet<Tail> {
unsafe fn clone_to_uninit(&self, dst: *mut u8) {
self.header.clone_to_uninit(dst.add(offset_of_val!(self, header)));
self.tail.clone_to_uninit(dst.add(offset_of_val!(self, tail)));
}
}
So no I don't have any other examples to support this RFC, i.e. I'm still on the side of the concern "needs fleshed out use case".
Allow declaring proc macro attributes and derive macros as unsafe, and
requiring
unsafe
to invoke them.Rendered