In C++23, the [[assume(conditonal-expression)]]
attribute makes it so that if conditional-expression doesn't evaluate to true
, the behavior is undefined.
For example:
int div(int x, int y) {
[[assume(y == 1)]];
return x / y;
}
This compiles to the same code as if y
was always 1
.
div(int, int):
mov eax, edi
ret
As commenters have pointed out, this is not a required optimization; it's just what GCC happens to do with the information that anything but y == 1
would be UB.
It would be valid for compilers to completely ignore all assumptions.
But what about constant expressions?
Compilers are required to diagnose all undefined behavior in constant expressions1), but is this reasonable? For example:
constexpr bool extremely_complicated(int x) {
bool result;
// 10,000 lines of math ...
return result;
}
constexpr int div(int x, int y) {
// This should result in a compiler error when the compiler is unable to prove
// what extremely_complicated(x) returns.
// extremely_complicated(x) is not evaluated, so it needs to be able to
// prove the result without evaluating the function.
[[assume(extremely_complicated(x))]];
return x / y;
}
constexpr int quotient = div(4, 2);
Is it still a problem even if the compiler has no way of proving whether an assumption would evaluate to true
? It obviously can't solve the halting problem.
How exactly do assumptions and constant expressions interact? [dcl.attr.assume] doesn't have any wording on this.
1) Note: extremely_complicated(x)
is not a constant expression, but it's located in an assumption whose failure would result in UB within a constant evaluation of div(4, 2)
, which is a constant expression. It is generally said that UB in a constant expression needs to be diagnosed.