Writing a simple evaluate I came across a funny issue.
Given the code:
enum node_type {LEAF, NODE};
struct tree_elm_t {
enum node_type type;
union {
struct tree_node_t node;
struct tree_leaf_t leaf;
} datum;
};
int parse_leaf(struct tree_leaf_t leaf);
int parse_node( struct tree_node_t node );
int parse_tree( struct tree_elm_t* tree );
....
int parse_tree( struct tree_elm_t* tree ) {
switch( tree->type ) {
case NODE: return parse_node(tree->datum.node);
case LEAF: return parse_leaf(tree->datum.leaf);
}
}
I was surprised to see that gcc is complaining about a missing control flow option :
example.c: In function 'parse_tree':
example.c:54: warning: control reaches end of non-void function
the flow problem can be solved by storing the return value, in a variable like so:
int parse_tree( struct tree_elm_t* tree ) {
int sum;
switch( tree->type ) {
case NODE: sum = parse_node(tree->datum.node); break;
case LEAF: sum = parse_leaf(tree->datum.leaf); break;
}
return sum;
}
I do however find the original code alot cleaner, is there a way of making gcc accept the original code - (I want to static analysis to realize that my code is valid, and clean).
EDIT:
I might have been a bit unclear.
lets say I compile the following code :
int parse_tree( struct tree_elm_t* tree ) {
int sum;
switch( tree->type ) {
case NODE: sum = parse_node(tree->datum.node); break;
// case LEAF: sum = parse_leaf(tree->datum.leaf); break;
}
return sum;
}
gcc will give me a warning:
example.c: In function 'parse_tree':
example.c:51: warning: enumeration value 'LEAF' not handled in switch
meaning that gcc has a sense of the options for values in the switch, and the fact that I hav commented out the LEAF case. This would imply that gcc also knows that when going though the switch every case is being examined. so why the statement:
control reaches end of non-void function
is it lack a lacking static analysis system in gcc - or a language feature?
Your compiler is complaining because all paths in your function's logic should return a value (as the prototype of this function prescribes):
int parse_tree( struct tree_elm_t* tree ) {
switch( tree->type ) {
case NODE: return parse_node(tree->datum.node);
case LEAF: return parse_leaf(tree->datum.leaf);
default: return 0; // <-- problem solved
}
}
Compiler (like me in this answer) focuses rather on the syntax than semantics of your code.
And although you have defined enum node_type {LEAF, NODE}
, your compiler doesn't want to rely on this constraint and accepts the possibility of type
in tree->type
statement having a different value from just NODE
or LEAF
anyway.
EDIT: I have tried this code:
enum node_type {LEAF, NODE};
struct node { enum node_type type; };
int parse_tree( struct node* n ) {
switch( n->type ) {
case NODE: return 1;
case LEAF: return 2;
}
}
int main() {
struct node n;
printf("%d", parse_tree(&n));
return 0;
}
on ideone and the result is following:
(gcc-4.8.1, compiled as "C") ~ http://ideone.com/b0wdSk : code is valid, outputs 2
(gcc-4.8.1, compiled as "C++") ~ http://ideone.com/OPH5Ar : same as "C"
(gcc-4.8.1, compiled as "C99 strict") ~ http://ideone.com/ou71fe : invalid because of:
error: control reaches end of non-void function [-Werror=return-type]
And to support Martin Kristiansen's point about assigning any integral value to enum being valid, I have tried struct node n; n.type = 7;
with the same code and with "C" but also with "C99 strict" the compiler doesn't complain at all. However "C++" gives:
error: invalid conversion from ‘int’ to ‘node_type’ [-fpermissive]
To prevent the missing return warning with GCC but still get warnings if you are actually missing an enum
case
, stop the control flow after the switch
statement but before the end of the function.
In C you can use exit(int)
, quick_exit(int)
, _Exit(int)
or abort()
. (reference)
In C++ there is the throw
expression – with or without a proper exception as argument. (reference)
This also has the benefit of defined behavior in case the function gets called incorrectly.
Clang does not warn about the missing return
btw.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With