Warn for function argument that is NOT a compile time constant
There is no way to do what you describe without GNU extensions.
This portable approach gives a hard error (because _Static_assert
requires a constant expression):
#define thefun(a, b) \
({ \
_Static_assert(b == 0, \
"'thefun' called with second argument not NULL"); \
real_thefun(a, b); \
})
However, there is one fortified-style approach that works on both GCC and Clang:
extern void thefun_called_with_nonnull_arg (void)
__attribute__((__deprecated__(
"'thefun' called with second argument not NULL")));
extern int real_thefun (void *, void *);
static inline int
thefun (void *a, void *b)
{
if (!__builtin_constant_p((unsigned short)(unsigned long)b) || b != 0)
thefun_called_with_nonnull_arg();
return real_thefun(a, b);
}
int warning_expected (void *a, void *b)
{
return thefun(a, b);
}
int warning_not_expected (void *a)
{
return thefun(a, 0);
}
Tested with GCC 8.3.0 and Clang 8.0.0.
See GCC bug report #91554 for more information about the need for the casts.
I finally managed to get it to work:
if (!__builtin_constant_p((int)(uintptr_t)b) || b != 0) {
With this you get only one warning.
It seems that gcc
can't do __builtin_constant_p
on a pointer type. The __builtin_constant_p(b)
always returns 0, so the warn function is always linked. Casting b
to int
strangely works. Although it looses precision in the pointer value, we don't care about it, cause we only check if it's a constant.