Undefined behavior when constexpr-evaluating negative bitshift?

吃可爱长大的小学妹 提交于 2019-12-23 20:51:11

问题


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.


回答1:


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.




回答2:


Just as StoryTeller explained, this is the expected behavior, as left shifting by a negative number is undefined behavior and an expression resulting in UB can't be used in a core constant expression (the fact that you don't try to access the result of that expression during runtime doesnT' change the fact that you require the compiler to evaluate it during compiletime).

If your branch actually depends on a template parameter you can work around this by using if constexpr:

template<int x>
constexpr int foo() {
    if constexpr (x >= 0) {
        constexpr int y = 1 << x;
        return y;
    }
    return 0;
}

Edit: As the answers to StoryTeller's question explain, this ONLY works inside a template and only if the conditional depends on the template parameter (more detailed explanation in the answers).



来源:https://stackoverflow.com/questions/46510531/undefined-behavior-when-constexpr-evaluating-negative-bitshift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!