GCC __builtin_expect在constexpr上下文中检查临时指针的可空性会导致奇怪的运行时行为



我使用__builtin_expect在constexpr函数中执行空指针检查,如下所示:

constexpr int Add(const int * x, const int * y)
{
assert(__builtin_expect(!!(x && y), 1));
return *x + *y;
}

我也有一个const ref的包装器方法,允许传递临时变量:

constexpr int Add(const int & x, const int & y)
{
return Add(&x, &y);
}

然后使用临时变量创建一个全局常量:

static constexpr int result = Add(1, 2);

打印此值将得到0:


int main() {
std::cout << result; // 0
}

这到底是怎么回事?

删除__builtin_expect无法编译,GCC抱怨指针比较到constexpr上下文中的临时变量可能与此相关。

Godbolt

这是一个编译器错误,特别是https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85944.

问题与__builtin_expect无关。它是关于常量表达式上下文中的空指针检查本身。应该没问题。在作为常量表达式求值期间,编译器知道指针引用的是临时对象,其生存期跨越常量表达式求值期间,因此不为空。满足Add(1, 2)为核心常数表达式的所有条件

但是GCC似乎不能正确处理命名空间范围内的临时信息。如果将result设置为块作用域变量(无论是否包含static),则一切都按预期工作。

对于一个简单的解决方案,您当然可以在第二个重载中使用按值参数,或者您可以先将参数存储在constexpr变量中,然后传递给Add。将初始化式包装在lambda中以引入块作用域可能也会很好:
static constexpr int result = []{ return Add(1, 2); }();

相关内容

  • 没有找到相关文章