编译器是否允许在常量表达式中考虑未定义行为的余地? [英] Is the compiler allowed leeway in what it considers undefined behavior in a constant expression?

查看:211
本文介绍了编译器是否允许在常量表达式中考虑未定义行为的余地?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们知道会导致未定义行为的操作不是核心常数表达式 草案C ++标准



在测试中我做了 clang gcc constexpr 中的未定义行为视为错误,但在左移右移时它们不一致。例如,在所有这些被认为是根据 5.8 段运算符段 1 em> 3 :

  constexpr int x1 = 1< 33; //假设32位int 
constexpr int x2 = 1<< -1;
constexpr int x3 = -1<< 1;
constexpr int x4 = 1>> 33; //假设32位int
constexpr int x5 = 1>> -1;
会产生错误(

> 查看实时
):

 错误:constexpr变量'x1'必须由常量表达式初始化
constexpr int x1 = 1< 33; //假设32位int
^ ~~~~~~~
注意:shift count 33> ='int'类型的宽度(32位)
constexpr int x1 = 1 << 33; //假设32位int
....

gcc 会产生警告,但它仍然会将每个变量视为常量表达式( 看到它现场 ):

 警告:左移计数> = width of type [默认启用] 
constexpr int x1 = 1<< 33; //假设32位int
^
警告:左移计数为负[默认启用]
constexpr int x2 = 1< -1;
...

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



正如Alan所提到的那样,这个标准说的是不确定的行为?



确实如此,对形成的程序的诊断可以是错误或警告,但是在这种情况下 gcc 似乎不是考虑形式不正确的 程序。与其他情况不同,例如溢出 gcc 不抱怨一个无效的constexpr,但警告变化。所以,看起来它是一个错误或 gcc 不认为这些情况是未定义,因此我的问题。

解决方案

由于Johannes似乎不想将他的评论转换成答案,所以我会自我回答。我与 Howard Hinnant 进行了离线对话,他确认了 gccs中的共识



标准草案的相关章节将是 1.4 的实施合规性


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


,并具有以下项目符号(强调我):


如果程序包含违反任何可诊断规则或本标准中描述为有条件支持的结构


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



虽然这是符合行为的 constexpr 产生一个错误,并允许 SFINAE 看起来更健壮的行为。考虑到 gcc constexpr 中的未定义的行为的其他实例中发出错误,这看起来不像预期的行为,如果是,至少不一致的行为,因此我提交了错误报告


We know that operations that would cause undefined behavior are not core constant expressions(section 5.19 paragraph 2 from the draft C++ standard)

In the tests I have done both clang and gcc treat undefined behavior in a constexpr as an error but they are inconsistent in the case of left an right shift. For example, in all of these cases which are considered undefined behavior according to section 5.8 Shift operators paragraph 1 to 3:

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 will produce an error (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
....

while gcc will produce a warning but it will still consider each variable to be constant expression (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 ;
...

This looks like a gcc bug but I know a compiler can make stronger guarantees for behavior the standard says is undefined and it does look like gcc gives some stronger guarantees for shifts. This may end up being a bug but it makes me wonder if the compiler allowed that same leeway in the context of a constexpr as well or does the compiler have to strictly adhere to what the standard says is undefined behavior here?

Update

As Alan mentions, it is indeed true that the diagnostic of an ill-formed program can be either an error or a warning but in this case gcc does not seem to consider the program ill-formed. Unlike other instances such as in the case of overflow, gcc does not complain about an invalid constexpr but warns about the shifts. So then it would seem that either it is a bug or gcc does not consider these cases to be undefined and hence my question.

解决方案

Since Johannes does not seem to want to convert his comment into an answer then I will self-answer. I had an offline conversation with Howard Hinnant and he confirmed the consensus in the comments that gccs behavior in this context is indeed conforming.

The relevant section from the draft standard would be section 1.4 Implementation compliance which says in paragraph 2:

Although this International Standard states only requirements on C++ implementations, those requirements are often easier to understand if they are phrased as requirements on programs, parts of programs, or execution of programs. Such requirements have the following meaning:

and has the following bullet (emphasis mine):

If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this Standard as "conditionally-supported" when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.

A diagnostic can either be a warning or an error. So once gcc provides a warning about the undefined behavior it does not requires a subsequent warning about the constexpr itself.

Although this is conforming behavior generating an error for the constexpr and allowing SFINAE would seem to be more robust behavior. Considering that gcc issues errors in other instances of undefined behavior in a constexpr this does not seem like the intended behavior or if it was, at least inconsistent behavior, so I filed a bug report.

这篇关于编译器是否允许在常量表达式中考虑未定义行为的余地?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆