rust-lang / rust-lang/rfcs

`const if` to supress instantiation/codegen of unreachable branches

Open
#3,582 37 comments 19 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

Currently there's a suboptimal interaction between const asserts and const generics.

A more general function that is valid for all N cannot call a function that asserts at compile time that N fulfills some conditions even if the call is on a branch that's dead for the invalid N.

I.e. this does not compile:

#![feature(inline_const)]

// method in std
fn method_with_precondition<const N: usize>() {
    const { assert!(N > 0) };
}

// user method, no way to opt out of asserts for N = 0
fn generic_caller_method<const N: usize>() -> fn() {
    if N > 0 {
        panic_on_zero::<N>
    } else {
        || {} // fallback
    }
}

fn main() {
    let _fun = foo::<0>();
}
error[E0080]: evaluation of `panic_on_zero::<0>::{constant#0}` failed
 --> src/main.rs:5:13
  |
5 |     const { assert!(N > 0) };
  |             ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: N > 0', src/main.rs:5:13
  |
  = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)

This blocks / requires unpleasant choices in several T-libs features that want to check for N != 0 or similar constraints:

If const-eval in the dead branches is expensive it might also help compile perf.

There are efforts (https://github.com/rust-lang/rust/issues/99682) to move monomorphization-time errors to check time and also apply those checks to dead code (https://github.com/rust-lang/rust/pull/112879), which will make it even more difficult to discharge compile-time obligations imposed by callees.

Currently the language does not seem to have any way to select different code paths in generic contexts without also instantiating those paths. Even generic_const_exprs does not offer this unless it gets extended https://github.com/rust-lang/project-const-generics/issues/26

Therefore it would be useful if we could write the case above as

fn foo<const N: usize>() -> fn() {
    const if N > 0 { 
        panic_on_zero::<N>
    } else {
        || {} // fallback
    }
}

so that panic_on_zero::<0> will never be instantiated.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the issue's generic-const example and proposed const if syntax, then read the linked issues on const generics, monomorphization-time errors, and dead-code checks. Compare the proposal with the constraints described in those discussions. Done means a settled language design and an accepted RFC or other documented resolution; no implementation files or tests are named.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.