Suspicious case statement syntax accepted by C compilers

Viewed 56

I found a long-standing bug is some code (I had written the code, so my it's own fault). The thing that I cannot understand is why it was not spotted by the compiler.

The code is in C, which I have been using for many years and I always consider myself knowledgeable about, but it makes no sense to me. I have tried similar code under both Visual Studio and Gnu C compilers and both accept it.

The code is:

enum TYPE_ENUMS {
    TEST_CASE = 1,
};

int main()
{
    int caseVal = 1;
    switch (caseVal) {
    TEST_CASE:
        printf("1\n");
    default:
        printf("Unknown Case %d\n", caseVal);
        break;
    }   
}

Can anyone explain how an enum can be part of a case statement without a "case" before it. Should this be valid code? and if so, is there a use for it?

2 Answers

What you have is actually a label that can be the target of a goto statement, and there's no restriction that says ordinary labels can't appear inside of a switch block.

Labels are in a separate namespace from ordinary identifiers which includes enum constants, so they can coexist without ambiguity. This is spelled out in section 6.2.3p1 of the C standard:

If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:

  • label names (disambiguated by the syntax of the label declaration and use);
  • the tags of structures, unions, and enumerations (disambiguated by following any of the keywords struct, union, or enum);
  • the members of structures or unions; each structure or union has a separate namespace for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
  • all other identifiers, called ordinary identifiers(declared in ordinary declarators or as enumeration constants).

It is valid code but, perhaps, not in the way you think. There is no error in your code but both MSVC and Clang-cl (in Visual Studio 2019) give warnings that indicate your TEST_CASE: line is simply an independent (of the switch) label.

Clang gives these:

warning : unused label 'TEST_CASE' [-Wunused-label]
warning : code will never be executed [-Wunreachable-code]

(The latter for the printf("1\n"); line)

MSVC gives this, in addition to equivalents of the above two warnings:

warning C4065: switch statement contains 'default' but no 'case' labels

If there is a 'moral to the story', it is this: Enable full compiler warnings!

Related