bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: proposed support for C1X-style static_assert


From: Paul Eggert
Subject: Re: proposed support for C1X-style static_assert
Date: Thu, 05 May 2011 22:47:07 -0700
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110424 Thunderbird/3.1.10

Here's what I pushed.  Thanks to Bruno and Eric for the reviews.

---
 ChangeLog                     |   22 +++++++
 doc/posix-headers/assert.texi |   21 ++++++-
 lib/assert.in.h               |   28 +++++++++
 lib/verify.h                  |  130 +++++++++++++++++++++++++----------------
 m4/assert_h.m4                |   29 +++++++++
 modules/assert-h              |   47 +++++++++++++++
 6 files changed, 225 insertions(+), 52 deletions(-)
 create mode 100644 lib/assert.in.h
 create mode 100644 m4/assert_h.m4
 create mode 100644 modules/assert-h

diff --git a/ChangeLog b/ChangeLog
index 3c60a4e..b57e17b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2011-05-05  Paul Eggert  <address@hidden>
+
+       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.
+       * doc/posix-headers/assert.texi: Document this.
+
 2011-05-05  Bruno Haible  <address@hidden>
 
        fclose, fflush: Respect rules for use of AC_LIBOBJ.
diff --git a/doc/posix-headers/assert.texi b/doc/posix-headers/assert.texi
index 02a1c3b..aa78ee7 100644
--- a/doc/posix-headers/assert.texi
+++ b/doc/posix-headers/assert.texi
@@ -3,12 +3,31 @@
 
 POSIX specification:@* 
@url{http://www.opengroup.org/onlinepubs/9699919799/basedefs/assert.h.html}
 
-Gnulib module: ---
+Gnulib module: assert-h
+
+See also the Gnulib module @code{assert}.
 
 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+The draft C1X and C++0X @code{static_assert}, and the draft C1X
address@hidden, are not supported by many platforms.
+For example, GCC versions before 4.6.0 do not support @code{_Static_assert},
+and G++ versions through at least 4.6.0 do not support @code{static_assert}.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
address@hidden
+Draft C1X @code{_Static_assert} and draft C++0X @code{static_assert}
+are keywords that can be used without including @code{<assert.h>}.
+The Gnulib substitutes are macros that require including @code{<assert.h>}.
address@hidden
+The draft C1X @code{static_assert} and @code{_Static_assert} can also
+be used within a @code{struct} or @code{union} specifier, in place of
+an ordinary declaration of a member of the struct or union.  The
+Gnulib substitute can be used only as an ordinary declaration.
address@hidden
+In C99, @code{assert} can be applied to any scalar expression.
+In C89, the argument to @code{assert} is of type @code{int}.
 @end itemize
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..e5065ff 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(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
+#  endif
+#  if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
+#   define static_assert _Static_assert /* Draft C1X requires this #define.  */
+#  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..50bd9f8
--- /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
-- 
1.7.4.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]