diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-05-09 08:57:56 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-05-09 09:09:34 -0700 |
commit | 89a5b4b828b962361be83904b5914ec4bb3408ec (patch) | |
tree | 304f84c52ca8a1e948532e0f3377e08e235d8431 /lib/verify.h | |
parent | b8068cf09b6c78e35cef072efc7613049c11a632 (diff) | |
download | gnulib-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.h | 97 |
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 |