rust-lang / rust-lang/rust

Which functions are "reachable", and therefore subject to monomorphization-time checks, is optimization-dependent

Open
#122,814 10 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-const-eval A-monomorphization C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

This is a variant of https://github.com/rust-lang/rust/issues/107503, but with a different underlying cause and hence not fixed by https://github.com/rust-lang/rust/pull/122568. @tmiasko provided this magnificent example (comments by me, they may be wrong):

//! This used to fail in optimized builds but pass in unoptimized builds. The reason is that in
//! optimized builds, `f` gets marked as cross-crate-inlineable, so the functions it calls become
//! reachable, and therefore `g` becomes a collection root. But in unoptimized builds, `g` is no
//! root, and the call to `g` disappears in an early `SimplifyCfg` before "mentioned items" are
//! gathered, so we never reach `g`.
#![crate_type = "lib"]

struct Fail<T>(T);
impl<T> Fail<T> {
    const C: () = panic!(); //~ERROR: evaluation of `Fail::<i32>::C` failed
}

pub fn f() {
    loop {}; g()
}

#[inline(never)]
fn g() {
    h::<i32>()
}

// Make sure we only use the faulty const in a generic function, or
// else it gets evaluated by some MIR pass.
fn h<T>() {
    Fail::<T>::C;
}

The symptom here is the opposite of https://github.com/rust-lang/rust/issues/107503: cargo build succeeds but cargo build --release fails. This is because more things become roots in optimized builds and therefore we evaluate more things.

I can think of two ways of fixing this:

  • Making the set of collection roots opt-level-independent. This is what I tried in https://github.com/rust-lang/rust/commit/a303df006a5be15f799fdb9f987ac083f8de191d. It caused a ~2% slowdown on some benchmarks; it's hard to get the full picture as we only benchmarked it together with the rest of https://github.com/rust-lang/rust/pull/122568. There may be ways to reduce this cost.
  • Make sure g is considered "mentioned" in f. This requires either collecting (some of) the mentioned items very early during MIR building, or making SimplifyCfg preserved unreachable blocks. This likely has lower perf impact, but it means we'd still miss const-eval failures reachable from dead private monomorphic functions.

Contributor guide

Open the contributing guide

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

Use the Rust snippet in the issue as the reproducer; compare cargo build with cargo build --release and inspect how collection roots and “mentioned” items differ around MIR SimplifyCfg. A complete fix should make the diagnostic behavior independent of optimization while addressing the performance or dead-private-function trade-off described in the proposed approaches.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
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.