Generic Const Arguments (GCA)

Authors

K19G

grok-bot

Updated

October 31, 2026

Generic Const Arguments (GCA)

Thesis

On stable Rust, a const generic parameter may appear in a const argument alone ([u8; N]) or as a fully concrete expression ([u8; 1 + 1]). The moment you write [u8; N + 1] or [u8; T::ASSOC], the compiler stops you. The old escape hatch, #![feature(generic_const_exprs)] (GCE), taught everyone the shape of the problem but never became a stabilization candidate.

Generic Const Arguments (GCA) is the Const Generics project group’s replacement family of nightly features. Expressions that involve generic parameters go through an explicit gca!(…) marker (for now), each capability has its own gate (gca_adts, gca_min_const_items, gca_const_items, …), and definitional equality — not GCE’s evaluation model — decides when two const arguments match. Nothing here is stable. This chapter shows what compiles on today’s nightly, marks every feature gate, and records where the Oct 2026 blog post already drifted from the compiler.

Version note: verified on rustc 1.101.0-nightly (a30aa9064 2026-10-08). The Inside Rust post Generic Const Args and You (2026-10-02) is the design overview; on this nightly the feature formerly named generic_const_args has been renamed to gca_const_items (removed name errors say “removed in 1.100.0”), and the gca! macro lives at std::gca / core::gca. No RFC yet; the project group says polish first.

Stable const generics basics (structs/functions parameterized by const N: usize) live in Generic Functions and Data Structures. This chapter does not re-teach that.

Mental model

Stable today
  const arg ::=  N  |  <fully concrete expr>
                 └── generic param alone

GCE (legacy nightly)     — evaluate complex exprs; hard to stabilize
GCA (current nightly)    — mark exprs with gca!(…); equality by definition
       │
       ├── gca_adts              arrays / tuples / structs / enums in gca!(…)
       ├── gca_min_const_items   const items whose RHS is gca!(…)
       ├── gca_const_items       + opaque const items, assoc bindings, dyn, needs -Znext-solver often
       └── gca_macroless_*       experimental: insert gca!(…) for you (rough)
Fact Consequence
gca!(…) may mention generic parameters Plain { N + 1 } as a const argument still cannot
gca!(…) accepts fewer expression kinds than a normal const block gca!(N + 1) and gca!(foo()) are not automatically legal; prefer const items / ADTs that the gates support
gca_const_items requires gca_min_const_items Enable both; incomplete-feature warnings are expected
Feature generic_const_args is gone on 1.101 nightly Use gca_const_items (compiler points the rename)
Nothing is stabilization-ready APIs that expose gca!(…) in public signatures are a SemVer hazard while the syntax is explicit

Worked examples

All listings were compiled with:

rustup toolchain install nightly --profile minimal   # once
rustc +nightly --version
rustc 1.101.0-nightly (a30aa9064 2026-10-08)

Case 0: stable still rejects N + 1

// stable_fail.rs — what stable const generics refuse
fn make<const N: usize>() -> [u8; N + 1] {
    [0; N + 1]
}

fn main() {
    let _ = make::<3>();
}
rustc --edition 2024 stable_fail.rs
error: generic parameters may not be used in const operations
 --> stable_fail.rs:1:35
  |
1 | fn make<const N: usize>() -> [u8; N + 1] {
  |                                   ^ cannot perform const operation using `N`
  |
  = help: const parameters may only be used as standalone arguments here, i.e. `N`
  = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
  = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item

Note the help text still mentions GCE and GCA — both are nightly escape hatches; new code should reach for GCA, not GCE.

Case 1: ADT const arguments with gca_adts

Build a const-generic parameter whose type is a struct, then construct that struct from another const parameter inside gca!(…):

// gca_adt.rs — struct expressions as const arguments (nightly GCA)
#![feature(gca_adts, adt_const_params, gca_min_const_items)]
#![expect(incomplete_features)]

use std::gca;
use std::marker::ConstParamTy;

#[derive(ConstParamTy, Eq, PartialEq)]
struct TupleStruct(usize);

fn accepts<const N: TupleStruct>() -> usize {
    N.0
}

fn example<const N: usize>() -> usize {
    accepts::<gca!(TupleStruct(N))>()
}

fn main() {
    println!("{}", example::<7>());
}
rustc +nightly --edition 2024 gca_adt.rs -o gca_adt && ./gca_adt
7

The same pattern works for enum variants, arrays (gca!([N1, 12])), and tuples (gca!((N1, 12))) per the project-group post. Array repeat syntax (gca!([N1; 2])) is still explicitly not supported.

Case 2: Associated constants with gca_const_items

// gca_assoc.rs — associated consts in array lengths (nightly GCA)
#![feature(gca_min_const_items, gca_const_items)]
#![expect(incomplete_features)]

use std::gca;

trait Trait {
    const ASSOC: usize;
}

impl Trait for u8 {
    const ASSOC: usize = 3;
}

fn example<T: Trait>() -> [u8; gca!(T::ASSOC)] {
    [0x1; _]
}

fn main() {
    let a = example::<u8>();
    println!("len={}", a.len());
}
rustc +nightly --edition 2024 gca_assoc.rs -Znext-solver -o gca_assoc && ./gca_assoc
len=3

-Znext-solver is required for the full gca_const_items path in current nightlies. Treat that as part of the experiment, not as something to bake into stable CI.

Case 3: Macroless (experimental)

gca_macroless_args asks the compiler to insert gca!(…) for you. It works for some associated-const cases on this nightly, and the project group still recommends writing gca!(…) explicitly:

// gca_macroless.rs — implicit gca!(…) (rough; prefer explicit)
#![feature(gca_min_const_items, gca_const_items, gca_macroless_args)]
#![expect(incomplete_features)]

trait Trait {
    const ASSOC: usize;
}

impl Trait for u8 {
    const ASSOC: usize = 3;
}

fn make_array<T: Trait>() -> [u8; T::ASSOC] {
    [0x1; _]
}

fn main() {
    println!("{}", make_array::<u8>().len());
}
rustc +nightly --edition 2024 gca_macroless.rs -Znext-solver -o gca_macroless && ./gca_macroless
3

Case 4: What still hurts — arithmetic inside gca!

The blog’s long-term story is “put complex ops in const items.” On 1.101 nightly, a direct gca!(N + 1) as a const-item RHS is still rejected:

// gca_arith.rs — not there yet on 2026-10-08 nightly
#![feature(gca_min_const_items, gca_const_items, generic_const_items)]
#![expect(incomplete_features)]
use std::gca;

const INC<const N: usize>: usize = gca!(N + 1);

fn make<const N: usize>() -> [u8; INC::<N>] {
    [0; INC::<N>]
}

fn main() {
    let _ = make::<3>();
}
rustc +nightly --edition 2024 gca_arith.rs
error: complex const arguments must be placed inside of a `const` block
 --> gca_arith.rs:5:41
  |
5 | const INC<const N: usize>: usize = gca!(N + 1);
  |                                         ^^^^^

So: ADTs and associated-const uses are the productive surface today; “any arithmetic via gca!” is not. Re-check nightly before teaching a team pattern around arithmetic helpers.

The trap

  1. Copy-pasting #![feature(generic_const_args)] from older posts. Removed in 1.100; rename to gca_const_items and enable gca_min_const_items with it.
  2. Assuming gca!(…) is a full const evaluator. It is a marker for a restricted expression grammar that may mention generics. Unsupported ops fail loudly.
  3. Stabilizing public APIs on gca!. The macroless work exists precisely because explicit gca! is considered ergonomically temporary — and also SemVer-visible.
  4. Mixing GCE and GCA in one crate “just to make it compile”. Two incomplete models; pick GCA for new experiments.
  5. Forgetting #![expect(incomplete_features)] / #[allow(incomplete_features)]. Without it, every build is a warning storm (or worse, depending on lint config).

The boring rule

Stay on stable const generics (N alone, or concrete exprs) for production. When you truly need generic const computation, use current nightly GCA with explicit gca!(…), gate every file with the specific features you touch, pin the nightly date in the chapter/PR, and re-run the listings after each toolchain bump — the rename from generic_const_args to gca_const_items already proved the surface moves.

Try this

  1. Compile Case 1 and Case 2 on your nightly; paste rustc +nightly --version next to the output.
  2. Attempt one gca!([N; 2]) repeat expression and confirm it still errors; watch the tracking issues for when it lands.
  3. Skim the project-const-generics repo / Zulip before filing duplicates — design feedback is solicited there.

Sources