We build with -Werror by default so that any warning is treated as an error and aborts the build. The build system allows NO_WERROR=1 to be used to override this behaviour, in order to allow builds to succeed when spurious warnings occur (e.g. when using a newer compiler that includes checks for which the codebase is not yet prepared). Some versions of gcc (observed with gcc 4.8.5 in CentOS 7) will report spurious build_assert() failures: the compilation will fail due to an allegedly unelided call to the build assertion's external function declared with __attribute__((error)) even though the compiler does manage to successfully elide the call (as verified by the fact that there are no unresolvable symbol references in the compiler output). Change build_assert() to declare __attribute__((warning)) instead of __attribute__((error)) on its extern function. This will still abort a normal build if the assertion fails, but may be overridden using NO_WERROR=1 if necessary to work around a spurious assertion failure. Note that if the build assertion has genuinely failed (i.e. if the compiler has genuinely not been able to elide the call) then the object will still contain an unresolvable symbol reference that will cause the link to fail (which matches the behaviour of the old linker_assert() mechanism). Signed-off-by: Michael Brown <mcb30@ipxe.org>
87 lines
2.3 KiB
C
87 lines
2.3 KiB
C
#ifndef _ASSERT_H
|
|
#define _ASSERT_H
|
|
|
|
/** @file
|
|
*
|
|
* Assertions
|
|
*
|
|
* This file provides two assertion macros: assert() (for run-time
|
|
* assertions) and linker_assert() (for link-time assertions).
|
|
*
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
|
|
#ifndef ASSERTING
|
|
#ifdef NDEBUG
|
|
#define ASSERTING 0
|
|
#else
|
|
#define ASSERTING 1
|
|
#endif
|
|
#endif
|
|
|
|
extern unsigned int assertion_failures;
|
|
|
|
#define ASSERTED ( ASSERTING && ( assertion_failures != 0 ) )
|
|
|
|
/** printf() for assertions
|
|
*
|
|
* This function exists so that the assert() macro can expand to
|
|
* printf() calls without dragging the printf() prototype into scope.
|
|
*
|
|
* As far as the compiler is concerned, assert_printf() and printf() are
|
|
* completely unrelated calls; it's only at the assembly stage that
|
|
* references to the assert_printf symbol are collapsed into references
|
|
* to the printf symbol.
|
|
*/
|
|
extern int __attribute__ (( format ( printf, 1, 2 ) ))
|
|
assert_printf ( const char *fmt, ... ) asm ( "printf" );
|
|
|
|
/**
|
|
* Assert a condition at run-time.
|
|
*
|
|
* If the condition is not true, a debug message will be printed.
|
|
* Assertions only take effect in debug-enabled builds (see DBG()).
|
|
*
|
|
* @todo Make an assertion failure abort the program
|
|
*
|
|
*/
|
|
#define assert( condition ) \
|
|
do { \
|
|
if ( ASSERTING && ! (condition) ) { \
|
|
assertion_failures++; \
|
|
assert_printf ( "assert(%s) failed at %s line %d\n", \
|
|
#condition, __FILE__, __LINE__ ); \
|
|
} \
|
|
} while ( 0 )
|
|
|
|
/**
|
|
* Assert a condition at build time
|
|
*
|
|
* If the compiler cannot prove that the condition is true, the build
|
|
* will fail with an error message.
|
|
*/
|
|
#undef static_assert
|
|
#define static_assert(x) _Static_assert( x, #x )
|
|
|
|
/**
|
|
* Assert a condition at build time (after dead code elimination)
|
|
*
|
|
* If the compiler cannot prove that the condition is true, the build
|
|
* will fail with an error message.
|
|
*
|
|
* This macro is iPXE-specific. Do not use this macro in code
|
|
* intended to be portable.
|
|
*/
|
|
#define build_assert( condition ) \
|
|
do { \
|
|
if ( ! (condition) ) { \
|
|
extern void __attribute__ (( warning ( \
|
|
"build_assert(" #condition ") failed" \
|
|
) )) _C2 ( build_assert_, __LINE__ ) ( void ); \
|
|
_C2 ( build_assert_, __LINE__ ) (); \
|
|
} \
|
|
} while ( 0 )
|
|
|
|
#endif /* _ASSERT_H */
|