Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insufficient control flow analysis of enum switch in GCC

In the following C++ code:

typedef enum { a, b, c } Test;

int foo(Test test) {
    switch (test) {
        case a: return 0;
        case b: return 1;
        case c: return 0;
    }
}

a warning is issued when compiling with -Wall, saying that control reaches end of non-void function. Why?


Edit

Its not generally correct to say that the variable test in the example can contain any value.

foo(12354) does not compile:

> test.cpp:15:14: error: invalid conversion from ‘int’ to ‘Test’
> test.cpp:15:14: error:   initializing argument 1 of ‘int foo(Test)’

because 12354 isn't a valid Test value (though it indeed would be valid in plain C, but it's not in C++).

You sure could explicitly cast an arbitrary integer constant to the enum type, but isn't that considered Undefined Behaviour?

like image 828
ulidtko Avatar asked Jun 16 '11 18:06

ulidtko


4 Answers

The problem is that a variable of type Test can have any value allowed by the type the compiler gives it. So if it decided it was a 32-bit unsigned integer, any value in that range is allowed. So, if for instance you call foo(123456), your switch statement will not catch any value and there's no return after your switch.

Put a default case in your switch or add some error-handling code.

like image 169
SolarBear Avatar answered Oct 15 '22 04:10

SolarBear


Although there is actual danger of passing foo an argument that will not hit any of the return statements, the warning does not depend on enum, or on the danger. You can see the same effect with bool, in a switch statement which is (as far as I can tell) completely watertight.

In general the compiler isn't smart enough to deduce whether you've covered every possible path that control could actually take through the switch statement. To be that smart it would have to be able to deduce all of the possible states the program can reach before entering the switch, which leads straight to the Halting Problem.

So the deduction has to stop somewhere, and (at least with gcc) it stops with the determination that there is no default case and that therefore control might be able to leave the switch without hitting return.

like image 43
Beta Avatar answered Oct 15 '22 06:10

Beta


There is no guarantee that the variable test will contain a valid enum so it is in fact possible for you to reach the end of your non-void function, e.g. if your calling code looks like this:

Test test = Test(3);
foo(test);
like image 25
Paul R Avatar answered Oct 15 '22 04:10

Paul R


Although your enum has only three declared states, the implementation will actually choose a larger integral type (typically int) to store the values, which are NOT restricted to those declared. The Standard just makes some minimal guarantees to ensure it can at least handle the values specified and certain combinations. Sometimes this freedom is essential, as the enum values are intended to be bitwise-ORed together to form combinations. So, the function foo can actually be called with say, Test(3), which wouldn't find a return statement in your switch.

like image 27
Tony Delroy Avatar answered Oct 15 '22 04:10

Tony Delroy