What an interesting question, really!
After several experiments, I found a solution that uses the __builtin_types_compatible_p and __builtin_choose_expr properties of the GCC.
__builtin_types_compatible_p
GCC Guidelines:
Built-in Function: int __builtin_types_compatible_p (type1, type2)
You can use the __builtin_types_compatible_p built-in function to determine if the two types are the same.
This built-in function returns 1 if unqualified versions of types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.
This built-in function ignores top-level qualifiers (e.g. const , volatile ). For example, int equivalent to const int .
So here is how we can test void ness.
#define __type_is_void(expr) __builtin_types_compatible_p(typeof(expr), void)
__builtin_choose_expr
Built-in Function: type __builtin_choose_expr (const_exp, exp1, exp2)
You can use the __builtin_choose_expr built-in function to evaluate the code based on the value of a constant expression. This built-in function returns exp1 if const_exp , which is an integer constant expression, is nonzero. Otherwise, it returns exp2 .
? : this built-in function similar to the operator ? : ? : in C, except that the returned expression has its own type, which is not changed by the rules of promotion. In addition, the built-in function does not evaluate an expression that is not selected . For example, if const_exp is true, exp2 not evaluated, even if it has side effects.
If exp1 returned, the return type is the same as exp1 . Similarly, if exp2 returned, its return type will be the same as exp2 .
So __builtin_choose_expr intrinsic is something like a “static switch” evaluated at compile time.
Training
I am not inserting your TIMER macro here, but I assume that it can break it into two versions: one for void expr and one for the rest. Here are just the butts that evaluate the expression and give the result of the same type.
#define __DO(expr) \ ({ typeof(expr) __ret; __ret = (expr); __ret; }) #define __DO_VOID(expr) \ (void) (expr)
Naive decision
Now we can statically switch between the two implementations, depending on the actual type of expression. But in fact, the naive solution does not work, see below.
#define DO(expr) \ __builtin_choose_expr(__type_is_void(expr), \ __DO_VOID(expr), \ __DO(expr))
Attempting to compile this code that passes the void expression gives the following error:
test.c:28:9: error: variable or field '__ret' declared void test.c:28:9: error: void value not ignored as it ought to be
Although __DO_VOID selected, __DO generates errors. This behavior is described in the manual:
... an unused expression ( exp1 or exp2 depending on the value of const_exp ) can still generate syntax errors. This may change in future versions.
Working solution
The trick is to replace the original void expr with some non-empty value in order to be able to compile the __DO case (which in any case is dead code when expr invalid).
#define __expr_or_zero(expr) __builtin_choose_expr(__type_is_void(expr), 0, (expr)) #define DO(expr) \ __builtin_choose_expr(__type_is_void(expr), \ __DO_VOID(expr), \ __DO(__expr_or_zero(expr))) # works fine!
What is it! Here is the complete source code on Ideone: http://ideone.com/EFy4pE