summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2018-12-14 14:21:16 -0800
committerH. Peter Anvin (Intel) <hpa@zytor.com>2018-12-14 15:42:03 -0800
commitb7f24e7715d8fdca52fda7fb9df1b70d8d4bbc6b (patch)
tree15669a93ec7bc21743b0928d04b7861180082cb6
parentc3c6cea83804e7ba36b31d15ba25954ea3a5bdfd (diff)
downloadnasm-b7f24e7715d8fdca52fda7fb9df1b70d8d4bbc6b.tar.gz
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>
-rw-r--r--configure.ac3
-rw-r--r--include/compiler.h21
-rw-r--r--include/nasmlib.h62
-rw-r--r--output/codeview.c4
-rw-r--r--output/outbin.c2
5 files changed, 71 insertions, 21 deletions
diff --git a/configure.ac b/configure.ac
index 09272240..1e981d03 100644
--- a/configure.ac
+++ b/configure.ac
@@ -207,9 +207,10 @@ PA_HAVE_FUNC(_byteswap_ulong, (0))
PA_HAVE_FUNC(_byteswap_uint64, (0))
dnl
-dnl Check for __builtin_constant_p()
+dnl Some rather useful gcc extensions...
dnl
PA_HAVE_FUNC(__builtin_constant_p, (0))
+PA_HAVE_FUNC(__builtin_choose_expr, (0,1,2))
dnl
dnl Check for supported gcc attributes; some compilers (e.g. Sun CC)
diff --git a/include/compiler.h b/include/compiler.h
index 7beeb8fe..f0258a8b 100644
--- a/include/compiler.h
+++ b/include/compiler.h
@@ -359,6 +359,27 @@ size_t strnlen(const char *s, size_t maxlen);
#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:
*
* `va_copy'
diff --git a/include/nasmlib.h b/include/nasmlib.h
index 66fbebcf..14f4dc7f 100644
--- a/include/nasmlib.h
+++ b/include/nasmlib.h
@@ -114,33 +114,61 @@ void nasm_read(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
*/
#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__)
-# define nasm_static_assert(x) \
- if (!(x)) { \
- extern void __attribute__((error("assertion " #x " failed"))) \
- _nasm_static_fail(void); \
- _nasm_static_fail(); \
- }
+# define nasm_static_assert(x) \
+ do { \
+ if (!(x)) { \
+ extern void __attribute__((error("assertion " #x " failed"))) \
+ _nasm_static_fail(void); \
+ _nasm_static_fail(); \
+ } \
+ } while (0)
#else
/* See http://www.drdobbs.com/compile-time-assertions/184401873 */
# define nasm_static_assert(x) \
do { enum { _static_assert_failed = 1/(!!(x)) }; } while (0)
#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 */
const char *invalid_enum_str(int);
diff --git a/output/codeview.c b/output/codeview.c
index 6028fc74..03fee590 100644
--- a/output/codeview.c
+++ b/output/codeview.c
@@ -654,7 +654,7 @@ static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
else if (win32)
section_write16(sect, 0x0006); /* machine */
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); /* verFEMinor */
section_write16(sect, 0); /* verFEBuild */
@@ -711,7 +711,7 @@ static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
section_write8(sect, 0); /* FLAG */
break;
default:
- nasm_assert(!"unknown symbol type");
+ nasm_panic("unknown symbol type");
}
section_wbytes(sect, sym->name, strlen(sym->name) + 1);
diff --git a/output/outbin.c b/output/outbin.c
index 971b9cc0..5e0dbdbc 100644
--- a/output/outbin.c
+++ b/output/outbin.c
@@ -1507,7 +1507,7 @@ static void write_srecord(unsigned int len, unsigned int alen,
case 4:
break;
default:
- nasm_assert(0);
+ panic();
break;
}