为何Clang不对穷尽枚举Switch的函数报错?如何配置触发错误?
考虑以下代码:
enum class E { ONE = 1, TWO = 2 }; int foo(E e) { switch (e) { case E::ONE: return 1; case E::TWO: return 2; } }
C++标准允许枚举类拥有超出枚举值范围的取值:
若枚举类型拥有固定的底层类型,必要时会先通过整数提升(7.3.7)或整数转换(7.3.9)将值转换为该类型,再转换为枚举类型。
调用foo(static_cast<E>(3))会触发未定义行为(UB)。这段代码无法通过GCC编译,但可通过Clang编译。
是否存在Clang编译选项可为此场景触发错误?-Wswitch-enum要求枚举所有分支(不适用于枚举范围极大的场景),-Wswitch-default要求添加default分支(不利于穷尽性检查)。我希望switch枚举分支不被认定为总能命中某一分支。
Clang目前没有直接匹配你需求的单一编译选项,但可以通过以下方式实现类似检测效果:
结合
-Wunreachable-code手动触发警告
在switch末尾添加一段不会被正常执行的代码(比如__builtin_unreachable()或终止程序的调用),开启-Wunreachable-code后,Clang会在认为switch可能未命中任何分支时,发出警告提示末尾代码不可达——这间接提醒了你存在未覆盖的枚举取值场景:int foo(E e) { switch (e) { case E::ONE: return 1; case E::TWO: return 2; } __builtin_unreachable(); }-Wswitch配合静态分析工具
开启-Wswitch后,Clang会对未覆盖的枚举成员发出警告;对于超出枚举成员的自定义转换值,可搭配Clang-Tidy等静态分析工具,通过自定义规则或现有规则的延伸思路,检测枚举类型switch是否处理了底层类型的所有可能取值。调试模式下的断言检查
若不需要编译期错误,可在switch末尾添加断言,在调试阶段捕获非法枚举值:#include <cassert> int foo(E e) { switch (e) { case E::ONE: return 1; case E::TWO: return 2; } assert(false && "非法的枚举值"); return -1; }
注意:Clang的-Wswitch-enum仅检查枚举成员是否被全覆盖,不会针对超出成员的自定义转换值发出警告,这是因为C++标准允许此类转换操作。
内容的提问来源于stack exchange,提问作者Curious

