哪个枚举值是C++ 14中未定义的行为,为什么?

jba*_*ple 7 c++ enums undefined-behavior language-lawyer c++14

标准中的脚注暗示任何枚举表达式值都是定义的行为; 为什么Clang的未定义行为消毒剂标志着超出范围的价值?

考虑以下程序:

enum A {B = 3, C = 7};

int main() {
  A d = static_cast<A>(8);
  return d + B;
}
Run Code Online (Sandbox Code Playgroud)

未定义行为清理程序下输出是:

$ clang++-5.0 -fsanitize=undefined -ggdb3 enum.cc && ./a.out 
enum.cc:5:10: runtime error: load of value 8, which is not a valid value for type 'A'
Run Code Online (Sandbox Code Playgroud)

请注意,错误不在static_cast,而是在添加.这也是真的是一个A被创建(但没有被初始化),然后一个int值为8 memcpyA- 被添加的ubsan错误,而不是初始加载.

IIUC,ubsan在较新的clangs中确实标记了static_castC++ 17模式中的错误.我不知道该模式是否也发现了错误memcpy.无论如何,这个问题都集中在C++ 14上.

报告的错误符合标准的以下部分:

dcl.enum:

对于其基础类型是固定的枚举,枚举的值是基础类型的值.否则,枚举的值是具有最小范围指数M的假设整数类型可表示的值,使得可以表示所有枚举器.大小足以容纳枚举类型的所有值的最小位字段的宽度为M.可以定义具有未由其任何枚举​​器定义的值的枚举.如果枚举列表为空,则枚举的值如如果枚举具有值为0的单个枚举100

因此,枚举A的值为0到7(包括0和7),"范围指数" M为3. A根据expr.pre评估值为8 的类型的表达式是未定义的行为:

如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义.

但是有一个打嗝:dcl.enum的脚注上写着:

这组值用于定义枚举类型的提升和转换语义.它不排除枚举类型的表达式具有超出此范围的值.[强调我的]

问题:如果"[dcl.enum]不排除枚举类型的表达式具有超出此范围的值",为什么表达式的值为8并键入A未定义的行为?

Kam*_*Cuk 5

Clang将static_cast的使用标记为超出范围的值.如果积分值不在枚举范围内,则行为未定义.

C++标准5.2.9静态强制转换[expr.static.cast]第7段

可以将整数或枚举类型的值显式转换为枚举类型.如果原始值在枚举值(7.2)的范围内,则该值不变.否则,生成的枚举值未指定/未定义(自C++ 17起).