Add _COGL_STATIC_ASSERT macro

This adds a _COGL_STATIC_ASSERT macro that can be used for compile time
assertions in C code. If supported by the compiler this macro uses
_Static_assert so that a message can be printed out if the assertion
fails.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit 465b39a764f2720e77678cafa56acb0e69007ffd)
This commit is contained in:
Robert Bragg 2012-04-16 17:23:15 +01:00
parent eaf29af7ee
commit 097d282b32
5 changed files with 81 additions and 4 deletions

View File

@ -37,7 +37,10 @@
/* This code assumes that we can cast an unsigned long to a pointer
and back without losing any data */
G_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *));
_COGL_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *),
"This toolchain breaks Cogl's assumption that it can "
"safely cast an unsigned long to a pointer without "
"loosing data");
#define ARRAY_INDEX(bit_num) \
((bit_num) / (sizeof (unsigned long) * 8))

View File

@ -2590,8 +2590,13 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
layer_state_hash_functions[_index] =
_cogl_pipeline_layer_hash_fragment_snippets_state;
{
/* So we get a big error if we forget to update this code! */
g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 10);
_COGL_STATIC_ASSERT (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 10,
"Don't forget to install a hash function for new "
"pipeline state and update assert at end of "
"_cogl_pipeline_init_state_hash_functions");
}
}
static gboolean
@ -2697,8 +2702,13 @@ _cogl_pipeline_init_state_hash_functions (void)
state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] =
_cogl_pipeline_hash_fragment_snippets_state;
{
/* So we get a big error if we forget to update this code! */
g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 16);
_COGL_STATIC_ASSERT (COGL_PIPELINE_STATE_SPARSE_COUNT == 16,
"Make sure to install a hash function for "
"newly added pipeline state and update assert "
"in _cogl_pipeline_init_state_hash_functions");
}
}
unsigned int

View File

@ -34,6 +34,11 @@
#include <stdio.h>
#endif
/* Double check that config.h has been included */
#if !defined (GETTEXT_PACKAGE) && !defined (_COGL_IN_TEST_BITMASK)
#error "config.h must be included before including cogl-util.h"
#endif
/* When compiling with Visual Studio, symbols that represent data that
are exported out of the DLL need to be marked with the dllexport
attribute. */
@ -227,4 +232,50 @@ _cogl_util_pixel_format_from_masks (unsigned long r_mask,
int depth, int bpp,
int byte_order);
/* Since we can't rely on _Static_assert always being available for
* all compilers we have limited static assert that can be used in
* C code but not in headers.
*/
#define _COGL_TYPEDEF_ASSERT(EXPRESSION) \
typedef struct { char Compile_Time_Assertion[(EXPRESSION) ? 1 : -1]; } \
G_PASTE (_GStaticAssert_, __LINE__)
/* _COGL_STATIC_ASSERT:
* @expression: An expression to assert evaluates to true at compile
* time.
* @message: A message to print to the console if the assertion fails
* at compile time.
*
* Allows you to assert that an expression evaluates to true at
* compile time and aborts compilation if not. If possible message
* will also be printed if the assertion fails.
*
* Note: Only Gcc >= 4.6 supports the c11 _Static_assert which lets us
* print a nice message if the compile time assertion fails.
*
* Note: this assertion macro can only be used in C code where it is
* valid to use a typedef. This macro should not be used in headers
* because we can't guarantee a unique name for the typedef due to
* the name being based on the line number of the file it's used in.
*
* Although we can remove this limitation if the compiler supports
* _Static_assert we currently choose to maintain the limitation in
* any case to help ensure we don't accidentally create code that
* doesn't compile on some toolchains because we forgot about this
* limitation.
*/
#ifdef HAVE_STATIC_ASSERT
#define _COGL_STATIC_ASSERT(EXPRESSION, MESSAGE) \
_Static_assert (EXPRESSION, MESSAGE); \
_COGL_TYPEDEF_ASSERT(EXPRESSION)
#else
#define _COGL_STATIC_ASSERT(EXPRESSION, MESSAGE) \
_COGL_TYPEDEF_ASSERT(EXPRESSION)
/* So that we can safely use _Static_assert() if we want to add
* assertions to internal headers we define it to a NOP here
* if it's not supported by the compiler. */
#define _Static_assert(EXPRESSION, MESSAGE)
#endif
#endif /* __COGL_UTIL_H */

View File

@ -935,6 +935,19 @@ AM_PROG_CC_C_O
AC_ISC_POSIX
AC_C_CONST
dnl ============================================================
dnl Compiler features
dnl ============================================================
AC_TRY_COMPILE([],
[
_Static_assert (1, "");
int
main (int argc, char **argv)
{
return 0;
}
],
[AC_DEFINE([HAVE_STATIC_ASSERT], [1], [Whether _Static_assert can be used or not])])
dnl ================================================================
dnl Libtool stuff.

View File

@ -9,9 +9,9 @@
within Cogl. Cogl doesn't export the symbols for this data type so
we just directly include the source instead */
#define _COGL_IN_TEST_BITMASK
#include <cogl/cogl-bitmask.h>
#include <cogl/cogl-bitmask.c>
#define _COGL_IN_TEST_BITMASK
#include <cogl/cogl-util.c>
typedef struct