Skip to content

Provide a way for derives to know if they were invoked with #[derive_const] #118304

Open

Description

@jhpratt

As part of #67792, #[derive_const] is the current way to indicate that a derive should be impl const Trait rather than impl Trait. However, this only works for built-in macros. It should be possible for end-user proc macros to know if they were invoked with #[derive_const], permitting the derive to emit the appropriate code.

In my opinion, this could be an opaque type provided as an additional parameter to the derive implementation. That type would have methods to obtain constness and any other future extension (i.e. effects).

cc @fee1-dead per this Zulip comment.

@rustbot label +A-proc-macros +C-enhancement +F-const-trait-impl +T-libs-api

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Nov 26, 2023
  2. added
    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Nov 26, 2023
  3. self-assigned this
    on Dec 3, 2023
  4. added
    T-libs-api[DEPRECATED; DO NOT USE]
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 4, 2023
  5. fmease commented on Jul 1, 2024

    @fmease
    Member

    PR #118580 extends support for #[derive_const] to user-defined derive proc-macros as outlined in the issue description. However, #[derive_const] itself is very ad-hoc and non-extensible as petrochenkov criticizes, justifiably so:

    Both #[derive_const] itself, and this, are maximally ad hoc tools for addressing the issue.

    How macros currently take their input - by a token stream, or two token streams if the macro has two inputs like #[attr(input1)] INPUT2.

    This PR adds a third backdoor input tailored for a very specific use case.
    The #[derive_const] added a whole new macro just to add one configuration bit to already existing #[derive] macro.

    I would suggest keeping the current model and using already existing token-based methods for configuring macro behaviors.

    • Either helper attributes, like many derive macros, including derive_more, already do
    • Or giving derive macros the second input token stream - #[derive(Clone(input1))] INPUT2, that would also improve consistency with attributes.

    Then the macros themselves can process the inputs as they want.
    E.g. built-in macros could conventionally take a const token to produce a const impl - #[derive(Clone(const))] struct S;, others may accept more configuration.

    If #[derive] needs some sugar to pass const to multiple derive macros that it applies at once, then it can grow such sugar itself, instead of delegating to a whole new special-purpose macro.
    E.g. #[derive(const: Clone, PartialEq, PartialOrd)] struct S; or anything else, tokens inside the parentheses are an arbitrary token stream, I remind you, so #[derive] can create its own language for its input, like any other attribute macro.

    Originally posted by @petrochenkov in #118580 (comment)

    On a second thought, there's a third way to pass inputs - the "global data" in struct Rustc.

    Proc macro methods without arguments like Span::call_site() take their return values from that global data. I also planned to add some more data there to be available to proc macros, like the kind of brackets used by the macro.

    If "derive expansion options" are placed into struct Rustc, then there's no need to add a second parameter to #[proc_macro_derive] functions for passing them.

    Originally posted by @petrochenkov in #118580 (comment)

    What other similar configuration values we may need in the future?

    Will we need to pass them to derive macros only, or for attribute possibly for attribute or fn-like macros too? With derive macros we have an intermediate layer, the #[derive] macro which has access to compiler magic to set such configuration values, but for attribute and fn-like macros we do not.

    Originally posted by @petrochenkov in #118580 (comment)

  6. fmease commented on Jul 1, 2024

    @fmease
    Member

    I will therefore close the aforementioned PR and block this issue on further design work to be done by PG-const-traits Project group: Const traits and likely also WG-macros Working group: Macros .

  7. added
    S-blockedStatus: Blocked on something else such as an RFC or other implementation work.
    WG-macrosWorking group: Macros
    on Jul 1, 2024
  8. illicitonion commented on Jul 17, 2025

    @illicitonion
    Contributor

    It feels like there are three intentions that may be expressible:

    1. I want a const impl
    2. I want a non-const impl
    3. I want whatever impl you can give me - if you can const, great, if not, I'll take non-const

    Do we intend to make each of these intentions signal-able? Particularly, will #[derive] imply 2 or 3? And will there be a way to express the other?

  9. oli-obk commented on Jul 17, 2025

    @oli-obk
    Contributor

    I don't think option 3 is doable without resorting to https://crates.io/crates/whichever-compiles (this is a joke, Option 3 is not possible, there is nothing that allows a proc macro to make a decision like that).

    You can manually try a const derive, if that doesn't work either change sth to make it work or switch to a normal non-const derive.

  10. illicitonion commented on Jul 17, 2025

    @illicitonion
    Contributor

    I think it's more a question of transition from const traits not existing to them existing - let's imagine I have a proc macro which derives an trait that it can always derive in a const way.

    Will callers need to explicitly switch from #[derive] to #[const_derive] in order to get the const version? Should it be an error to #[derive] a const Trait? Is it ok for a proc macro to give a const impl when called with #[derive]?

  11. sunipkm commented on May 11, 2026

    @sunipkm
  12. removed their assignment
    on Jun 4, 2026
  13. added
    E-needs-designThis issue needs exploration and design to see how and if we can fix/implement it
    and removed
    S-blockedStatus: Blocked on something else such as an RFC or other implementation work.
    on Jun 4, 2026
  14. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-trait-systemArea: Trait systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.E-needs-designThis issue needs exploration and design to see how and if we can fix/implement itF-const_trait_impl`#![feature(const_trait_impl)]`PG-const-traitsProject group: Const traitsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-libsRelevant to the library team, which will review and decide on the PR/issue.WG-macrosWorking group: Macros

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions