为什么 g++-11 '-O2' 包含错误而 '-O0' 正常?

Why does g++-11 '-O2' contain a bug while '-O0' is ok?

#include <limits>
#include <cstdint>
#include <iostream>

template<typename T>
T f(T const a = std::numeric_limits<T>::min(),
    T const b = std::numeric_limits<T>::max())
{
    if (a >= b)
    {
        throw 1;
    }

    auto n = static_cast<std::uint64_t>(b - a + 1);
    if (0 == n)
    {
        n = 1;
    }

    return n;
}

int main()
{
    std::cout << f<int>() << std::endl;
}

g++-11 -std=c++20 -O2 应该输出 0 而不是 1!

clang++ 符合预期。如果我把-O2改成-O0,g++-11也可以。

参见:online demo

为什么 g++ -O2 包含一个错误,而 -O0 没问题?

ab的类型是intaINT_MIN和[=12时,

b - a + 1显然是UB =] 是 INT_MAX 因为有符号溢出是未定义的行为。

来自cppreference:

When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined

在执行计算之前,您不会转换为 int64_t