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 /* This code assumes that we can cast an unsigned long to a pointer
and back without losing any data */ 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) \ #define ARRAY_INDEX(bit_num) \
((bit_num) / (sizeof (unsigned long) * 8)) ((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] = layer_state_hash_functions[_index] =
_cogl_pipeline_layer_hash_fragment_snippets_state; _cogl_pipeline_layer_hash_fragment_snippets_state;
{
/* So we get a big error if we forget to update this code! */ /* 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 static gboolean
@ -2697,8 +2702,13 @@ _cogl_pipeline_init_state_hash_functions (void)
state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] = state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] =
_cogl_pipeline_hash_fragment_snippets_state; _cogl_pipeline_hash_fragment_snippets_state;
{
/* So we get a big error if we forget to update this code! */ /* 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 unsigned int

View File

@ -34,6 +34,11 @@
#include <stdio.h> #include <stdio.h>
#endif #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 /* When compiling with Visual Studio, symbols that represent data that
are exported out of the DLL need to be marked with the dllexport are exported out of the DLL need to be marked with the dllexport
attribute. */ attribute. */
@ -227,4 +232,50 @@ _cogl_util_pixel_format_from_masks (unsigned long r_mask,
int depth, int bpp, int depth, int bpp,
int byte_order); 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 */ #endif /* __COGL_UTIL_H */

View File

@ -935,6 +935,19 @@ AM_PROG_CC_C_O
AC_ISC_POSIX AC_ISC_POSIX
AC_C_CONST 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 ================================================================
dnl Libtool stuff. dnl Libtool stuff.

View File

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