mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-10-10 00:25:06 -04:00
nasm_assert(): try to run at compile time if possible
Try to make nasm_assert() do a static assert if the argument can be evaluated at compile time by any particular compiler. We also provide nasm_try_static_assert() which will assert a compile-time expression if and only if we can determine we have a constant at compile time *and* we know that the compiler has a way to handle it. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
@@ -207,9 +207,10 @@ PA_HAVE_FUNC(_byteswap_ulong, (0))
|
|||||||
PA_HAVE_FUNC(_byteswap_uint64, (0))
|
PA_HAVE_FUNC(_byteswap_uint64, (0))
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Check for __builtin_constant_p()
|
dnl Some rather useful gcc extensions...
|
||||||
dnl
|
dnl
|
||||||
PA_HAVE_FUNC(__builtin_constant_p, (0))
|
PA_HAVE_FUNC(__builtin_constant_p, (0))
|
||||||
|
PA_HAVE_FUNC(__builtin_choose_expr, (0,1,2))
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Check for supported gcc attributes; some compilers (e.g. Sun CC)
|
dnl Check for supported gcc attributes; some compilers (e.g. Sun CC)
|
||||||
|
@@ -358,6 +358,27 @@ size_t strnlen(const char *s, size_t maxlen);
|
|||||||
# define is_constant(x) false
|
# define is_constant(x) false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we can guarantee that a particular expression is constant, use it,
|
||||||
|
* otherwise use a different version.
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
# define not_pedantic_start \
|
||||||
|
_Pragma("GCC diagnostic push") \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
|
||||||
|
# define not_pedantic_end \
|
||||||
|
_Pragma("GCC diagnostic pop")
|
||||||
|
#else
|
||||||
|
# define not_pedantic_start
|
||||||
|
# define not_pedantic_end
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE___BUILTIN_CHOOSE_EXPR
|
||||||
|
# define if_constant(x,y) __builtin_choose_expr(is_constant(x),(x),(y))
|
||||||
|
#else
|
||||||
|
# define if_constant(x,y) (y)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The autoconf documentation states:
|
* The autoconf documentation states:
|
||||||
*
|
*
|
||||||
|
@@ -113,34 +113,62 @@ static inline size_t nasm_aprintf_size(void)
|
|||||||
void nasm_read(void *, size_t, FILE *);
|
void nasm_read(void *, size_t, FILE *);
|
||||||
void nasm_write(const void *, size_t, FILE *);
|
void nasm_write(const void *, size_t, FILE *);
|
||||||
|
|
||||||
/*
|
|
||||||
* NASM assert failure
|
|
||||||
*/
|
|
||||||
fatal_func nasm_assert_failed(const char *, int, const char *);
|
|
||||||
#define nasm_assert(x) \
|
|
||||||
do { \
|
|
||||||
if (unlikely(!(x))) \
|
|
||||||
nasm_assert_failed(__FILE__,__LINE__,#x); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NASM failure at build time if the argument is false
|
* NASM failure at build time if the argument is false
|
||||||
*/
|
*/
|
||||||
#ifdef static_assert
|
#ifdef static_assert
|
||||||
# define nasm_static_assert(x) static_assert(x, #x)
|
# define nasm_static_assert(x) static_assert((x), #x)
|
||||||
#elif defined(HAVE_FUNC_ATTRIBUTE_ERROR) && defined(__OPTIMIZE__)
|
#elif defined(HAVE_FUNC_ATTRIBUTE_ERROR) && defined(__OPTIMIZE__)
|
||||||
# define nasm_static_assert(x) \
|
# define nasm_static_assert(x) \
|
||||||
|
do { \
|
||||||
if (!(x)) { \
|
if (!(x)) { \
|
||||||
extern void __attribute__((error("assertion " #x " failed"))) \
|
extern void __attribute__((error("assertion " #x " failed"))) \
|
||||||
_nasm_static_fail(void); \
|
_nasm_static_fail(void); \
|
||||||
_nasm_static_fail(); \
|
_nasm_static_fail(); \
|
||||||
}
|
} \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
/* See http://www.drdobbs.com/compile-time-assertions/184401873 */
|
/* See http://www.drdobbs.com/compile-time-assertions/184401873 */
|
||||||
# define nasm_static_assert(x) \
|
# define nasm_static_assert(x) \
|
||||||
do { enum { _static_assert_failed = 1/(!!(x)) }; } while (0)
|
do { enum { _static_assert_failed = 1/(!!(x)) }; } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* conditional static assert, if we know it is possible to determine
|
||||||
|
* the assert value at compile time. Since if_constant triggers
|
||||||
|
* pedantic warnings on gcc, turn them off explicitly around this code.
|
||||||
|
*/
|
||||||
|
#ifdef static_assert
|
||||||
|
# define nasm_try_static_assert(x) \
|
||||||
|
do { \
|
||||||
|
not_pedantic_start \
|
||||||
|
static_assert(if_constant(x, true), #x); \
|
||||||
|
not_pedantic_end \
|
||||||
|
} while (0)
|
||||||
|
#elif defined(HAVE_FUNC_ATTRIBUTE_ERROR) && defined(__OPTIMIZE__)
|
||||||
|
# define nasm_try_static_assert(x) \
|
||||||
|
do { \
|
||||||
|
if (!if_constant(x, true)) { \
|
||||||
|
extern void __attribute__((error("assertion " #x " failed"))) \
|
||||||
|
_nasm_static_fail(void); \
|
||||||
|
_nasm_static_fail(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define nasm_try_static_assert(x) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NASM assert failure
|
||||||
|
*/
|
||||||
|
fatal_func nasm_assert_failed(const char *, int, const char *);
|
||||||
|
#define nasm_assert(x) \
|
||||||
|
do { \
|
||||||
|
nasm_try_static_assert(x); \
|
||||||
|
if (unlikely(!(x))) \
|
||||||
|
nasm_assert_failed(__FILE__,__LINE__,#x); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* Utility function to generate a string for an invalid enum */
|
/* Utility function to generate a string for an invalid enum */
|
||||||
const char *invalid_enum_str(int);
|
const char *invalid_enum_str(int);
|
||||||
|
|
||||||
|
@@ -654,7 +654,7 @@ static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
|
|||||||
else if (win32)
|
else if (win32)
|
||||||
section_write16(sect, 0x0006); /* machine */
|
section_write16(sect, 0x0006); /* machine */
|
||||||
else
|
else
|
||||||
nasm_assert(!"neither win32 nor win64 are set!");
|
nasm_panic("neither win32 nor win64 are set!");
|
||||||
section_write16(sect, 0); /* verFEMajor */
|
section_write16(sect, 0); /* verFEMajor */
|
||||||
section_write16(sect, 0); /* verFEMinor */
|
section_write16(sect, 0); /* verFEMinor */
|
||||||
section_write16(sect, 0); /* verFEBuild */
|
section_write16(sect, 0); /* verFEBuild */
|
||||||
@@ -711,7 +711,7 @@ static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
|
|||||||
section_write8(sect, 0); /* FLAG */
|
section_write8(sect, 0); /* FLAG */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nasm_assert(!"unknown symbol type");
|
nasm_panic("unknown symbol type");
|
||||||
}
|
}
|
||||||
|
|
||||||
section_wbytes(sect, sym->name, strlen(sym->name) + 1);
|
section_wbytes(sect, sym->name, strlen(sym->name) + 1);
|
||||||
|
@@ -1507,7 +1507,7 @@ static void write_srecord(unsigned int len, unsigned int alen,
|
|||||||
case 4:
|
case 4:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nasm_assert(0);
|
panic();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user