static-assertions
static-assertions copied to clipboard
const_assert is not compatible with const generics
The following code raises a compiler error. I was expecting const_assert! to statically assert the const generic fits the bound.
Code Snippet
use static_assertions;
const SHA256_DIGEST_LENGTH: usize = 32;
fn truncate_sha256_digest<const L: usize>(
digest: &[u8; SHA256_DIGEST_LENGTH as usize],
) -> [u8; L] {
const_assert!(L <= SHA256_DIGEST_LENGTH);
let mut res = [0u8; L];
res.copy_from_slice(&digest[..L]);
res
}
Error
error[E0401]: can't use generic parameters from outer function
--> ...
|
32 | fn truncate_sha256_digest<const L: usize>(
| - const parameter from outer function
...
35 | const_assert!(L <= SHA256_DIGEST_LENGTH);
| ^ use of generic parameter from outer function
Hi, has any one found a way around this issue?
It seems to be possible in a limited form, using a combination of const generics and associated constants. Playground link.
EDIT: I made a crude macro.
Nice!
Any update on this issue? The primary reason I found and tried static_assertions is precisely to verify relationships between const generic parameters.
The work-around seems like a completely different approach, correct? Is there a crate for the work-around?
EDIT: I made a crude macro.
I think there is a tiny error in it. It should be:
($($list:ident : $ty:ty),* => $expr:expr) => {{
- struct Assert<$(const $list: usize,)*>;
+ struct Assert<$(const $list: $ty,)*>;
impl<$(const $list: $ty,)*> Assert<$($list,)*> {
const OK: u8 = 0 - !($expr) as u8;
}
Assert::<$($list,)*>::OK
}};
Moreover, it's (meanwhile?) possible to use assert! inside the macro:
impl<$(const $list: $ty,)*> Assert<$($list,)*> {
- const OK: u8 = 0 - !($expr) as u8;
+ const OK: () = assert!($expr);
}
Assert::<$($list,)*>::OK
}};
($expr:expr) => {
- const OK: u8 = 0 - !($expr) as u8;
+ const OK: () = assert!($expr);
};
And I think the scope of the second OK constant should be limited:
- ($expr:expr) => {
+ ($expr:expr) => {{
const OK: () = assert!($expr);
- };
+ }};
Moreover, it's (meanwhile?) possible to use
assert!inside the macro:
I don't think so. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bee60f1ca0ac361c93cb5ac937e891c0
Honestly I don't even think this is a static-assertions problem, I believe this is a Rust problem.
Okay, I found a workaround:
The assert thing does work, you just have to reference the const at some point in the control flow of the program.
pub struct Test<const X: usize> {}
impl<const X: usize> Test<X> {
const CHECK: () = assert!(X < 10);
fn new() -> Self {
let _ = Self::CHECK; // this is necessary for CHECK to evaluate at comp time
Self {}
}
}
pub fn main() {
let test = Test::<20>::new();
}
Neither CHECK nor _ change the compiled binary at all, but both must be present to get compile-time checking.