Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

const_assert is not compatible with const generics #40

Open
c6c7 opened this issue Mar 25, 2021 · 7 comments
Open

const_assert is not compatible with const generics #40

c6c7 opened this issue Mar 25, 2021 · 7 comments

Comments

@c6c7
Copy link

c6c7 commented Mar 25, 2021

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
@korken89
Copy link

korken89 commented Apr 4, 2021

Hi, has any one found a way around this issue?

@0e4ef622
Copy link

0e4ef622 commented May 21, 2021

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.

@korken89
Copy link

Nice!

@nathan-at-least
Copy link

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?

@JanBeh
Copy link

JanBeh commented Feb 20, 2023

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);
-    };
+    }};

(Playground)

@RyanDamerell
Copy link

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.

@RyanDamerell
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants