Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"control reaches end of non-void function" with fully handled case switch over an enum type

Tags:

Why does this code trigger a "control reaches end of non-void function" even if all possible values of type_t are handled? What is the best way to take care of this warning? Adding a return -1 after the switch?
(Code tested here)

typedef enum {
    A,
    B
} type_t;

int useType(type_t x) {
    switch (x) {
        case A:
            return 0;
        case B:
            return 1;
    }
}


Related: Detecting if casting an int to an enum results into a non-enumerated value
like image 663
Antonio Avatar asked Nov 09 '15 10:11

Antonio


People also ask

How do you fix control reaches end of non-void function?

If control reaches the end of a function and no return is encountered, GCC assumes a return with no return value. However, for this, the function requires a return value. At the end of the function, add a return statement that returns a suitable return value, even if control never reaches there.

What does control may reach end of non-void function?

When we write the programs in C++. After executing programs, sometimes we get the error: 'warning: control reaches the end of non-void function', which means that certain functions that would have to return some values attain the termination. It might not give any value later.

What is a non-void function?

Functions that return are great for when we need to go through a lot of steps to get a value that we want to use in our code somewhere. Calling a non-void function tells the computer to head over to the function definition, do everything, and come back with the result once it's done.


1 Answers

In general, enums are not exclusive. Someone could call your function like useType( (type_t)3 ); for example. This is mentioned specifically in C++14 [dcl.enum]/8:

It is possible to define an enumeration that has values not defined by any of its enumerators.

Now, there are a bunch of rules about exactly which other values are possible for which other sorts of enum.

There are two categories of enum. The first is fixed underlying type, e.g. enum type_t : int, or enum class type_t . In those cases all values of the underlying type are valid enumerators.

The second is not fixed underlying type, which includes pre-C++11 enums such as yours. In this case the rule about values can be summarized by saying: compute the smallest number of bits necessary in order to store all values of the enum; then any number expressible in that number of bits is a valid value.


So - in your specific case, a single bit can hold both values A and B, so 3 is not valid value for the enumerator.

But if your enum were A,B,C, then even though 3 is not listed specifically, it is a valid value by the above rule. (So we can see that almost all enums will not be exclusive).

Now we need to look at the rule for what happens if someone does actually try to convert 3 to type_t. The conversion rule is C++14 [expr.static.cast]/10, which says that an unspecified value is produced.

However, CWG issue 1766 recognized that the C++14 text was defective and has replaced it with the following:

A value of integral or enumeration type can be explicitly converted to a complete enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the behavior is undefined.

Therefore, in your specific case of exactly two enumerators with value 0 and 1, no other value is possible unless the program has already triggered undefined behaviour, so the warning could be considered a false positive.


To remove the warning, add a default: case that does something. I'd also suggest, in the interest of defensive programming, that it's a good idea to have a default case anyway. In practice it may serve to 'contain' the undefined behaviour: if someone does happen to pass an invalid value then you can throw or abort cleanly.


NB: Regarding the warning itself: it's impossible for a compiler to accurately warn if and only if control flow would reach the end of a function , because this would require solving the halting problem.

They tend to err on the side of caution: the compiler will warn if it is not completely sure, meaning that there are false positives.

So the presence of this warning does not necessarily indicate that the executable would actually allow entry into the default path.

like image 103
M.M Avatar answered Oct 04 '22 18:10

M.M