Skip to content

rustc will emit code for const-eval false branches #108857

Open
@Voultapher

Description

@Voultapher

I tried this code:

#![feature(inline_const)]

use std::mem;

const fn is_elegible<T>() -> bool {
    mem::size_of::<T>() <= mem::size_of::<[u64; 4]>()
}

fn logic_a<T>(_v: &mut [T]) {
    println!("{}", std::any::type_name::<T>());
}

fn logic_b<T>(v: &mut [T]) {
    use std::sync::atomic::{AtomicBool, Ordering};

    static VAL: AtomicBool = AtomicBool::new(false);

    if v.len() > 2 {
        VAL.store(true, Ordering::Release);
    }
}

fn do_some_logic<T>(v: &mut [T]) {
    if const { is_elegible::<T>() } {
        logic_a(v);
    } else {
        logic_b(v);
    }
}

pub fn main() {
    do_some_logic(&mut [3, 5, 6]);

    // struct BigThing([u64; 20]);
    // do_some_logic(&mut [BigThing([0; 20])]);
}

I expected to see this happen:

Looking at the LLVM-IR and generated code, it generates code for logic_b despite const { is_elegible::<T>() } evaluating to true, which means only logic_a should be passed to the code-gen backend.

Instead, this happened:

Before LLVM-IR or any other backend IR is generated if an expression is forced to be evaluated inline via an inline cost block, it must be evaluated and pruned.

Meta

rustc --version --verbose:

rustc 1.69.0-nightly (5243ea5c2 2023-02-20)
binary: rustc
commit-hash: 5243ea5c29b136137c36bd773e5baa663790e097
commit-date: 2023-02-20
host: x86_64-unknown-linux-gnu
release: 1.69.0-nightly
LLVM version: 15.0.7

This has been discussed before, and I was told the expected behavior is the current behavior https://internals.rust-lang.org/t/why-does-a-const-eval-not-taken-branch-still-generate-llvm-ir/18378/15 and it is for some cases but not reliably.

Motivation

When building large complex abstractions such as sort implementations it can be valuable to limit certain code to specific types. There are other places in the standard library that also do such heuristics eg.

if (left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()) {

The conversation seemed to show no consensus whether if const_fn() should be const evaluated, but it using if const { const_fn() } seems to imply that we can rely on the condition being const evaluated. Without such a construct certain optimizations can't be done without sacrificing compile times, which is problematic eg. #108662

What I'd like to se would be consistent behavior or a new abstraction that provides that behavior if inline const expressions are deemed to be the wrong tool.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationA-const-propArea: Constant propagationC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions