Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc and clang disagree on whether expression is constant evaluated

For the following program:

struct S { int i; };

constexpr S f() { 
  return std::is_constant_evaluated() ? S{1} : S{0}; 
}

int main() {
  S s = f();
  return s.i;
}

gcc returns 0, and clang returns 1. demo

I don't think the evaluation of f is being done in a context that requires constant evaluation, so I think clang is wrong here. Or is it the other way round? Or are both results valid?

like image 786
cigien Avatar asked Jul 09 '20 19:07

cigien


1 Answers

The requirement we're looking for is if an expression is manifestly constant-evaluated, which is defined in [expr.const]/14, which is:

  • a constant-expression, or
  • the condition of a constexpr if statement ([stmt.if]), or
  • an immediate invocation, or
  • the result of substitution into an atomic constraint expression to determine whether it is satisfied ([temp.constr.atomic]), or
  • the initializer of a variable that is usable in constant expressions or has constant initialization.

The first four of these conditions clearly don't hold.

For the last one, our variable is not usable in constant expressions since it neither is constexpr nor has a const-qualified integral/enumeration type. So that's the first half of the fifth condition.

For the last part of the last one, we need to determine if we have constant initialization (not to be confused with being constant-initialized). That definition is in [basic.start.static]/2, emphasis mine:

Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized ([expr.const]).

But s is not a variable with static or thread storage duration, so there is no constant initialization, so the last part of the last condition doesn't hold either.

Hence, none of the conditions hold, and in the OP, std::is_constant_evaluated() should return false and this is a clang bug.

like image 57
Barry Avatar answered Oct 16 '22 10:10

Barry