当假设 [[assume]] 包含 UB 时会发生什么?

Jan*_*tke 23 c++ language-lawyer c++23 assumption

在 C++23 中,该[[assume(expression)]]属性使得如果表达式false,则行为未定义。例如:

int div(int x, int y) {
    [[assume(y == 1)]];
    return x / y;
}
Run Code Online (Sandbox Code Playgroud)

y这会编译成与始终相同的代码1

div(int, int):
        mov     eax, edi
        ret
Run Code Online (Sandbox Code Playgroud)

但是,如果存在另一级别的未定义行为,会发生什么情况?

int div(int x, int y) {
    [[assume(x / 0 == 1)]];
    return x / y;
}
Run Code Online (Sandbox Code Playgroud)

现在假设里面有UB,但是假设没有被评估。这是什么意思?这只是无稽之谈还是编译器可以用这个假设做任何事情?

use*_*522 21

来自[dcl.attr.assume]

不计算表达式。

因此,表达式的未定义行为并不立即意味着给定输入的程序的未定义行为。

然而它仍在继续:

如果转换后的表达式在假设出现的点处计算结果为 true,则该假设不起作用。否则,行为是未定义的。

具有未定义行为的表达式的计算不是对计算结果为的表达式的计算,true并且程序的行为也将根据“否则”语句未定义,或者,如果您认为未指定是否未指定如果评估将具有未定义的行为,则满足“如果转换后的表达式在假设出现的点处评估为真”,则仍然不会指定是否采用“否则分支,因此将再次出现总体未定义的行为,因为未指定行为的一种选择的未定义行为意味着总体未定义的行为。

这在第 4.3 章的提案P1774中得到了具体解决。作为在假设不计算为 时使行为未定义的决定true与在假设计算为 时使行为未定义的决定之间的细微差别false

通过这种方式,例如可以编写假设,x + y == z而编译器不必考虑有符号溢出的特殊情况,这可能会使假设无法用于优化。


Nic*_*las 6

目前所有标准的规定是

该表达式根据上下文转换为 bool ([conv.general])。不计算表达式。如果转换后的表达式在假设出现的点处计算结果为 true,则该假设不起作用。否则,行为是未定义的。

现在,这听起来有点矛盾,就好像一个表达式没有被评估,它怎么能“评估为真”。但这就是“愿意”的意义所在。该表达式没有被求值,但如果它求值,结果会是“true”吗?

但事情是这样的:未定义的行为是未定义的。评估引发 UB 的表达式的结果是...未定义,因为这就是“未定义行为”的含义

但是,如果任何此类执行包含未定义的操作,则本文档对使用该输入执行该程序的实现没有任何要求(甚至不涉及第一个未定义操作之前的操作)。

那么,带有 UB 的表达式的计算结果会是“true”吗?最合理的答案是否定的,因为它的行为是未定义的。对任何特定行为没有任何要求。如果结果不是“true”,则程序有 UB。

  • 是的,我正要发布类似的答案。它没有明确说明当表达式具有未定义行为时会发生什么,但是具有未定义行为的表达式没有其计算的特定值,因此根据标准,它不会计算为 true,并且编译器可以执行任何它喜欢的操作响应由此产生的未定义行为。 (3认同)