assign with op in constexpr: gcc vs. clang vs

  • A+
template<class A, class B> constexpr int f(A a, B b) {     a /= b;     return a; }  constexpr int x = f(2, 2);   // a, b: int constexpr int y = f(2., 2.); // a, b: double constexpr int z = f(2, 2.);  // a: int, b: double //<-- BOOM! constexpr int w = f(2., 2);  // a: double, b: int  int main() {} 

The code doesn't compiled by clang (error: constexpr variable 'z' must be initialized by a constant expression), msvc crashed (according to godbolt) and gcc works fine. If a /= b is simply replaced by a = a / b then everybody accepts it. Why? Who is right? Seems it's related to implicit narrowing conversion, but then why a = a / b works?


Some discovery after digging into clang's source:

In clang, the evaluation of constant expression is mostly handled in lib/AST/ExprConstant.cpp. In particular, compound assignment of integer is handled by CompoundAssignSubobjectHandler::found(APSInt &Value, QualType SubobjType), which contains:

    if (!SubobjType->isIntegerType() || !RHS.isInt()) {       // We don't support compound assignment on integer-cast-to-pointer       // values.       Info.FFDiag(E);       return false;     } 

Apparently this rejects a non-integer RHS and produces a diagnostic. Judging from the comment, the author wasn't considering floating-point values when he wrote this if statement. Thus, I venture to say that this is an oversight made by Richard Smith when he implemented the compound assignment evaluator.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: