13

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?

cigien
  • 57,834
  • 11
  • 73
  • 112

1 Answers1

13

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    In the example from the standard, the expression initializes a global variable. And gcc does [print 1](https://godbolt.org/z/Tc4jG9) with that modification. Is that relevant at all? – cigien Jul 09 '20 at 21:25
  • @cigien I don't think so, there's nothing relevant here about scoping or storage duration. But the wording is kind of hard to follow so I'm not sure. – Barry Jul 09 '20 at 21:27
  • I'm not so sure this is a bug, clang [prints 0](https://godbolt.org/z/Yvd8YE) for that case as well. I feel like there's a difference that has *something* to do with scope. – cigien Jul 09 '20 at 21:35
  • @cigien Okay I found the right bit, I have to rewrite this answer again, give me a few min. – Barry Jul 09 '20 at 21:41
  • @cigien Ok, third time's the charm maybe. – Barry Jul 09 '20 at 21:48
  • Yeah, so it's storage duration (makes more sense than scope :p). I'll think about this for a bit, but seems correct to me. – cigien Jul 09 '20 at 21:50