当一个假设,即[[假设]]包含未定义行为时会发生什么?

23
在C++23中,[[assume(expression)]]属性使得如果expressionfalse,行为将变得未定义。 例如:
int div(int x, int y) {
    [[assume(y == 1)]];
    return x / y;
}

这将编译成与 y 始终为 1 相同的代码。
div(int, int):
        mov     eax, edi
        ret

然而,如果存在另一种未定义行为的层次,会发生什么呢?
int div(int x, int y) {
    [[assume(x / 0 == 1)]];
    return x / y;
}

现在假设中有UB,但是这个假设没有被评估。 这是什么意思?只是胡言乱语还是编译器可以对这个假设做些什么?
2个回答

21

[dcl.attr.assume]

该表达式不会被求值。

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

然而,它继续说:

如果转换后的表达式在假设出现的点上求值为真,则假设没有效果。 否则,行为是未定义的。

要么对于会导致未定义行为的表达式的求值并非对求值为true的表达式的求值,且程序的行为根据"Otherwise"句子而言将是未定义的;或者,如果你认为是否满足"如果转换后的表达式在假设出现的点上求值为真"在求值会导致未定义行为的情况下尚不确定,那么是否采取"Otherwise"分支仍然没有明确规定,因此整体上仍然存在未定义行为,因为对于一种未指定行为的选择来说,未定义行为意味着整体上仍然存在未定义行为。

这在提案P1774的第4.3章中有明确说明,作为决策的一个微妙差别,即如果假设不评估为true,则行为变为未定义,而如果假设评估为false,则行为也变为未定义。
这样,例如可以编写像x + y == z这样的假设,而编译器无需考虑有符号溢出的特殊情况,这可能使假设无法用于优化。

如果一个表达式是无法在不进行评估的情况下证明为真的,例如因为它基于访问一个具有volatile限定符的对象的效果,那该怎么办? - supercat
1
不应该指定包含未定义行为的假设表达式是否求值为 true,因为标准对未定义行为没有任何要求。它甚至可能产生一个明确记录的结果,可以是 true,并且这仍然是符合规范的。 - Ruslan
@supercat [\ dcl.type.cv] / 5:"通过volatile glvalue进行访问的语义是实现定义的。"我认为实现应该做出选择并对其进行文档化。 - user17732522
@Ruslan 这是我提到的第二种替代解释。你在我的回答中看到了什么错误,还是只想确认第二种解释? - user17732522
@user17732522:实现通常只需要记录它们如何处理实际执行的操作。良好编写的规范不应该以“会”在特定情况下发生的事情来判断程序的正确性。C99中所谓的“restrict的形式规范”是基于可能无意义的假设;我还没有弄清楚“假设”是否会有这样的矛盾,但它很可能不适合大多数任务。 - supercat

6

目前标准只是这样说

表达式在上下文中被转换为bool类型([conv.general])。表达式不会被评估。如果转换后的表达式在假设出现的地方评估为true,则该假设没有任何影响。否则,行为是未定义的。

现在,这听起来有点矛盾,因为如果一个表达式不被评估,它怎么能“评估为true”呢?但这就是“would”的意思。表达式不会被评估,但如果它被评估,会得到“true”吗?

然而,这里有一点需要注意:未定义行为是未定义的。评估引发未定义行为的表达式的结果是... 未定义的,因为这就是“未定义行为”的含义

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

那么,一个带有UB的表达式会评估为“true”吗?最合理的答案是否定的,因为它的行为是未定义的。对于任何特定的行为都没有要求。如果它不会得到“true”,那么程序就会出现UB。

3
是的,我正要发布一个类似的答案。它并没有明确说明当一个表达式具有未定义行为时会发生什么,但是一个具有未定义行为的表达式没有特定的值可以评估,所以从标准来说,它并不等于真,编译器可以根据产生的未定义行为进行任意操作。 - ShadowRanger
1
最合理的答案是否定的,因为它的行为是未定义的。这不是未定义行为的工作方式。它允许任何行为,包括产生意外的、预期的,甚至可能是文档化的结果。所以在这种情况下,它同样有可能产生true。例如,假设某个实现将除零定义为始终返回1,这在标准的观点下是完全可以接受的。然后这个假设将评估为true,在这种情况下完全符合预期。 - Ruslan
@Ruslan:记住:问题是“如果发生了,答案是否正确?”如果行为未定义,那么最准确的答案应该是“我不知道”,因为...你不知道。你不知道它是否产生真实结果,所以“可能”发生的事情是无关紧要的。因此,在这个背景下,“我不知道”并不等同于“是”,而在功能上等同于“否”。 - Nicol Bolas
好的,嗯,你说得对:如果有可能返回false(或者不返回任何值),那么行为是未定义的——根据标准来说,即使这个特定的实现保证了其他情况。 - Ruslan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接