[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
proposed support for C1X-style static_assert
From: |
Paul Eggert |
Subject: |
proposed support for C1X-style static_assert |
Date: |
Thu, 05 May 2011 00:01:36 -0700 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Thunderbird/3.1.8 |
Here's a proposed refactoring of the guts of verify.h so that
it can be used to support C1X-style static_assert.
I prefer gnulib's 'verify (FOO)' to C1X's
'static_assert (FOO, "FOO didn't work")', but
it's also nice to support the standard syntax.
assert-h: new module, which supports C1X-style static_assert
* lib/assert.in.h, m4/assert_h.m4, modules/assert-h: New files.
* lib/verify.h: Revamp so that this can be copied into assert.h,
while retaining the ability to use it standalone as before.
Rename private identifiers so as not to encroach on the
standard C namespace, since this is now used by assert.h.
(_GL_VERIFY_TYPE): New macro, factoring out differing parts of
the old verify_true.
(_GL_VERIFY_TRUE): New macro, with much of the contents of
the old verify_true. Use _GL_VERIFY_TYPE.
(_GL_VERIFY): New macro, with much of the contents of the old verify.
(static_assert): New macro, if _GL_STATIC_ASSERT_H
is defined and static_assert is not; _GL_STATIC_ASSERT_H is
defined when this file is copied into the replacement assert.h.
(_Static_assert): New macro, if _GL_STATIC_ASSERT_H is defined
and _Static_assert is not built in.
(verify_true, verify): Define only if _GL_STATIC_ASSERT_H is not
defined, and use the new macros mentioned above.
diff --git a/lib/assert.in.h b/lib/assert.in.h
new file mode 100644
index 0000000..1857ceb
--- /dev/null
+++ b/lib/assert.in.h
@@ -0,0 +1,28 @@
+/* Substitute for and wrapper around <assert.h>
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Do not guard the include, since <assert.h> is supposed to define
+ the assert macro each time it is included. */
+
+#if __GNUC__ >= 3
address@hidden@
+#endif
address@hidden@
+
address@hidden@ @NEXT_ASSERT_H@
+
+/* The definition of static_assert is copied here. */
diff --git a/lib/verify.h b/lib/verify.h
index 6bca43f..39a5ffc 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -17,42 +17,37 @@
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
-#ifndef VERIFY_H
-# define VERIFY_H 1
+#ifndef _GL_VERIFY_H
+# define _GL_VERIFY_H
-/* Define HAVE__STATIC_ASSERT to 1 if _Static_assert works as per the
+
+/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per the
C1X draft N1548 section 6.7.10. 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 HAVE_STATIC_ASSERT to 1 if static_assert works as per the
- C1X draft N1548 section 7.2 or the C++0X draft N3242 section 7.(4).
+ Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per the
+ C++0X draft N3242 section 7.(4).
This will likely be supported by future GCC versions, in C++ mode.
- For now, use this only with GCC. Eventually whether _Static_assert
- and static_assert works should be determined by 'configure'. */
+ 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__ || (__GNUC__ == 4 && 6 <= __GNUC_MINOR__)) && !defined
__cplusplus
-# define HAVE__STATIC_ASSERT 1
+# define _GL_HAVE__STATIC_ASSERT 1
# endif
/* The condition (99 < __GNUC__) is temporary, until we know about the
first G++ release that supports static_assert. */
# if (99 < __GNUC__) && defined __cplusplus
-# define HAVE_STATIC_ASSERT 1
+# define _GL_HAVE_STATIC_ASSERT 1
# endif
/* Each of these macros verifies that its argument R is nonzero. To
be portable, R should be an integer constant expression. Unlike
assert (R), there is no run-time overhead.
- There are two macros, since no single macro can be used in all
- contexts in C. verify_true (R) is for scalar contexts, including
- integer constant expression contexts. verify (R) is for declaration
- contexts, e.g., the top level.
-
- Symbols ending in "__" are private to this header.
-
If _Static_assert works, verify (R) uses it directly. Similarly,
- verify_true (R) works by packaging a _Static_assert inside a struct
+ _GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
that is an operand of sizeof.
The code below uses several ideas for C++ compilers, and for C
@@ -64,7 +59,9 @@
constant and nonnegative.
* Next this expression W is wrapped in a type
- struct verify_type__ { unsigned int verify_error_if_negative_size__: W; }.
+ struct __gl_verify_type {
+ unsigned int __gl_verify_error_if_negative: W;
+ }.
If W is negative, this yields a compile-time error. No compiler can
deal with a bit-field of negative size.
@@ -78,7 +75,7 @@
void function (int n) { verify (n < 0); }
- * For the verify macro, the struct verify_type__ will need to
+ * For the verify macro, the struct __gl_verify_type will need to
somehow be embedded into a declaration. To be portable, this
declaration must declare an object, a constant, a function, or a
typedef name. If the declared entity uses the type directly,
@@ -116,11 +113,11 @@
Which of the following alternatives can be used?
extern int dummy [sizeof (struct {...})];
- extern int dummy [sizeof (struct verify_type__ {...})];
+ extern int dummy [sizeof (struct __gl_verify_type {...})];
extern void dummy (int [sizeof (struct {...})]);
- extern void dummy (int [sizeof (struct verify_type__ {...})]);
+ extern void dummy (int [sizeof (struct __gl_verify_type {...})]);
extern int (*dummy (void)) [sizeof (struct {...})];
- extern int (*dummy (void)) [sizeof (struct verify_type__ {...})];
+ extern int (*dummy (void)) [sizeof (struct __gl_verify_type {...})];
In the second and sixth case, the struct type is exported to the
outer scope; two such declarations therefore collide. GCC warns
@@ -159,44 +156,75 @@
possible. */
# define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
-/* Verify requirement R at compile-time, as an integer constant expression.
- Return 1. */
+/* 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. */
+
+# define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
+ (!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
# ifdef __cplusplus
template <int w>
- struct verify_type__ { unsigned int verify_error_if_negative_size__: w; };
-# define verify_true(R) \
- (!!sizeof (verify_type__<(R) ? 1 : -1>))
-# elif HAVE__STATIC_ASSERT
-# define verify_true(R) \
- (!!sizeof \
- (struct { \
- _Static_assert (R, "verify_true (" #R ")"); \
- int verify_dummy__; \
- }))
-# elif HAVE_STATIC_ASSERT
-# define verify_true(R) \
- (!!sizeof \
- (struct { \
- static_assert (R, "verify_true (" #R ")"); \
- int verify_dummy__; \
- }))
+ struct __gl_verify_type {
+ unsigned int __gl_verify_error_if_negative: w;
+ };
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ __gl_verify_type<(R) ? 1 : -1>
+# elif defined _GL_HAVE__STATIC_ASSERT
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ struct { \
+ _Static_assert (R, DIAGNOSTIC); \
+ int __gl_dummy; \
+ }
# else
-# define verify_true(R) \
- (!!sizeof \
- (struct { unsigned int verify_error_if_negative_size__: (R) ? 1 : -1; }))
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ struct { unsigned int __gl_verify_error_if_negative: (R) ? 1 : -1; }
# endif
/* Verify requirement R at compile-time, as a declaration without a
- trailing ';'. */
+ trailing ';'. If R is false, fail at compile-time, preferably
+ with a diagnostic that includes the string-literal DIAGNOSTIC.
+
+ Unfortunately, unlike C1X, this implementation must appear as an
+ ordinary declaration, and cannot appear inside struct { ... }. */
+
+# ifdef _GL_HAVE__STATIC_ASSERT
+# define _GL_VERIFY _Static_assert
+# else
+# define _GL_VERIFY(R, DIAGNOSTIC) \
+ extern int (*_GL_GENSYM (__gl_verify_function) (void)) \
+ [_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
+# endif
-# if HAVE__STATIC_ASSERT
-# define verify(R) _Static_assert (R, "verify (" #R ")")
-# elif HAVE_STATIC_ASSERT
-# define verify(R) static_assert (R, "verify (" #R ")")
+/* _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 _Static_assert /* Draft C1X requires this #define. */
+# ifndef _GL_HAVE__STATIC_ASSERT
+# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
+# endif
+# endif
# else
-# define verify(R) \
- extern int (* _GL_GENSYM (verify_function) (void)) [verify_true (R)]
+
+/* Each of these macros verifies that its argument R is nonzero. To
+ be portable, R should be an integer constant expression. Unlike
+ assert (R), there is no run-time overhead.
+
+ There are two macros, since no single macro can be used in all
+ contexts in C. verify_true (R) is for scalar contexts, including
+ integer constant expression contexts. verify (R) is for declaration
+ contexts, e.g., the top level. */
+
+/* Verify requirement R at compile-time, as an integer constant expression.
+ Return 1. */
+
+# define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
+
+/* Verify requirement R at compile-time, as a declaration without a
+ trailing ';'. */
+
+# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
+
# endif
#endif
diff --git a/m4/assert_h.m4 b/m4/assert_h.m4
new file mode 100644
index 0000000..30ca248
--- /dev/null
+++ b/m4/assert_h.m4
@@ -0,0 +1,29 @@
+# assert-h.m4
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_DEFUN([gl_ASSERT_H],
+[
+ ASSERT_H=
+ AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <assert.h>
+ static_assert (2 + 2 == 4, "arithmetic doesn't work");
+ ]],
+ [[
+ static_assert (sizeof (char) == 1, "sizeof doesn't work");
+ ]])],
+ [gl_cv_static_assert=yes],
+ [gl_cv_static_assert=no])])
+ if test $gl_cv_static_assert = no; then
+ ASSERT_H=assert.h
+ gl_NEXT_HEADERS([assert.h])
+ fi
+ AC_SUBST([ASSERT_H])
+ AM_CONDITIONAL([GL_GENERATE_ASSERT_H], [test -n "$ASSERT_H"])
+])
diff --git a/modules/assert-h b/modules/assert-h
new file mode 100644
index 0000000..eeda888
--- /dev/null
+++ b/modules/assert-h
@@ -0,0 +1,47 @@
+Description:
+An <assert.h> that conforms to C1X.
+
+Files:
+lib/assert.in.h
+lib/verify.h
+m4/assert_h.m4
+
+Depends-on:
+include_next
+
+configure.ac:
+gl_ASSERT_H
+
+Makefile.am:
+BUILT_SOURCES += $(ASSERT_H)
+
+# We need the following in order to create <assert.h> when the system
+# doesn't have one that works with the given compiler.
+if GL_GENERATE_ASSERT_H
+assert.h: assert.in.h verify.h $(top_builddir)/config.status
+ $(AM_V_GEN)rm -f address@hidden $@ && \
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
+ sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+ -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+ -e 's|@''NEXT_ASSERT_H''@|$(NEXT_ASSERT_H)|g' \
+ < $(srcdir)/assert.in.h && \
+ sed -e 's|__gl_verify|__gl_static_assert|g' \
+ -e 's|_GL_VERIFY|_GL_STATIC_ASSERT|g' \
+ < $(srcdir)/verify.h; \
+ } > address@hidden && \
+ mv address@hidden $@
+else
+assert.h: $(top_builddir)/config.status
+ rm -f $@
+endif
+MOSTLYCLEANFILES += assert.h assert.h-t
+
+Include:
+<assert.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Paul Eggert
- proposed support for C1X-style static_assert,
Paul Eggert <=
- Re: proposed support for C1X-style static_assert, Bruno Haible, 2011/05/05
- Re: proposed support for C1X-style static_assert, Paul Eggert, 2011/05/05
- Re: proposed support for C1X-style static_assert, Bruno Haible, 2011/05/05
- Re: proposed support for C1X-style static_assert, Paul Eggert, 2011/05/05
- Re: proposed support for C1X-style static_assert, Paul Eggert, 2011/05/06
- Re: proposed support for C1X-style static_assert, Bruno Haible, 2011/05/22
- Re: proposed support for C1X-style static_assert, Paul Eggert, 2011/05/22
- Re: proposed support for C1X-style static_assert, Bruno Haible, 2011/05/29