Description
openedon Apr 24, 2024
In #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 containUnsafeCell
, 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. Cargo itself doesn't even build any more so we did not get numbers.) 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.
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