Description
Right now we have ad hoc checks for certain known bad scenarios in our const evaluator ... so for example:
#![feature(const_fn)]
fn add1(x: u32) -> u32 {
// For non-const, I can inject input checks
assert!(x < ::std::u32::MAX);
x + 1
}
#[cfg(cannot_build_today)]
const fn const_add1(x: u32) -> u32 {
// but current rules for `const fn`
// disallow this variation
assert!(x < ::std::u32::MAX,
"I want this assertion to fire.");
x + 1
}
// So one is forced to instead write this:
const fn const_add1(x: u32) -> u32 {
x + 1
}
fn main() {
let x = -1i32 as u32;
println!("foo(0): {}", add1(0));
println!("bar(-1 as u32): {}",
const_add1(x));
println!("foo(-1 as u32): {}",
add1(x));
}
the above code today evaluates like so (playpen) in debug mode:
foo(0): 1
thread '<main>' panicked at 'arithmetic operation overflowed', <anon>:20
playpen: application terminated with error code 101
and in release mode:
foo(0): 1
bar(-1 as u32): 0
thread '<main>' panicked at 'assertion failed: x < ::std::u32::MAX', <anon>:5
playpen: application terminated with error code 101
(i.e., there is no way to emulate the foo
behavior within bar
while compiling in release mode.)
Another example: since we made the NonZero
constructor a const function, we cannot add a debug_assert!
to its body that checks that the input is actually non-zero. (If it were not a const function, then it is straight-forward to extend the Zeroable
trait with an fn is_zero(&self) -> bool
predicate to use as the basis for such a `debug_assert!).
I don't feel like writing up a formal RFC yet for addressing this, but I think it would be nice to extend the const fn
sublanguage to allow assert!
and debug_assert!
statements where the input text expression is restricted to a const expression, and then have rustc
actually fail the compilation if it discovers an assertion violation at compile-time.