{"article":{"slug":"generic-const-args-and-you","title":"Generic Const Args and You","subtitle":null,"summary":"Back in June of 2024 at RustFest Zürich, the Const Generics project group first discussed a new design for supporting more complex uses of generic parameters in Const Generics. Since then, we've continued to refine the initial design and have implemented the new design as a family of features dubbed \"Generic Const Arguments\" (GCA for short).","content_type":"tutorial","language":"en","canonical_url":"https://blog.rust-lang.org/inside-rust/2026/10/02/generic-const-args-and-you/","author":{"name":"Inside Rust Blog","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Rust Blog","url":"https://blog.rust-lang.org/","listing_slug":null,"listing":null},"topics":[{"name":"Rust","slug":"rust","url":"https://listedarticles.com/topics/rust"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Systems Programming","slug":"systems-programming","url":"https://listedarticles.com/topics/systems-programming"},{"name":"Tutorials","slug":"tutorials","url":"https://listedarticles.com/topics/tutorials"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":2501,"reading_minutes":11,"published_at":"2026-10-02T00:00:00.000Z","added_at":"2026-10-02T15:16:45.049Z","updated_at":"2026-10-02T15:16:45.049Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/generic-const-args-and-you","markdown_url":"https://listedarticles.com/articles/generic-const-args-and-you.md","example":false,"citation":"Inside Rust Blog, Rust Blog. \"Generic Const Args and You.\" 2 Oct 2026. https://blog.rust-lang.org/inside-rust/2026/10/02/generic-const-args-and-you/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://blog.rust-lang.org/inside-rust/2026/10/02/generic-const-args-and-you/"},"body_markdown":"Back in June of 2024 at RustFest Zürich, the Const Generics project group first discussed a new design for supporting more complex uses of generic parameters in Const Generics. Since then, we've continued to refine the initial design and have implemented the new design as a family of features dubbed \"Generic Const Arguments\" (GCA for short).\n\nThese features are intended to replace the existing `generic_const_exprs` feature which has existed in some form or another since `min_const_generics` was stabilized back in 2021. Even though GCA obviates `generic_const_exprs` it was still incredibly valuable to have invested the time into it that we did as the design and implementation of GCA was informed quite significantly by `generic_const_exprs`.\n\nEach feature in the GCA family introduces support for a specific set of expressions to be used in Const Generics with generic parameters. This post will go over all of the features part of the GCA family and explain their design and how to use them.\n\nA huge thanks to [@camelid](https://www.github.com/camelid) for doing almost all of the initial implementation work for the GCA prototype. Without him GCA would have stayed just a vague concept rather than anything tangible.\n\nAdditionally, a huge thanks to [@khyperia](https://github.com/khyperia) who has done a significant amount of the implementation and design work required to go from the original GCA prototype to the fully featured family that it is now.\n\nFinally there have been a tonne of other people who have made contributions to getting GCA to where it is today. For a full list of everyone and all of their contributions, see the [Full Const Generics](https://github.com/rust-lang/goals/issues/100) project goal.\n\n## \n\nOn stable, only generic parameters by themselves (e.g. `{ N }`) or fully concrete constants (e.g. `{ 1 + 1 }`) are supported by Const Generics. It's not possible to have arrays like `[u8; T::NUM_BYTES]` or `[u8; N + 1]`. This limitation prevents a lot of useful abstractions and pushes users to rely on the typenum crate instead.\n\nGeneric Const Arguments is a family of features introducing support for more kinds of expressions involving generic parameters to Const Generics. For example, the `gca_adts` feature adds support for Struct Expressions involving generic parameters to Const Generics:\n\n```\n#![feature(adt_const_params, gca_adts)]\nuse core::gca;\n/* some details omitted */\nstruct Bar<const N: Foo>;\ntype BarWrapper<const N: usize> = Bar<gca!(Foo { field: N })>;\n```\nIn this example the `gca!(Foo { field: N })` is the new functionality introduced by `gca_adts`. The `adt_const_params` feature is separate and instead allows defining the `const N: Foo` generic parameter.\n\nAll GCA features require any newly supported expressions to be written inside of a `gca!` macro call. We are aware that this requirement poses significant ergonomic problems and are currently looking into ways to avoid this, though have not arrived at a good solution yet (more on this later).\n\n`gca!` Const Arguments have slightly different semantics than other const arguments.\n\nFirst, `gca!(..)` Const Arguments allow for uses of generic parameters within them, Const Arguments are otherwise usually not allowed to do so. In the above example the usage of the Const Parameter `N` in `gca!(Foo { field: N })` is legal as it is within a `gca!(..)` expression, if we had written `Bar<{ Foo { field: N } }>` then the compiler would error.\n\nSecondly, `gca!(..)` Const Arguments support much fewer kinds of expressions inside them than normal Const Arguments do. For example at the time of writing `gca!` arguments do not support arithmetic or function calls. Writing `gca!(1 + 1)` or `gca!(foo())` would result in an error, but just writing `{ 1 + 1 }` or `{ foo() }` would not.\n\nUsing such unsupported expressions while also using generic parameters can be accomplished via the `gca_const_items` feature which we will talk more about later.\n\n### \n\nSupport for constructing arrays, tuples, and ADTs are all lumped into the `gca_adts` feature. We might split this into multiple features at some point but for now it's just the one.\n\nConstructing enums and structs is supported regardless of the syntax they're defined with (i.e. unit, tuple or struct syntax):\n\n```\n#![feature(gca_adts, adt_const_params)]\nuse core::gca;\n#[derive(ConstParamTy, Eq, PartialEq)]\nstruct TupleStruct(usize);\nfn accepts<const N: TupleStruct>() {}\nfn example<const N: usize>() {\n    accepts::<gca!(TupleStruct(N))>();\n}\n```\n```\n#![feature(gca_adts, adt_const_params)]\nuse core::gca;\n#[derive(ConstParamTy, Eq, PartialEq)]\nenum MyEnum {\n    Record { x: usize },\n}\nfn accepts<const E: MyEnum>() {}\nfn example<const N: usize>() {\n    accepts::<gca!(MyEnum::Record { x: N })>();\n}\n```\nAnd lastly support for constructing arrays and tuples:\n\n```\n#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_arrays<const N: [usize; 2]>() {}\nfn example<const N1: usize>() {\n    accepts_arrays::<gca!([N1, 12])>();\n}\n```\n```\n#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_tuple<const N: (usize, usize)>() {}\nfn example<const N1: usize>() {\n    accepts_tuple::<gca!((N1, 12))>();\n}\n```\nWe currently do not support array repeat expressions but do intend to support this at some point:\n\n```\n#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_arrays<const N: [usize; 2]>() {}\nfn example<const N1: usize>() {\n    // currently disallowed :(\n    accepts_arrays::<gca!([N1; 2])>();\n}\n```\n### \n\nSupport for using const items in the type system is part of the `gca_const_items` feature. This feature also requires the `-Znext-solver` unstable flag to be enabled.\n\nBy allowing arbitrary const items to be used in the type system, we are allowing arbitrary expressions to *indirectly* be used in the type system. For example `gca!(N + 1)` cannot be used in the type system, but a const item defined as `const FOO: usize = N + 1;` can be.\n\nUsing an associated constant as a const argument looks like the following:\n\n```\n#![feature(gca_const_items)]\nuse core::gca;\ntrait Trait {\n    const ASSOC: usize\n}\nfn example<T: Trait>() -> [u8; gca!(T::ASSOC)] {\n    [0x1; _]\n}\n```\nUsing a free or inherent associated const item looks similarly:\n\n```\n#![feature(gca_const_items, generic_const_items, inherent_associated_types)]\nuse core::gca;\nconst FREE<T>: usize = size_of::<T>();\nfn example_free<T>() -> [u8; gca!(FREE::<T>)] {\n    [0x6; _]\n}\nstruct Foo<T>(T);\nimpl<T> Foo<T> {\n    const INHERENT: usize = size_of::<T>();\n}\nfn example_inherent<T>(foo: Foo<T>) -> [u8; gca!(Foo<T>::INHERENT)] {\n    [0x7; _]\n}\n```\nNote that the `inherent_associated_types` feature gate has also been enabled in the example. Using inherent associated constants in the `gca!(..)` macro requires an additional feature gate as there are equivalent challenges for supporting this as there are to supporting inherent associated types.\n\nWhen defining a const item, the right hand side can be a `gca!(..)` expression, indicating that the type system can reason about the exact form of the expression. Without this the constant is treated \"opaquely\" and the type system has limited ability to reason about generic uses of it:\n\n```\n#![feature(gca_const_items, generic_const_items)]\nuse core::gca;\nconst FREE_OPAQUE<const N: usize>: usize = N;\nfn make_array1<const N: usize>() -> [u8; FREE_OPAQUE::<N>] {\n    // ERROR: `FREE_OPAQUE::<N>` and `N` are not equal\n    [0; N]\n}\nconst FREE_GCA<const N: usize>: usize = gca!(N);\nfn make_array2<const N: usize>() -> [u8; FREE_GCA::<N>] {\n    // OK :3\n    [0; N]\n}\n```\nIn the above example, the `FREE_GCA` constant is defined as having a `gca!(..)` right hand side, allowing the type system to reason about the const item transparently. This lets the compiler determine that `FREE_GCA::<N>` is equivalent to `N` and therefore that the types `[u8; N]` and `[u8; FREE_GCA::<N>]` are equal.\n\nOn the other hand, the `FREE_OPAQUE` constant is not defined as having a `gca!(..)` right hand side, and so the type system treats it \"opaquely\", unable to reason about it being equivalent to `N`. Ultimately, this causes the types `[u8; N]` and `[u8; FREE_OPAQUE::<N>]` to be considered unequal.\n\nWith support for const items in the type system present, `gca_const_items` also supports associated const bindings and traits with associated constants being dyn compatible:\n\n```\n#![feature(gca_const_items)]\ntrait Trait {\n    const ASSOC: usize;\n}\nfn make_dyn<const N: usize, T: Trait<ASSOC = { N }>>(\n    val: T,\n) -> Box<dyn Trait<ASSOC = { N }> {\n    Box::new(val)\n}\n```\nOn stable, the above example would fail to compile for two reasons. Firstly, unlike associated types we don't support bounding associated constants (e.g. `T: Trait<ASSOC = { N }>`). Secondly, unlike associated types, we don't allow creating `dyn` types for traits which have associated consts. With `gca_const_items` enabled both of these are supported.\n\n### \n\nWe also have a minimal version of the `gca_const_items` feature, `gca_min_const_items`. It supports much the same as the full feature, except that instead of supporting *all* const items, only ones defined as `gca!(..)` expressions are supported. The unstable `-Znext-solver` flag is *not* required to use this feature.\n\n```\n#![feature(gca_min_const_items, generic_const_args)]\nconst BAD<const N: usize>: usize = N;\nconst GOOD<const N: usize>: usize = gca!(N);\nfn foo<const N: usize>() {\n    // not OK! `BAD` isn't equal to a `gca!(..)` expression\n    let _: [u8; BAD::<N>];\n    \n    // OK :3\n    let _: [u8; GOOD::<N>];\n}\n```\nUnlike with the full `gca_const_items` feature which would accept the above example, this is rejected under `gca_min_const_items` as `BAD` does not use a `gca!(..)` right hand side.\n\nTo support trait associated constants a `rustc_always_gca`<sup>[1](#fn-1)</sup> attribute exists which enforces that an associated constant is always implemented as a `gca!(..)` expression.\n\n```\n#![feature(gca_min_const_items)]\ntrait Trait<const N: usize> {\n    #[rustc_always_gca]\n    const ASSOC: usize;\n}\nimpl<const N: usize> Trait<N> for () {\n    // Not OK! not a `gca!(..)` expression\n    const ASSOC: usize = N;\n    \n    // OK!\n    const ASSOC: usize = gca!(N);\n}\n```\nRequiring all const items in the type system to be defined as a `gca!(..)` expression allows us to limit the expressiveness of Const Generics in some desirable ways.\n\nFor example, `gca_const_items` introduces the chance of post-mono errors coming from Const Generics, something which is (at the time of writing) not otherwise possible when using Const Generics. With `gca_min_const_items`, at the cost of some expressiveness, we exclude the aspects of `gca_const_items` which can cause these errors.\n\nAs another example, the full `gca_const_items` feature can have quite confusing errors where two constants are considered unequal even though we as humans can tell that they're obviously equal. With `gca_min_const_items` there are fairly straight forward rules for determining when two constants are equal without any big surprises.\n\nFinally, it's also significantly easier to implement `gca_min_const_items` than `gca_const_items` which means that it should be possible to get this minimal version up to the quality required for stabilization much sooner than it would be for `gca_const_items`.\n\n## \n\nWhile the GCA family of features currently introduces new explicit `gca!(..)` const arguments, this being *explicit* is undesirable in the long term as it results in significant ergonomic issues in Const Generics heavy code. However, there are a number of design and implementation complexities when it comes to implicitly inserting the `gca!(..)` macro.\n\nFirst, the implementation side, it's hard for the compiler to be able to correctly determine when an argument needs to be a `gca!(..)` Const Argument. Naive syntactic methods of doing this result in false-positives where arguments are incorrectly considered to be `gca!(..)` arguments resulting in knock-on errors.\n\n```\n#![feature(\n    gca_adts,\n    gca_macroless_args\n)]\nstruct Foo(usize);\nfn Bar(_: usize) -> usize { 1 }\nfn accepts_usize<const N: usize>() {}\nfn accepts_foo<const N: Foo>() {}\nfn example<const N: usize>() {\n    const ONE: usize = 1;\n    accepts_usize::<Bar(ONE)>();\n    accepts_foo::<Foo(N)>();\n}\n```\nIn this example both `::<Bar(ONE)>` and `::<Foo(N)>` are wholly syntactically equivalent, and yet `Foo(N)` *must* be a `gca!(..)` Const Argument as it contains a path to a generic parameter (`N`), and `Bar(ONE)` must *not* be a `gca!(..)` Const Argument as it is a function call which is not supported in `gca!(..)` Const Arguments.\n\nSecondly, from a design perspective having `gca!(..)` Const Arguments be implicit muddies the waters about what Const Arguments are accepted. Without `gca!(..)` there is no clear distinction between const arguments which can use generic parameters and those which cannot. It also means that the SemVer commitment of a `gca!(..)` Const Argument in a public API not being changed is made implicit which could cause accidental breaking changes.\n\nTo allow us to handle these complexities independently from the core semantic challenges of GCA, there are separate feature gates for implicitly adding the `gca!(..)` macro, rather than having it part of the main GCA features.\n\nThere are currently two features relating to this, `gca_macroless_args` and `gca_macroless_items`. Each feature implicitly adds the `gca!(..)` macro in different positions where it's currently required to write out explicitly. These features are very experimental and don't work particularly well, and, to be honest, we would probably recommend *not* using them and instead *do* recommend using explicit `gca!(..)` Const Arguments for the time being.\n\nIt's also important to note that despite `gca!(..)` being implicit under these features, the Const Arguments are still subject to the same restrictions as when writing `gca!(..)` by hand. This means, for example, macroless does not introduce support for writing `N + 1` as a Const Argument, as `gca!(N + 1)` is similarly not (yet) supported.\n\n### \n\n`feature(gca_macroless_args)` allows Const Arguments to be written with `gca!(..)` left implicit:\n\n```\n#![feature(\n    gca_macroless_args,\n    gca_const_items,\n)]\n// OK even without an explicit `gca!(..)`\nfn make_array<T: Trait>() -> [u8; T::ASSOC] {\n    // ...\n}\n```\nWithout this feature enabled the compiler would require the return type of `make_array` to be written as `[u8; gca!(T::ASSOC)]`.\n\n### \n\n`feature(gca_macroless_items)` allows const items under `gca_const_items` and `gca_min_const_items` to be written with `gca!(..)` left implicit:\n\n```\n#![feature(\n    gca_macroless_items,\n    gca_min_const_items,\n)]\ntrait Trait {\n    #[rustc_always_gca]\n    const ASSOC: usize;\n}\nimpl<const N: usize> Trait for [u8; N] {\n    // OK even without an explicit `gca!(..)`\n    const ASSOC: usize = N;\n}\n```\nIn this example the implementation of `ASSOC` must be a `gca!(..)` expression due to the `rustc_always_gca` attribute. With the macroless feature this is added implicitly, without it the implementation would have to be written as `const ASSOC: usize = gca!(N);`.\n\n## \n\nWe're not currently ready to stabilize any of the features talked about in this post. It will be a while before any of them have reached a level of polish where we would feel comfortable proposing the design as an RFC.\n\nWe would very much like to hear about any issues you run into with any of the GCA features. Whether that be compiler crashes, design issues making it hard to write code that you want to write, or if you're just struggling to get your code working with these features.\n\nThe best way to reach us would be to either open an issue on the [project-const-generics github repo](https://github.com/rust-lang/project-const-generics/issues/new?template=gca-experience-report.md), or open a thread in the [project-const-generics zulip channel](https://rust-lang.zulipchat.com/#topics/channel/260443-project-const-generics).\n\n1. \nIntroducing new attributes is technically a breaking change unless it has a `rustc_` prefix so we are using the name`rustc_always_gca` until stabilization at which point it would be renamed to`always_gca` .[↩](#fr-1-1)","body_html":"<p>Back in June of 2024 at RustFest Zürich, the Const Generics project group first discussed a new design for supporting more complex uses of generic parameters in Const Generics. Since then, we&#39;ve continued to refine the initial design and have implemented the new design as a family of features dubbed &quot;Generic Const Arguments&quot; (GCA for short).</p>\n<p>These features are intended to replace the existing <code>generic_const_exprs</code> feature which has existed in some form or another since <code>min_const_generics</code> was stabilized back in 2021. Even though GCA obviates <code>generic_const_exprs</code> it was still incredibly valuable to have invested the time into it that we did as the design and implementation of GCA was informed quite significantly by <code>generic_const_exprs</code>.</p>\n<p>Each feature in the GCA family introduces support for a specific set of expressions to be used in Const Generics with generic parameters. This post will go over all of the features part of the GCA family and explain their design and how to use them.</p>\n<p>A huge thanks to <a href=\"https://www.github.com/camelid\" rel=\"nofollow ugc noopener\">@camelid</a> for doing almost all of the initial implementation work for the GCA prototype. Without him GCA would have stayed just a vague concept rather than anything tangible.</p>\n<p>Additionally, a huge thanks to <a href=\"https://github.com/khyperia\" rel=\"nofollow ugc noopener\">@khyperia</a> who has done a significant amount of the implementation and design work required to go from the original GCA prototype to the fully featured family that it is now.</p>\n<p>Finally there have been a tonne of other people who have made contributions to getting GCA to where it is today. For a full list of everyone and all of their contributions, see the <a href=\"https://github.com/rust-lang/goals/issues/100\" rel=\"nofollow ugc noopener\">Full Const Generics</a> project goal.</p>\n<p>## </p>\n<p>On stable, only generic parameters by themselves (e.g. <code>{ N }</code>) or fully concrete constants (e.g. <code>{ 1 + 1 }</code>) are supported by Const Generics. It&#39;s not possible to have arrays like <code>[u8; T::NUM_BYTES]</code> or <code>[u8; N + 1]</code>. This limitation prevents a lot of useful abstractions and pushes users to rely on the typenum crate instead.</p>\n<p>Generic Const Arguments is a family of features introducing support for more kinds of expressions involving generic parameters to Const Generics. For example, the <code>gca_adts</code> feature adds support for Struct Expressions involving generic parameters to Const Generics:</p>\n<pre><code>#![feature(adt_const_params, gca_adts)]\nuse core::gca;\n/* some details omitted */\nstruct Bar&lt;const N: Foo&gt;;\ntype BarWrapper&lt;const N: usize&gt; = Bar&lt;gca!(Foo { field: N })&gt;;</code></pre>\n<p>In this example the <code>gca!(Foo { field: N })</code> is the new functionality introduced by <code>gca_adts</code>. The <code>adt_const_params</code> feature is separate and instead allows defining the <code>const N: Foo</code> generic parameter.</p>\n<p>All GCA features require any newly supported expressions to be written inside of a <code>gca!</code> macro call. We are aware that this requirement poses significant ergonomic problems and are currently looking into ways to avoid this, though have not arrived at a good solution yet (more on this later).</p>\n<p><code>gca!</code> Const Arguments have slightly different semantics than other const arguments.</p>\n<p>First, <code>gca!(..)</code> Const Arguments allow for uses of generic parameters within them, Const Arguments are otherwise usually not allowed to do so. In the above example the usage of the Const Parameter <code>N</code> in <code>gca!(Foo { field: N })</code> is legal as it is within a <code>gca!(..)</code> expression, if we had written <code>Bar&lt;{ Foo { field: N } }&gt;</code> then the compiler would error.</p>\n<p>Secondly, <code>gca!(..)</code> Const Arguments support much fewer kinds of expressions inside them than normal Const Arguments do. For example at the time of writing <code>gca!</code> arguments do not support arithmetic or function calls. Writing <code>gca!(1 + 1)</code> or <code>gca!(foo())</code> would result in an error, but just writing <code>{ 1 + 1 }</code> or <code>{ foo() }</code> would not.</p>\n<p>Using such unsupported expressions while also using generic parameters can be accomplished via the <code>gca_const_items</code> feature which we will talk more about later.</p>\n<p>### </p>\n<p>Support for constructing arrays, tuples, and ADTs are all lumped into the <code>gca_adts</code> feature. We might split this into multiple features at some point but for now it&#39;s just the one.</p>\n<p>Constructing enums and structs is supported regardless of the syntax they&#39;re defined with (i.e. unit, tuple or struct syntax):</p>\n<pre><code>#![feature(gca_adts, adt_const_params)]\nuse core::gca;\n#[derive(ConstParamTy, Eq, PartialEq)]\nstruct TupleStruct(usize);\nfn accepts&lt;const N: TupleStruct&gt;() {}\nfn example&lt;const N: usize&gt;() {\n    accepts::&lt;gca!(TupleStruct(N))&gt;();\n}</code></pre>\n<pre><code>#![feature(gca_adts, adt_const_params)]\nuse core::gca;\n#[derive(ConstParamTy, Eq, PartialEq)]\nenum MyEnum {\n    Record { x: usize },\n}\nfn accepts&lt;const E: MyEnum&gt;() {}\nfn example&lt;const N: usize&gt;() {\n    accepts::&lt;gca!(MyEnum::Record { x: N })&gt;();\n}</code></pre>\n<p>And lastly support for constructing arrays and tuples:</p>\n<pre><code>#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_arrays&lt;const N: [usize; 2]&gt;() {}\nfn example&lt;const N1: usize&gt;() {\n    accepts_arrays::&lt;gca!([N1, 12])&gt;();\n}</code></pre>\n<pre><code>#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_tuple&lt;const N: (usize, usize)&gt;() {}\nfn example&lt;const N1: usize&gt;() {\n    accepts_tuple::&lt;gca!((N1, 12))&gt;();\n}</code></pre>\n<p>We currently do not support array repeat expressions but do intend to support this at some point:</p>\n<pre><code>#![feature(gca_adts, adt_const_params)]\nuse core::gca;\nfn accepts_arrays&lt;const N: [usize; 2]&gt;() {}\nfn example&lt;const N1: usize&gt;() {\n    // currently disallowed :(\n    accepts_arrays::&lt;gca!([N1; 2])&gt;();\n}</code></pre>\n<p>### </p>\n<p>Support for using const items in the type system is part of the <code>gca_const_items</code> feature. This feature also requires the <code>-Znext-solver</code> unstable flag to be enabled.</p>\n<p>By allowing arbitrary const items to be used in the type system, we are allowing arbitrary expressions to <em>indirectly</em> be used in the type system. For example <code>gca!(N + 1)</code> cannot be used in the type system, but a const item defined as <code>const FOO: usize = N + 1;</code> can be.</p>\n<p>Using an associated constant as a const argument looks like the following:</p>\n<pre><code>#![feature(gca_const_items)]\nuse core::gca;\ntrait Trait {\n    const ASSOC: usize\n}\nfn example&lt;T: Trait&gt;() -&gt; [u8; gca!(T::ASSOC)] {\n    [0x1; _]\n}</code></pre>\n<p>Using a free or inherent associated const item looks similarly:</p>\n<pre><code>#![feature(gca_const_items, generic_const_items, inherent_associated_types)]\nuse core::gca;\nconst FREE&lt;T&gt;: usize = size_of::&lt;T&gt;();\nfn example_free&lt;T&gt;() -&gt; [u8; gca!(FREE::&lt;T&gt;)] {\n    [0x6; _]\n}\nstruct Foo&lt;T&gt;(T);\nimpl&lt;T&gt; Foo&lt;T&gt; {\n    const INHERENT: usize = size_of::&lt;T&gt;();\n}\nfn example_inherent&lt;T&gt;(foo: Foo&lt;T&gt;) -&gt; [u8; gca!(Foo&lt;T&gt;::INHERENT)] {\n    [0x7; _]\n}</code></pre>\n<p>Note that the <code>inherent_associated_types</code> feature gate has also been enabled in the example. Using inherent associated constants in the <code>gca!(..)</code> macro requires an additional feature gate as there are equivalent challenges for supporting this as there are to supporting inherent associated types.</p>\n<p>When defining a const item, the right hand side can be a <code>gca!(..)</code> expression, indicating that the type system can reason about the exact form of the expression. Without this the constant is treated &quot;opaquely&quot; and the type system has limited ability to reason about generic uses of it:</p>\n<pre><code>#![feature(gca_const_items, generic_const_items)]\nuse core::gca;\nconst FREE_OPAQUE&lt;const N: usize&gt;: usize = N;\nfn make_array1&lt;const N: usize&gt;() -&gt; [u8; FREE_OPAQUE::&lt;N&gt;] {\n    // ERROR: `FREE_OPAQUE::&lt;N&gt;` and `N` are not equal\n    [0; N]\n}\nconst FREE_GCA&lt;const N: usize&gt;: usize = gca!(N);\nfn make_array2&lt;const N: usize&gt;() -&gt; [u8; FREE_GCA::&lt;N&gt;] {\n    // OK :3\n    [0; N]\n}</code></pre>\n<p>In the above example, the <code>FREE_GCA</code> constant is defined as having a <code>gca!(..)</code> right hand side, allowing the type system to reason about the const item transparently. This lets the compiler determine that <code>FREE_GCA::&lt;N&gt;</code> is equivalent to <code>N</code> and therefore that the types <code>[u8; N]</code> and <code>[u8; FREE_GCA::&lt;N&gt;]</code> are equal.</p>\n<p>On the other hand, the <code>FREE_OPAQUE</code> constant is not defined as having a <code>gca!(..)</code> right hand side, and so the type system treats it &quot;opaquely&quot;, unable to reason about it being equivalent to <code>N</code>. Ultimately, this causes the types <code>[u8; N]</code> and <code>[u8; FREE_OPAQUE::&lt;N&gt;]</code> to be considered unequal.</p>\n<p>With support for const items in the type system present, <code>gca_const_items</code> also supports associated const bindings and traits with associated constants being dyn compatible:</p>\n<pre><code>#![feature(gca_const_items)]\ntrait Trait {\n    const ASSOC: usize;\n}\nfn make_dyn&lt;const N: usize, T: Trait&lt;ASSOC = { N }&gt;&gt;(\n    val: T,\n) -&gt; Box&lt;dyn Trait&lt;ASSOC = { N }&gt; {\n    Box::new(val)\n}</code></pre>\n<p>On stable, the above example would fail to compile for two reasons. Firstly, unlike associated types we don&#39;t support bounding associated constants (e.g. <code>T: Trait&lt;ASSOC = { N }&gt;</code>). Secondly, unlike associated types, we don&#39;t allow creating <code>dyn</code> types for traits which have associated consts. With <code>gca_const_items</code> enabled both of these are supported.</p>\n<p>### </p>\n<p>We also have a minimal version of the <code>gca_const_items</code> feature, <code>gca_min_const_items</code>. It supports much the same as the full feature, except that instead of supporting <em>all</em> const items, only ones defined as <code>gca!(..)</code> expressions are supported. The unstable <code>-Znext-solver</code> flag is <em>not</em> required to use this feature.</p>\n<pre><code>#![feature(gca_min_const_items, generic_const_args)]\nconst BAD&lt;const N: usize&gt;: usize = N;\nconst GOOD&lt;const N: usize&gt;: usize = gca!(N);\nfn foo&lt;const N: usize&gt;() {\n    // not OK! `BAD` isn&#39;t equal to a `gca!(..)` expression\n    let _: [u8; BAD::&lt;N&gt;];\n    \n    // OK :3\n    let _: [u8; GOOD::&lt;N&gt;];\n}</code></pre>\n<p>Unlike with the full <code>gca_const_items</code> feature which would accept the above example, this is rejected under <code>gca_min_const_items</code> as <code>BAD</code> does not use a <code>gca!(..)</code> right hand side.</p>\n<p>To support trait associated constants a <code>rustc_always_gca</code>&lt;sup&gt;<a href=\"#fn-1\">1</a>&lt;/sup&gt; attribute exists which enforces that an associated constant is always implemented as a <code>gca!(..)</code> expression.</p>\n<pre><code>#![feature(gca_min_const_items)]\ntrait Trait&lt;const N: usize&gt; {\n    #[rustc_always_gca]\n    const ASSOC: usize;\n}\nimpl&lt;const N: usize&gt; Trait&lt;N&gt; for () {\n    // Not OK! not a `gca!(..)` expression\n    const ASSOC: usize = N;\n    \n    // OK!\n    const ASSOC: usize = gca!(N);\n}</code></pre>\n<p>Requiring all const items in the type system to be defined as a <code>gca!(..)</code> expression allows us to limit the expressiveness of Const Generics in some desirable ways.</p>\n<p>For example, <code>gca_const_items</code> introduces the chance of post-mono errors coming from Const Generics, something which is (at the time of writing) not otherwise possible when using Const Generics. With <code>gca_min_const_items</code>, at the cost of some expressiveness, we exclude the aspects of <code>gca_const_items</code> which can cause these errors.</p>\n<p>As another example, the full <code>gca_const_items</code> feature can have quite confusing errors where two constants are considered unequal even though we as humans can tell that they&#39;re obviously equal. With <code>gca_min_const_items</code> there are fairly straight forward rules for determining when two constants are equal without any big surprises.</p>\n<p>Finally, it&#39;s also significantly easier to implement <code>gca_min_const_items</code> than <code>gca_const_items</code> which means that it should be possible to get this minimal version up to the quality required for stabilization much sooner than it would be for <code>gca_const_items</code>.</p>\n<p>## </p>\n<p>While the GCA family of features currently introduces new explicit <code>gca!(..)</code> const arguments, this being <em>explicit</em> is undesirable in the long term as it results in significant ergonomic issues in Const Generics heavy code. However, there are a number of design and implementation complexities when it comes to implicitly inserting the <code>gca!(..)</code> macro.</p>\n<p>First, the implementation side, it&#39;s hard for the compiler to be able to correctly determine when an argument needs to be a <code>gca!(..)</code> Const Argument. Naive syntactic methods of doing this result in false-positives where arguments are incorrectly considered to be <code>gca!(..)</code> arguments resulting in knock-on errors.</p>\n<pre><code>#![feature(\n    gca_adts,\n    gca_macroless_args\n)]\nstruct Foo(usize);\nfn Bar(_: usize) -&gt; usize { 1 }\nfn accepts_usize&lt;const N: usize&gt;() {}\nfn accepts_foo&lt;const N: Foo&gt;() {}\nfn example&lt;const N: usize&gt;() {\n    const ONE: usize = 1;\n    accepts_usize::&lt;Bar(ONE)&gt;();\n    accepts_foo::&lt;Foo(N)&gt;();\n}</code></pre>\n<p>In this example both <code>::&lt;Bar(ONE)&gt;</code> and <code>::&lt;Foo(N)&gt;</code> are wholly syntactically equivalent, and yet <code>Foo(N)</code> <em>must</em> be a <code>gca!(..)</code> Const Argument as it contains a path to a generic parameter (<code>N</code>), and <code>Bar(ONE)</code> must <em>not</em> be a <code>gca!(..)</code> Const Argument as it is a function call which is not supported in <code>gca!(..)</code> Const Arguments.</p>\n<p>Secondly, from a design perspective having <code>gca!(..)</code> Const Arguments be implicit muddies the waters about what Const Arguments are accepted. Without <code>gca!(..)</code> there is no clear distinction between const arguments which can use generic parameters and those which cannot. It also means that the SemVer commitment of a <code>gca!(..)</code> Const Argument in a public API not being changed is made implicit which could cause accidental breaking changes.</p>\n<p>To allow us to handle these complexities independently from the core semantic challenges of GCA, there are separate feature gates for implicitly adding the <code>gca!(..)</code> macro, rather than having it part of the main GCA features.</p>\n<p>There are currently two features relating to this, <code>gca_macroless_args</code> and <code>gca_macroless_items</code>. Each feature implicitly adds the <code>gca!(..)</code> macro in different positions where it&#39;s currently required to write out explicitly. These features are very experimental and don&#39;t work particularly well, and, to be honest, we would probably recommend <em>not</em> using them and instead <em>do</em> recommend using explicit <code>gca!(..)</code> Const Arguments for the time being.</p>\n<p>It&#39;s also important to note that despite <code>gca!(..)</code> being implicit under these features, the Const Arguments are still subject to the same restrictions as when writing <code>gca!(..)</code> by hand. This means, for example, macroless does not introduce support for writing <code>N + 1</code> as a Const Argument, as <code>gca!(N + 1)</code> is similarly not (yet) supported.</p>\n<p>### </p>\n<p><code>feature(gca_macroless_args)</code> allows Const Arguments to be written with <code>gca!(..)</code> left implicit:</p>\n<pre><code>#![feature(\n    gca_macroless_args,\n    gca_const_items,\n)]\n// OK even without an explicit `gca!(..)`\nfn make_array&lt;T: Trait&gt;() -&gt; [u8; T::ASSOC] {\n    // ...\n}</code></pre>\n<p>Without this feature enabled the compiler would require the return type of <code>make_array</code> to be written as <code>[u8; gca!(T::ASSOC)]</code>.</p>\n<p>### </p>\n<p><code>feature(gca_macroless_items)</code> allows const items under <code>gca_const_items</code> and <code>gca_min_const_items</code> to be written with <code>gca!(..)</code> left implicit:</p>\n<pre><code>#![feature(\n    gca_macroless_items,\n    gca_min_const_items,\n)]\ntrait Trait {\n    #[rustc_always_gca]\n    const ASSOC: usize;\n}\nimpl&lt;const N: usize&gt; Trait for [u8; N] {\n    // OK even without an explicit `gca!(..)`\n    const ASSOC: usize = N;\n}</code></pre>\n<p>In this example the implementation of <code>ASSOC</code> must be a <code>gca!(..)</code> expression due to the <code>rustc_always_gca</code> attribute. With the macroless feature this is added implicitly, without it the implementation would have to be written as <code>const ASSOC: usize = gca!(N);</code>.</p>\n<p>## </p>\n<p>We&#39;re not currently ready to stabilize any of the features talked about in this post. It will be a while before any of them have reached a level of polish where we would feel comfortable proposing the design as an RFC.</p>\n<p>We would very much like to hear about any issues you run into with any of the GCA features. Whether that be compiler crashes, design issues making it hard to write code that you want to write, or if you&#39;re just struggling to get your code working with these features.</p>\n<p>The best way to reach us would be to either open an issue on the <a href=\"https://github.com/rust-lang/project-const-generics/issues/new?template=gca-experience-report.md\" rel=\"nofollow ugc noopener\">project-const-generics github repo</a>, or open a thread in the <a href=\"https://rust-lang.zulipchat.com/#topics/channel/260443-project-const-generics\" rel=\"nofollow ugc noopener\">project-const-generics zulip channel</a>.</p>\n<ol><li></li></ol>\n<p>Introducing new attributes is technically a breaking change unless it has a <code>rustc_</code> prefix so we are using the name<code>rustc_always_gca</code> until stabilization at which point it would be renamed to<code>always_gca</code> .<a href=\"#fr-1-1\">↩</a></p>","headings":[]}}