Files
ipxe/src/include/assert.h
Michael Brown 0f5abd8b11 [libc] Allow build_assert() failures to be ignored via NO_WERROR=1
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>
2024-02-10 14:47:40 +00:00

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 */