How do I static assert a property of a generic u32 parameter?

With nightly you have @vague's answer, which is the proper solution.


On stable, you can use post-monomorphization errors (panic!s when resolving generic constants) to emulate that, but it's really a poorman's substitute, since cargo check won't detect those failures, only the final cargo build can, and it will only do so if such a function is deemed reachable enough for it to make it to codegen (thence triggering a monomorphization of that generic const, and thus, observing the panic). This is what @LegionMammal978's solution is about, but it was missing these obligatory disclaimers about the limitations of post-mono errors

  • In other words: if you're compiling the final binary, an approach based on post-mono checks is fine. But if you're just a library, then you may make mistakes which you'll never detect and only a downstream user will, which will be highly inconvenient for them. So I would advise against post-mono checks for library authors.

On the other hand, @LegionMammal978's approach has the advantage of using a compile-time panic for a way nicer error message. So we can take that idea and apply it to the nightly approach, yielding:

struct AssertDivisibleBy4<const N: u32>;

impl<const N: u32> AssertDivisibleBy4<N> {
    const OK: usize = {
        assert!(N % 4 == 0, "must be divisible by 4");
        0
    };
}

fn test2<const N: u32> ()
where
    [(); AssertDivisibleBy4::<N>::OK]:,
{
    // …
}

so that a test2::<3>, even in unreachable code, yields:

error[E0080]: evaluation of `AssertDivisibleBy4::<3_u32>::OK` failed
 --> src/lib.rs:8:9
  |
8 |         assert!(N % 4 == 0, "must be divisible by 4");
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'must be divisible by 4', src/lib.rs:8:9
  |
2 Likes