Peeter Joot's (OLD) Blog.

Math, physics, perl, and programming obscurity.

A failed attempt trying to be too clever with static assertions.

Posted by peeterjoot on March 1, 2011

In our DB2 code we use the standard static assertions trick (at least until C++0x’s static_assert is available ubiquitously). That uses a typedef in a macro using an invalid size to get the compiler to barf nicely on the developer:

#define CTASSERT(cexpr) \
   { typedef char CTAssertFailed[(cexpr) ? 1 : -1]; }

We’ve got a whole slew of other runtime checking assertion macros for DB2 developers. It so happens that we sometimes have the compiler warning us that some of our runtime assertions can never be true. That’s not a functional problem, but when these are in headers, it can create a lot of noise, and we have a lot of code and a lot of headers and this noise really adds up.

I wanted to see if I could coerce the compiler into not being noisy when our runtime assertions could be evaluated statically. I thought I might be able to do this by using the GCC __builtin_constant_p() compiler intrinsic “function”, to get our assertion code to do compile time checking instead of runtime checking when the compiler knew the expression was constant.

It so happens that GCC intrinsics are now available on a number of the compilers we use (i.e. the intel compiler, the AIX IBM xlC compiler, and of course in g++ itself). Minus a boatload of ifdefs (are assertions enabled, does the compiler have the builtin feature, …) here’s what I cooked up:

#define AACTION0_R(expr, fatal) \
    ((expr) || \
       AssertFailed( #expr, __FILE__, __LINE__, NULL, fatal, NULL ))

#define CTASSERT_E(cexpr) \
   (sizeof(char[(cexpr) ? 1 : -1]))

#define AACTION0(expr, fatal)                                               \
      ((void)(                                                                   \
         __builtin_constant_p( expr ) ? CTASSERT_E( expr )                   \
                                      : AACTION0_R(expr, fatal)             \

#define Assert(expr) AACTION0(expr, true)

The problem is that this bit of what I thought was nice cleverness doesn’t work in all situations. I wouldn’t have realized this use of these macros hadn’t crashed one of the compilers that we build the product with, and when contacted, one of the compiler developers pointed out that this wouldn’t work on a number of compilers the way I wanted it to (including g++.)

Where it did work was exactly the places that our static assertion macros could be used. For example, in the fragment

Assert( true ) ;
Assert( false ) ;

I did get a compile time assertion failure on the second line as desired. However, in code like

inline void foo(const bool b)
   Assert( b ) ;

int main()
   foo(false) ;
   foo(true) ;

   return 0 ;

I didn’t get my assertions, neither the compile time versions, nor the runtime fallback (what I thought the compiler would call when it could not determine that I had a compile time constant). I would not mind so much if the runtime version happened more often since that is what currently occurs up front anyhow. However, what happens is that I do not get a compile error in this case, plus my runtime assertion fallback does not even get called. I tried alternate ways of doing the static assertions, like the boost uninstantiated template method, but I found with that, the compiler generated code for the static case, even when __builtin_constant_p() was false, so it promptly bombed when I wanted things to go to my fallback case.

I did really like this general idea and I wonder if it can be made to work? An even better question is whether or not somebody has already successfully made this work (at least on some platforms).


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: