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

bolts: Simplify definition of nonzero! macro #2624

Merged
merged 3 commits into from
Oct 23, 2024

Conversation

langston-barrett
Copy link
Contributor

No description provided.

@domenukk
Copy link
Member

Looks like this doesn't work in my tests.
We could use static_assertions for this however, a crate we're already including

@langston-barrett
Copy link
Contributor Author

Looks like this doesn't work in my tests.

Can you say more about what not working means, and what kinds of tests you were looking at? It appears to be working ok in CI.

@domenukk
Copy link
Member

It compiles in a panic that triggers at runtime instead of actually aborting compilation

@langston-barrett
Copy link
Contributor Author

Can you share an example with that behavior? The following example fails at compile-time (playground):

use core::num::NonZeroUsize;

#[macro_export]
macro_rules! nonzero {
    ($val:expr) => {
        const {
            match NonZeroUsize::new($val) {
                Some(x) => x,
                None => panic!("Value was zero"),
            }
        }
    };
}

fn main() {
    println!("{}", nonzero!(0));
}
error[E0080]: evaluation of `main::{constant#0}` failed
  --> src/lib.rs:16:20
   |
16 |     println!("{}", nonzero!(0));
   |                    ^^^^^^^^^^^ the evaluated program panicked at 'Value was zero', src/lib.rs:16:20
   |

@domenukk
Copy link
Member

That's what I tried. How is my code different? :D
https://rust.godbolt.org/z/jG65badMn

@domenukk
Copy link
Member

Your example works. I'm a bit confused but oh well..
That way we can even just use NonZero and support all numerical types, want to change it?

@langston-barrett
Copy link
Contributor Author

The example you posted seems quite different from the solution proposed here. Namely, you use a const fn, whereas this PR uses a macro. As noted in my comment above, const fns are only guaranteed to evaluate at compile-time when placed in a const context, e.g., a const block. Here's a simpler test-case that exhibits the difference (try commenting out the first call to nonzero to see it panic at runtime):

use core::num::NonZero;

pub fn main() {
    const { nonzero::<0>() }; // panics at compile-time
    nonzero::<0>(); // panics at runtime
}

const fn nonzero<const N: usize>() -> NonZero<usize> {
    match NonZero::new(N) {
        Some(val) => val,
        None => panic!("Zero passed to `nonzero`"),
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=61a3494a15fc9ca7d635d09cffdf1554

@domenukk
Copy link
Member

domenukk commented Oct 22, 2024

I also can't fix it by adding a const { } block inside that function though, so I'm still confused

@langston-barrett
Copy link
Contributor Author

langston-barrett commented Oct 22, 2024

Right. You can think of const fn as saying "this function can be evaluated in a const context". It doesn't mean "this function will always be evaluated to a constant". They can be called from non-const contexts as well, so in a way,const fns are const-ness polymorphic. However, when they are evaluated in a const context (i.e., inside of a const block), then they are guaranteed to evaluate to a constant (i.e., at compile-time).

The nice part about this is that you don't have to make const and non-const copies of the same function if you want to use a const fn in a non-const context.

@domenukk
Copy link
Member

domenukk commented Oct 22, 2024

Ok neat, so this actually works:

pub const fn nonzero<const N: usize>() -> NonZeroUsize {
    const {
        match NonZero::new(N) {
            Some(val) => val,
            None => panic!("expected non-zero value"),
        }
    }
}

Anyway I guess the macro is fine as well / looks a bit nicer / the errors may trigger at the right place
But we should just do NonZero::new instead of NonZeroUsize in the macro, IMHO.

@domenukk domenukk merged commit dfd5609 into AFLplusplus:main Oct 23, 2024
98 checks passed
riesentoaster pushed a commit to riesentoaster/LibAFL that referenced this pull request Dec 11, 2024
* bolts: Simplify definition of `nonzero!` macro

* Non-Usize NonZero

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
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

Successfully merging this pull request may close these issues.

2 participants