summaryrefslogtreecommitdiff
path: root/lib/verify.h
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-05-09 08:57:56 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2019-05-09 09:09:34 -0700
commit89a5b4b828b962361be83904b5914ec4bb3408ec (patch)
tree304f84c52ca8a1e948532e0f3377e08e235d8431 /lib/verify.h
parentb8068cf09b6c78e35cef072efc7613049c11a632 (diff)
downloadgnulib-89a5b4b828b962361be83904b5914ec4bb3408ec.tar.gz
Support C2X and C++17 static_assert
C2X and C++17 finally added support for a simple, single-argument ‘static_assert’ that implements what the Gnulib ‘verify’ macro was doing back in 2005. Implement static_assert on older platforms. The only remaining advantage of ‘verify’ is a shorter name. * doc/posix-headers/assert.texi (assert.h): * doc/verify.texi (Compile-time Assertions): Modernize for C2X and C++17. * lib/verify.h (_GL_HAVE__STATIC_ASSERT1, _GL_HAVE_STATIC_ASSERT1): New macros. (_GL_HAVE__STATIC_ASSERT): Remove. (_GL_HAVE__STATIC_ASSERT): Rely more heavily on __STDC_VERSION__. (_GL_VERIFY_TRUE, _GL_VERIFY_TYPE): Remove 2nd arg, the diagnostic string. All callers changed. (_GL_VERIFY): Require 3 or more args, of which only the first 2 are used. All callers changed. (_Static_assert): Allow either 1 or 2 args, and define if !_GL_HAVE__STATIC_ASSERT1 instead of defining if !_GL_HAVE__STATIC_ASSERT. (static_assert): Define if !_GL_HAVE_STATIC_ASSERT1 instead of defining if !_GL_HAVE_STATIC_ASSERT. (verify_expr, verify): Don’t bother trying to copy the expression into the diagnostic, since 1-argument static_assert doesn’t. (verify): Prefer 1-argument _Static_assert if it works. * m4/assert_h.m4 (gl_ASSERT_H): Check for 1-argument static_assert.
Diffstat (limited to 'lib/verify.h')
-rw-r--r--lib/verify.h97
1 files changed, 53 insertions, 44 deletions
diff --git a/lib/verify.h b/lib/verify.h
index eccd7e2019..d7e15bc8a3 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -21,23 +21,31 @@
#define _GL_VERIFY_H
-/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per C11.
- This is supported by GCC 4.6.0 and later, in C mode, and its use
- here generates easier-to-read diagnostics when verify (R) fails.
-
- Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per C++11.
- This is supported by GCC 6.1.0 and later, in C++ mode.
-
- Use this only with GCC. If we were willing to slow 'configure'
- down we could also use it with other compilers, but since this
- affects only the quality of diagnostics, why bother? */
-#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
- && (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
- && !defined __cplusplus)
-# define _GL_HAVE__STATIC_ASSERT 1
-#endif
-#if 6 <= __GNUC__ && defined __cplusplus
-# define _GL_HAVE_STATIC_ASSERT 1
+/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert (R, DIAGNOSTIC)
+ works as per C11. This is supported by GCC 4.6.0 and later, in C
+ mode.
+
+ Define _GL_HAVE__STATIC_ASSERT1 to 1 if _Static_assert (R) works as
+ per C2X, and define _GL_HAVE_STATIC_ASSERT1 if static_assert (R)
+ works as per C++17. This is supported by GCC 9.1 and later.
+
+ Support compilers claiming conformance to the relevant standard,
+ and also support GCC when not pedantic. If we were willing to slow
+ 'configure' down we could also use it with other compilers, but
+ since this affects only the quality of diagnostics, why bother? */
+#ifndef __cplusplus
+# if (201112L <= __STDC_VERSION__ \
+ || (!defined __STRICT_ANSI__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)))
+# define _GL_HAVE__STATIC_ASSERT 1
+# endif
+# if (202000L <= __STDC_VERSION__ \
+ || (!defined __STRICT_ANSI__ && 9 <= __GNUC__))
+# define _GL_HAVE__STATIC_ASSERT1 1
+# endif
+#else
+# if 201703L <= __cplusplus || 9 <= __GNUC__
+# define _GL_HAVE_STATIC_ASSERT1 1
+# endif
#endif
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
@@ -167,11 +175,9 @@
#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
/* Verify requirement R at compile-time, as an integer constant expression
- that returns 1. If R is false, fail at compile-time, preferably
- with a diagnostic that includes the string-literal DIAGNOSTIC. */
+ that returns 1. If R is false, fail at compile-time. */
-#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
- (!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
+#define _GL_VERIFY_TRUE(R) (!!sizeof (_GL_VERIFY_TYPE (R)))
#ifdef __cplusplus
# if !GNULIB_defined_struct__gl_verify_type
@@ -181,40 +187,43 @@ template <int w>
};
# define GNULIB_defined_struct__gl_verify_type 1
# endif
-# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
- _gl_verify_type<(R) ? 1 : -1>
-#elif defined _GL_HAVE__STATIC_ASSERT
-# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+# define _GL_VERIFY_TYPE(R) _gl_verify_type<(R) ? 1 : -1>
+#elif defined _GL_HAVE__STATIC_ASSERT1
+# define _GL_VERIFY_TYPE(R) \
struct { \
- _Static_assert (R, DIAGNOSTIC); \
+ _Static_assert (R); \
int _gl_dummy; \
}
#else
-# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+# define _GL_VERIFY_TYPE(R) \
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
#endif
/* Verify requirement R at compile-time, as a declaration without a
- trailing ';'. If R is false, fail at compile-time, preferably
- with a diagnostic that includes the string-literal DIAGNOSTIC.
+ trailing ';'. If R is false, fail at compile-time.
+
+ This macro requires three or more arguments but uses at most the first
+ two, so that the _Static_assert macro optionally defined below supports
+ both the C11 two-argument syntax and the C2X one-argument syntax.
Unfortunately, unlike C11, this implementation must appear as an
ordinary declaration, and cannot appear inside struct { ... }. */
-#ifdef _GL_HAVE__STATIC_ASSERT
-# define _GL_VERIFY _Static_assert
+#if defined _GL_HAVE__STATIC_ASSERT
+# define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC)
#else
-# define _GL_VERIFY(R, DIAGNOSTIC) \
+# define _GL_VERIFY(R, DIAGNOSTIC, ...) \
extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
- [_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
+ [_GL_VERIFY_TRUE (R)]
#endif
/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
#ifdef _GL_STATIC_ASSERT_H
-# if !defined _GL_HAVE__STATIC_ASSERT && !defined _Static_assert
-# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
+# if !defined _GL_HAVE__STATIC_ASSERT1 && !defined _Static_assert
+# define _Static_assert(...) \
+ _GL_VERIFY (__VA_ARGS__, "static assertion failed", -)
# endif
-# if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
+# if !defined _GL_HAVE_STATIC_ASSERT1 && !defined static_assert
# define static_assert _Static_assert /* C11 requires this #define. */
# endif
#endif
@@ -235,22 +244,22 @@ template <int w>
verify_true is obsolescent; please use verify_expr instead. */
-#define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
+#define verify_true(R) _GL_VERIFY_TRUE (R)
/* Verify requirement R at compile-time. Return the value of the
expression E. */
-#define verify_expr(R, E) \
- (_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
+#define verify_expr(R, E) (_GL_VERIFY_TRUE (R) ? (E) : (E))
/* Verify requirement R at compile-time, as a declaration without a
- trailing ';'. */
+ trailing ';'. verify (R) acts like static_assert (R) except that
+ it is portable to C11/C++14 and earlier, and its name is shorter
+ and may be more convenient. */
-#ifdef __GNUC__
-# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
+#ifdef _GL_HAVE__STATIC_ASSERT1
+# define verify(R) _Static_assert (R)
#else
-/* PGI barfs if R is long. Play it safe. */
-# define verify(R) _GL_VERIFY (R, "verify (...)")
+# define verify(R) _GL_VERIFY (R, "verify (...)", -)
#endif
#ifndef __has_builtin