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

Time:03-20

I stumbled upon a strange compile error in Clang-12. The code below compiles just fine in GCC 9. Is this a bug in the compiler or is there an actual problem with my code and GCC is just too forgiving?

#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;
}

The code also compiles fine in Clang-12 if I remove the template<typename T> line and just write V v; instead of V<void> v;. The problem also goes away if I make x non-atomic. My compile command is:

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

I get the following compiler output:

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.

CodePudding user response:

Looks like a bug to me. Modifying case A to case nullptr gives the following error message (on the template definition):

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

Making the class template into a class as suggested in the question then gives

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

The latter message is correct. When class types are used in a switch condition they should be contextually implicitly converted to a integral or enumeration type and then be promoted. Here it should use std::atomic<X>'s conversion function which converts to X and is then promoted to int.

It shouldn't matter whether the statement appears in a template or not.

The base class is not dependent, so referring to the member x directly without this-> is also fine.

A conversion of A to std::atomic<X> would not be a constant expression, which is probably where the diagnostic comes from.

Here is an open Clang bug report and here is another potentially related bug report.

Actually, although the two mentioned bug reports are still open, the test code they present seems to work correctly since Clang 10. It seems to me that the variant in your question using a base class is a special case missed by that fix.

  • Related