编译器是否允许在常量表达式中考虑未定义的行为?

时间:2014-02-01 18:44:15

标签: c++ gcc c++11 language-lawyer undefined-behavior

我们知道operations that would cause undefined behavior are not core constant expressions 5.19第2段draft C++ standard

在我已经完成的测试clanggcc中,将 constexpr 中的未定义行为视为错误,但在左移右移的情况下它们不一致。例如,根据部分5.8 Shift运算符 1 3 ,所有这些被视为未定义行为的情况:< / p>

constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
constexpr int x2 =  1 << -1 ;
constexpr int x3 =  -1 << 1 ;
constexpr int x4 =  1 >> 33 ; //Assuming 32-bit int
constexpr int x5 =  1 >> -1 ;

clang会产生错误( see it live ):

error: constexpr variable 'x1' must be initialized by a constant expression
    constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
                  ^     ~~~~~~~
note: shift count 33 >= width of type 'int' (32 bits)
    constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
....

虽然gcc会产生警告,但仍然会将每个变量视为常量表达式( see it live ):

warning: left shift count >= width of type [enabled by default]
 constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
                          ^
warning: left shift count is negative [enabled by default]
 constexpr int x2 =  1 << -1 ;
...

这看起来像一个gcc错误,但我知道编译器可以为标准所说的未定义的行为提供更强的保证,它看起来像gcc gives some stronger guarantees for shifts。这可能最终成为一个错误,但它让我想知道编译器是否在constexpr的上下文中允许相同的余地,或者编译器是否必须严格遵守标准所说的未定义行为?< / p>

更新

正如Alan提到的那样,格式错误的程序的诊断确实可能是错误或警告,但在这种情况下,gcc似乎并未考虑程序格式错误。与其他情况不同,例如在overflow的情况下,gcc不会抱怨无效的constexpr,但会警告这些变化。那么它似乎是一个错误或gcc不认为这些情况是未定义因此我的问题。

1 个答案:

答案 0 :(得分:3)

由于约翰内斯似乎不想将他的评论转换成答案,我会自我回答。我与Howard Hinnant进行了离线对话,他在评论中确认了gccs在这种情况下的行为确实符合要求。

标准草案的相关部分是第1.4 条实施合规性部分,该部分在 2 段落中说明:

  

虽然本国际标准仅规定了对C ++实现的要求,但如果将这些要求表达为对程序,程序部分或程序执行的要求,则这些要求通常更容易理解。这些要求具有以下含义:

并且有以下项目符号(强调我的):

  

如果某个程序包含违反任何可诊断规则或本标准中描述的构造的发生,如果该实施不支持该构造,那么符合条件的实现应至少发出一个诊断消息。

诊断可以是警告或错误。因此,一旦gcc提供有关未定义行为的警告,它就不需要关于constexpr本身的后续警告。

虽然这是符合行为,为 constexpr 生成错误,并且允许 SFINAE 似乎是更健壮的行为。考虑到gcc constexpr 中的未定义行为的其他实例中发出错误,这似乎不是预期的行为,或者如果是,至少是不一致的行为,所以我filed a bug report