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->
也可以。
A
到 std::atomic<X>
的转换将不是常量表达式,这可能是诊断的来源。
Here is an open Clang bug report and here 是另一个可能相关的错误报告。
实际上,虽然提到的两个错误报告仍然开放,但它们提供的测试代码似乎自 Clang 10 起就可以正常工作。在我看来,你的问题中使用基数 class 的变体是该修复遗漏了特殊情况。
我在 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->
也可以。
A
到 std::atomic<X>
的转换将不是常量表达式,这可能是诊断的来源。
Here is an open Clang bug report and here 是另一个可能相关的错误报告。
实际上,虽然提到的两个错误报告仍然开放,但它们提供的测试代码似乎自 Clang 10 起就可以正常工作。在我看来,你的问题中使用基数 class 的变体是该修复遗漏了特殊情况。