https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91158

--- Comment #3 from Cassio Neri <cassio.neri at gmail dot com> ---
Forget my use case and comments on dead code elimination. That was a
digression. (My bad.) In general, I don't expect `if` and `if constexpr` to
behave the same but I do in this particular case. (I might be wrong.) Finally,
since `__builtin_constant_p` is not standard this ticket is a feature request,
not a bug report.

My reasoning is this: when the compiler sees `static_assert(f1(1));` it enters
a "constexpr evaluation mode" (not sure this is the right terminology but you
get the point). At this moment, regardless of optimization level the compiler
must propagate `1` to `f1` otherwise (generally speaking) it cannot evaluate
`f1(1)` and decide whether the `static_assert` passes or not. Therefore, when
it enters `f1` and sees `if constexpr (__builtin_constant_p(n))` it is already
in "constexpr evaluation mode" (so `constexpr` here is redundant) and it knows
`n == 1`. Hence, it should evaluate `__builtin_constant_p(n)` to `1`.

To make clear that my point is not that `if` and `if constexpr` should always
work the same, please, contrast with this program:

int main() {
    if (f0(1))           puts("if   : yes");
    else                 puts("if   : no");
    if constexpr (f0(1)) puts("if ce: yes");
    else                 puts("if ce: no");
}

The output in -O0 mode is `if   : no` and `if ce: yes`. Since the first `if` is
not `constexpr`, the compiler doesn't need to enter "constexpr evaluation mode"
and -O0 is too low for `1` to be propagated to `f0`. The second `if`, on the
other hand, is `constexpr`. The compiler enters "constexpr evaluation mode",
propagates `1` to `f0` and evaluates `if (__builtin_constant_p(n))` to `1`
regardless that this `if` is not `constexpr`.

Also, to make clear I'm OK with `if constexpr (__builtin_constant_p(n))`
evaluating to `0` even in -O3 level, consider this:

int main() {
    if (f0(1))           puts("if   : yes");
    else                 puts("if   : no");
}

The output is `if   : no`. Since the `if` is not `constexpr`, constant
propagation is up to the optimizer (QoI issue) and I'm OK if it enters
"constexpr evaluation mode" only inside `f1` (when it sees `if constexpr
(__builtin_constant_p(n))`) at which point is too late to know the value of `n`
and considers `n` as non constant.

Finally, I would link to link this issue with bug 70552 comment 5. Martin
Sebor, commenting on a patch for another related issue says:

    "The patch referenced from it sets a precedent for the intrinsic treating
constant expressions as constant despite its late evaluation under "normal"
circumstances".

IIUIC, it says that `__builtin_constant_p(expr)` always evaluates to `1` if
expr is a C++ constant expression (e.g. a call to a `constexpr` function).
Similarly, I believe that in "constexpr evaluation mode", almost every
evaluation of `__builtin_constant_p(expr)` in the taken path should yield `1`.
(There are exceptions, notably, when `expr` is a non `constexpr` local
variable.)

Reply via email to