C macro _Generic gives unexpected compiler error
The problem is that every branch of a generic selection must be valid, even if they are not evaluated.
For example, your first macro:
bob(i1, s1)
Expands to (types added for clarity):
_Generic( ((int32_t) i1),
int32_t: _Generic( ((int16_t) s1),
int16_t: "s-l",
int8_t: "c-l" ),
int16_t: _Generic( ((int16_t) s1), // The error is here
int32_t: "l-s",
int8_t: "c-s"),
int8_t:_Generic( ((int16_t) s1),
int32_t: "l-c",
int16_t: "s-c")
)
Obviously the uint32_t
branch is valid: It just selects "s-l"
. But the int16_t
branch is not valid, as from
(An int16_t
itself) does not have a corresponding branch.
In this particular scenario, it wouldn't hurt to add a self-conversion operator that does nothing.
A-Ha Moment, Thanks to John Bollinger in comments.
If I Hand expand the Macro into code:
void main(void)
{
int32_t i1;
int16_t s1;
int8_t c1;
printf("%s\n",
_Generic( i1 , int32_t: _Generic(s1, int16_t: "s-l", int8_t: "c-l" ),
int16_t: _Generic(s1, int32_t: "l-s", int8_t: "c-s" ), // <-- No int16_t here
int8_t: _Generic(s1, int32_t: "l-c", int16_t: "s-c") ) );
}
It becomes obvious that this will not compile unless the paths not taken are stripped out which I guess is not what happens.
So I guess default case to error condition is the correct method?
Edit: So I still have not figured out how to get the default case to throw a compiler error, however I discovered if I put a call in the default case to a non-existant function it will compile but will throw a linker error if I violate the rule I was trying to enforce. Not great but better than a runtime error.
char *this_function_does_not_exist(); // fake function prototype
#define bob( to, from ) \
_Generic( to , \
int32_t: _Generic(from, \
default: this_function_does_not_exist(), \
int16_t: "s-l", \
int8_t: "c-l" ) , \
int16_t: _Generic(from, \
default: this_function_does_not_exist(), \
int32_t: "l-s", \
int8_t: "c-s") , \
int8_t:_Generic(from, \
default: this_function_does_not_exist(), \
int32_t: "l-c", \
int16_t: "s-c") \
)
If anyone who reads this has a better, C11, way to in effect embed a _Static_assert inside a _Generic let me know. (I know I can embed a _Generic inside a _Static_assert, it just gets really ugly and I don't want to maintain duplicate logic)