Clang-12 中的错误? "case value is not a constant expression"

Bug in Clang-12? "case value is not a constant expression"

我在 Clang-12 中偶然发现了一个奇怪的编译错误。下面的代码在 GCC 9 中编译得很好。这是编译器中的错误还是我的代码存在实际问题,GCC 太宽容了?

#include<atomic>

enum X {
        A
};

class U {
        public:
        std::atomic<X> x;
        U() { x = A; }
};

template<typename T>
class V : public U {
        public:
        V() {
                switch(x) {
                        case A:
                        break;
                }
        }
};

int main() {
        V<void> v;
        return 0;
}

如果我删除 template<typename T> 行并只写 V v; 而不是 V<void> v;,代码在 Clang-12 中也可以正常编译。如果我使 x 非原子,问题也会消失。我的编译命令是:

clang++-12 test.cpp -std=c++17 -o test

我得到以下编译器输出:

test.cpp:18:9: error: case value is not a constant expression
                        case A:
                             ^
test.cpp:17:10: warning: enumeration value 'A' not handled in switch [-Wswitch]
                switch(x) {
                       ^
test.cpp:25:10: note: in instantiation of member function 'V<void>::V' requested here
        V<void> v;
                ^
1 warning and 1 error generated.

在我看来像是一个错误。将 case A 修改为 case nullptr 会给出以下错误消息(在模板定义上):

error: no viable conversion from 'std::nullptr_t' to 'std::atomic<X>'

按照问题中的建议将 class 模板制作成 class 然后给出

error: value of type 'std::nullptr_t' is not implicitly convertible to 'int'

后面的消息是正确的。当 class 类型用于 switch 条件时,它们应该根据上下文隐式转换为整数或枚举类型,然后进行提升。这里应该使用std::atomic<X>的转换函数,转换为X,然后提升为int

声明是否出现在模板中并不重要。

基础class不依赖,所以直接引用成员x而不用this->也可以。

Astd::atomic<X> 的转换将不是常量表达式,这可能是诊断的来源。

Here is an open Clang bug report and here 是另一个可能相关的错误报告。

实际上,虽然提到的两个错误报告仍然开放,但它们提供的测试代码似乎自 Clang 10 起就可以正常工作。在我看来,你的问题中使用基数 class 的变体是该修复遗漏了特殊情况。