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.