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

Sha*_*our 5 c++ gcc undefined-behavior language-lawyer c++11

我们知道导致未定义行为的操作不是核心常量表达式(C++标准草案第5.19节第2段)

在测试中我已经完成了两个clang并将constexpr中的gcc未定义行为视为错误,但是在左移右移的情况下它们是不一致的.例如,根据Shift操作符13段,所有这些被视为未定义行为的情况:5.8

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 ;
Run Code Online (Sandbox Code Playgroud)

clang会产生错误(看到它):

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
....
Run Code Online (Sandbox Code Playgroud)

虽然gcc会产生警告,但它仍然会将每个变量视为常量表达式(请参见实时):

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 ;
...
Run Code Online (Sandbox Code Playgroud)

这看起来像一个gcc错误,但我知道编译器可以为标准所说的未定义的行为提供更强的保证,并且它确实看起来像gcc为转换提供了更强的保证.这可能最终成为一个错误,但它让我想知道编译器是否允许在一个上下文中同样的余地,constexpr或者编译器是否必须严格遵守标准所说的未定义行为?

更新

正如艾伦提到,这的确是事实,诊断的的形成不良的程序可以是一个错误或警告,但在这种情况下,gcc似乎没有考虑到节目形成不良.与其他情况不同,例如在溢出的情况下,gcc不会抱怨无效的constexpr,但会警告这些变化.那么它似乎是一个错误或gcc不认为这些情况是未定义的,因此我的问题.

Sha*_*our 3

由于约翰内斯似乎不想将他的评论转化为答案,那么我将自我回答。我与Howard Hinnant进行了线下对话,他确认了评论中的共识,即gccs在这种情况下的行为确实是合规的。

\n\n

标准草案中的相关部分是1.4 “实施合规性”部分,其中第2段规定:

\n\n
\n

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

\n
\n\n

并有以下项目符号(重点是我的):

\n\n
\n

如果程序包含违反任何可诊断规则或出现本标准中描述为 \xe2\x80\x9cconditionally-supported\xe2\x80\x9d 的构造,而实现不支持该构造,则应在至少一条诊断消息。

\n
\n\n

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

\n\n

尽管这是为constexpr生成错误的符合行为,但允许SFINAE似乎是更稳健的行为。考虑到constexpr未定义行为gcc的其他实例中会出现错误,这似乎不像预期的行为,或者如果是的话,至少是不一致的行为,所以我提交了一份错误报告

\n