Skip to content
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

Unsafe derives and attributes #3715

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions text/3715-unsafe-derives-and-attrs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
- Feature Name: `unsafe_derives_and_attrs`
- Start Date: 2024-10-22
- RFC PR: [rust-lang/rfcs#3715](https://github.com/rust-lang/rfcs/pull/3715)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary
[summary]: #summary

Allow declaring proc macro attributes and derive macros as unsafe, and
requiring `unsafe` to invoke them.

# Motivation
[motivation]: #motivation

Some traits place requirements on implementations that the Rust compiler cannot
verify. Those traits can mark themselves as unsafe, requiring `unsafe impl`
syntax to implement. However, trait `derive` macros cannot currently require
`unsafe`. This RFC defines a syntax for declaring and using unsafe `derive`
macros.

This RFC also defines a syntax for declaring proc macro attributes as unsafe.

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

## Derives

When declaring a proc macro `derive`, you can add the `unsafe` parameter to the
`proc_macro_derive` attribute to indicate that the derive requires `unsafe`:

```rust
#[proc_macro_derive(DangerousTrait, unsafe)]
pub fn derive_helper_attr(_item: TokenStream) -> TokenStream {
TokenStream::new()
}
```

Invoking this derive requires writing either
`#[unsafe(derive(DangerousTrait))]` or `#[derive(unsafe(DangerousTrait))]`.
joshtriplett marked this conversation as resolved.
Show resolved Hide resolved
(The latter syntax allows isolating the `unsafe` to a single derive within a
list of derives.) Invoking an unsafe derive without the unsafe derive syntax
will produce a compiler error. Using the unsafe derive syntax without an unsafe
derive will trigger an "unused unsafe" lint.

A `proc_macro_derive` attribute can include both `attributes` for helper
attributes and `unsafe` to declare the derive unsafe, in any order.

## Attributes

When declaring a proc macro attribute, you can add the `unsafe` parameter to
joshtriplett marked this conversation as resolved.
Show resolved Hide resolved
the `proc_macro_attribute` attribute to indicate that the attribute requires
`unsafe`:

```rust
#[proc_macro_attribute(unsafe)]
pub fn dangerous(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
```

Invoking an unsafe attribute requires the unsafe attribute syntax:
`#[unsafe(dangerous)]`.

# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

Should we support the `#[unsafe(derive(DangerousTrait))]` syntax, or only
`#[derive(unsafe(DangerousTrait))]`? The former elevates the `unsafe` to be
more visible, and allows deriving several traits using one `unsafe`. The latter
isolates the `unsafe` to a specific trait. This RFC proposes supporting both,
but we could choose to only support the latter instead.

We could use a different syntax for invoking unsafe derives, such as
`derive(unsafe Trait)`. However, that would be inconsistent with unsafe
attributes (which use parentheses), *and* it has the potential to look like a
modifier to `Trait` (e.g. an unsafe version of `Trait`).

# Prior art
[prior-art]: #prior-art

RFC 3325 defined unsafe attributes. This RFC provides a natural extension of
that mechanism to derives.

# Unresolved questions
[unresolved-questions]: #unresolved-questions

This RFC proposes accepting both `#[unsafe(derive(MyTrait))]` and
`#[derive(unsafe(MyTrait))]`, among other reasons to make it easy to write
`#[derive(SafeTrait, unsafe(MyTrait))]`. Should we allow both, or only allow
the former?

# Future possibilities
[future-possibilities]: #future-possibilities

When we add support for `macro_rules!`-based attributes and derives, we should
provide a means for such attributes and derives to declare themselves unsafe as
well.

We could provide a syntax to declare specific helper attributes of a derive as
unsafe, without declaring the entire derive unsafe.