Search code examples
c++undefined-behaviorbit-shiftconstexpr

Undefined behavior when constexpr-evaluating negative bitshift?


Consider the following snippet of code:

int main(){
    constexpr int x = -1;
    if(x >= 0){
        constexpr int y = 1<<x;
    }
}

GCC 7 (and probably other versions of GCC) refuses to compile this and says:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]

I can guess where this may have come from: the constexpr declaration on y makes GCC evaluate y at compile time, where it might be negative. Removing the constexpr fixes the error.

However, is this undefined behavior by the standard? The condition is always false, so the value of y will never be used.

In my actual code, x is a template parameter, which may or may not be negative.


Solution

  • GCC complains because your definition of y is explicitly an ill-formed constexpr declaration. The initialzier violates [expr.const]/2, which specifies:

    An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

    • an operation that would have undefined behavior as specified in Clauses [intro] through [cpp] of this International Standard [ Note: including, for example, signed integer overflow (Clause [expr]), certain pointer arithmetic ([expr.add]), division by zero, or certain shift operations  — end note ] ;

    So you can't use 1<<x to initialize y. It doesn't matter that the branch will never be executed and can be eliminated. GCC is still obligated to verify it's semantically correct.