bug-gnulib
[Top][All Lists]
Advanced

[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



reply via email to

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