rust-lang / rust-lang/rust

Clean up implicit const promotion behavior

Open
#124,328 7 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-const-prop A-constant-promotion A-maybe-future-edition C-enhancement I-lang-radar T-compiler T-lang WG-const-eval
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

In https://github.com/rust-lang/rust/issues/80619 we tamed promotion to no longer cause fundamental problems around whether and when const-evaluation is allowed to fail. All our promoteds are now either infallible, or in guaranteed-live code.

However, as part of this, the rules for what we promote when became "a bit" obscure:

  • &(1/1) gets promoted, but &(1/(1+0)) does not. This is because when the RHS of the division is not a constant, it may be 0, and computing the promoted value would fail, so we can't promote this.
  • Inside the initializer expression of a const/static, &myfunction() gets promoted only if the control flow graph of the initializer is a straight line until it reaches this point. (See here for examples.) This is to ensure that we do not promote function calls in dead code.
  • &Enum::Variant gets promoted even if other enum variants contain UnsafeCell, which is borderline unsound.

We should probably clean that up, by not promoting function calls or division/modulo ever (requiring a const block instead), and also not doing value-based reasoning for interior mutability during promotion. I assume this requires an edition transition. (Here is a crater run that just tried to not promote function calls ever. ) Edition transitions for promotions are non-trivial; they would have to work something like this:

  • Do not promote these things.
  • Run borrowck.
  • If that fails, try promoting them and see if that makes borrowck pass. If yes, issue a forward-compat lint. If there's more than one candidate that could be promoted, try all of them one after the other... (or accept that we would add more const { ... } blocks than are actually needed)

That's non-trivial but would also help clean up a very organically grown (and hence confusingly-shaped) part of the language, and resolve some cases that are at least borderline unsound.

FWIW, for division/modulo, there is in theory an alternative -- we could treat them similar to what we do with overflows in add/sub/mul. This requires having a version of these operators that always succeeds. Then we can promote &(a/b) to using that kind of division, and additionally include a runtime check (outside the promoted) for division-by-0 (and for overflow due to division-by-int-min).

Cc @rust-lang/wg-const-eval

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

Start by reading issue #80619 and the examples in PR #121557 to understand the current promotion rules. Review PR #148952 and its crater report for the impact of not promoting function calls. Done requires an agreed promotion design, including edition-transition behavior and handling of division, modulo, and interior mutability.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.