I doubt that there's a really good solution for this, but I've found a possibility for something like const_assert()
, which appears to work with the two versions of gcc I have readily to hand (4.1.2 and 4.4.4).
#include <assert.h>
extern void dummy_void_function(void);
#define const_assert(x) \
assert(__builtin_choose_expr(__builtin_constant_p((x) == (x)), \
(x), dummy_void_function()))
extern int function(void);
extern int __attribute__((pure)) pure_function(void);
extern int __attribute__((const)) const_function(void);
extern int global;
extern volatile int volatile_global;
void test(int arg)
{
/* These cause compile-time errors: */
const_assert(function() == 0);
const_assert(pure_function() == 0);
const_assert(volatile_global == 0);
/* These don't: */
const_assert(const_function() == 0);
const_assert(arg == 0);
const_assert(global == 0);
}
This is really checking whether the expression (x) == (x)
is regarded as a compile-time constant by the compiler, and creating brokenness if it's not. The "good" cases effectively become assert(x);
and the bad ones generate compile-time errors:
$ gcc -c const_assert.c
const_assert.c: In function 'test':
const_assert.c:18: error: void value not ignored as it ought to be
const_assert.c:19: error: void value not ignored as it ought to be
const_assert.c:20: error: void value not ignored as it ought to be
However, with optimisation enabled, it still produces errors in the expected cases, but one of them is a bit odd:
$ gcc -O -c const_assert.c
const_assert.c: In function 'test':
const_assert.c:18: error: void value not ignored as it ought to be
const_assert.c:19: error: first argument to '__builtin_choose_expr' not a constant
const_assert.c:20: error: void value not ignored as it ought to be
...you'd expect the result of __builtin_constant_p()
to be regarded as a constant by definition! So I'm not sure that I would really trust this for real code...
(And I don't have any good ideas right now for pure_assert()
!)