| 
 | 1 | +- Feature Name: `declarative_derive_macros`  | 
 | 2 | +- Start Date: 2024-09-20  | 
 | 3 | +- RFC PR: [rust-lang/rfcs#3698](https://github.com/rust-lang/rfcs/pull/3698)  | 
 | 4 | +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)  | 
 | 5 | + | 
 | 6 | +# Summary  | 
 | 7 | +[summary]: #summary  | 
 | 8 | + | 
 | 9 | +Support implementing `derive(Trait)` via a `macro_rules!` macro.  | 
 | 10 | + | 
 | 11 | +# Motivation  | 
 | 12 | +[motivation]: #motivation  | 
 | 13 | + | 
 | 14 | +Many crates support deriving their traits with `derive(Trait)`. Today, this  | 
 | 15 | +requires defining proc macros, in a separate crate, typically with several  | 
 | 16 | +additional dependencies adding substantial compilation time, and typically  | 
 | 17 | +guarded by a feature that users need to remember to enable.  | 
 | 18 | + | 
 | 19 | +However, many common cases of derives don't require any more power than an  | 
 | 20 | +ordinary `macro_rules!` macro. Supporting these common cases would allow many  | 
 | 21 | +crates to avoid defining proc macros, reduce dependencies and compilation time,  | 
 | 22 | +and provide these macros unconditionally without requiring the user to enable a  | 
 | 23 | +feature.  | 
 | 24 | + | 
 | 25 | +# Guide-level explanation  | 
 | 26 | +[guide-level-explanation]: #guide-level-explanation  | 
 | 27 | + | 
 | 28 | +You can define a macro to implement `derive(MyTrait)` by defining a  | 
 | 29 | +`macro_rules!` macro with the `#[macro_derive]` attribute. Such a macro can  | 
 | 30 | +create new items based on a struct, enum, or union. Note that the macro can  | 
 | 31 | +only append new items; it cannot modify the item it was applied to.  | 
 | 32 | + | 
 | 33 | +For instance, the following macro will ignore the item it is attached to, and  | 
 | 34 | +append a function `answer()`:  | 
 | 35 | + | 
 | 36 | +```rust  | 
 | 37 | +#[macro_derive]  | 
 | 38 | +macro_rules! AnswerFn {  | 
 | 39 | +    ($_:tt) => { fn answer() -> u32 { 42 } };  | 
 | 40 | +}  | 
 | 41 | + | 
 | 42 | +#[derive(AnswerFn)]  | 
 | 43 | +struct Struct;  | 
 | 44 | + | 
 | 45 | +fn main() {  | 
 | 46 | +    assert_eq!(42, answer());  | 
 | 47 | +}  | 
 | 48 | +```  | 
 | 49 | + | 
 | 50 | +Derive macros defined using `macro_rules!` follow the same scoping rules as  | 
 | 51 | +any other macro, and may be invoked by any path that resolves to them.  | 
 | 52 | + | 
 | 53 | +A derive macro may share the same path as a trait of the same name. For  | 
 | 54 | +instance, the name `mycrate::MyTrait` can refer to both the `MyTrait` trait and  | 
 | 55 | +the macro for `derive(MyTrait)`. This is consistent with existing derive  | 
 | 56 | +macros.  | 
 | 57 | + | 
 | 58 | +A derive macro may also define *helper attributes*. These attributes are  | 
 | 59 | +[inert](https://doc.rust-lang.org/reference/attributes.html#active-and-inert-attributes),  | 
 | 60 | +and their only purpose is to be fed into the derive macro that defined them.  | 
 | 61 | +That said, they can be seen by all macros.  | 
 | 62 | + | 
 | 63 | +To define helper attributes, put an attributes key in the `macro_derive`  | 
 | 64 | +attribute, with a comma-separated list of identifiers for helper attributes:  | 
 | 65 | +`#[macro_derive(attributes(helper))]`. The derive macro can process the  | 
 | 66 | +`#[helper]` attribute, along with any arguments to it, as part of the item the  | 
 | 67 | +derive macro was applied to.  | 
 | 68 | + | 
 | 69 | +If a derive macro mistakenly emits the token stream it was applied to  | 
 | 70 | +(resulting in a duplicate item definition), the error the compiler emits for  | 
 | 71 | +the duplicate item should hint to the user that the macro was defined  | 
 | 72 | +incorrectly, and remind the user that derive macros only append new items.  | 
 | 73 | + | 
 | 74 | +# Rationale and alternatives  | 
 | 75 | +[rationale-and-alternatives]: #rationale-and-alternatives  | 
 | 76 | + | 
 | 77 | +Adding this feature will allow many crates in the ecosystem to drop their proc  | 
 | 78 | +macro crates and corresponding dependencies, and decrease their build times.  | 
 | 79 | + | 
 | 80 | +Crates could instead define `macro_rules!` macros and encourage users to invoke  | 
 | 81 | +them using existing syntax like `macroname! { ... }`, rather than using  | 
 | 82 | +derives. This would provide the same functionality, but would not support the  | 
 | 83 | +same syntax people are accustomed to, and could not maintain semver  | 
 | 84 | +compatibility with an existing proc-macro-based derive. In addition, this would  | 
 | 85 | +not preserve the property derive macros normally have that they cannot change  | 
 | 86 | +the item they are applied to.  | 
 | 87 | + | 
 | 88 | +A mechanism to define attribute macros would let people write attributes like  | 
 | 89 | +`#[derive_mytrait]`, but that would not provide compatibility with existing  | 
 | 90 | +derive syntax.  | 
 | 91 | + | 
 | 92 | +We could allow `macro_rules!` derive macros to emit a replacement token stream;  | 
 | 93 | +however, that would be inconsistent with the restriction preventing proc macros  | 
 | 94 | +from doing the same.  | 
 | 95 | + | 
 | 96 | +# Prior art  | 
 | 97 | +[prior-art]: #prior-art  | 
 | 98 | + | 
 | 99 | +We have had proc-macro-based derive macros for a long time, and the ecosystem  | 
 | 100 | +makes extensive use of them.  | 
 | 101 | + | 
 | 102 | +The [`macro_rules_attribute`](https://crates.io/crates/macro_rules_attribute)  | 
 | 103 | +crate defines proc macros that allow invoking declarative macros as derives,  | 
 | 104 | +demonstrating a demand for this. This feature would allow defining such derives  | 
 | 105 | +without requiring proc macros at all, and would support the same invocation  | 
 | 106 | +syntax as a proc macro.  | 
 | 107 | + | 
 | 108 | +The `macro_derive` attribute and its `attributes` syntax are based on the  | 
 | 109 | +[existing `proc_macro_derive` attribute for proc  | 
 | 110 | +macros](https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros).  | 
0 commit comments