Skip to content

const fn's should allow (and eval) assert! and debug_assert! statements #1383

Closed
@pnkfelix

Description

@pnkfelix

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-compilerRelevant to the compiler team, which will review and decide on the RFC.T-langRelevant to the language team, which will review and decide on the RFC.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions