1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2025-08-08 17:22:05 +03:00

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.
This commit is contained in:
Paul Eggert
2011-05-05 22:43:18 -07:00
parent 864eeee51d
commit 8b401988f8
6 changed files with 225 additions and 52 deletions

View File

@@ -1,3 +1,25 @@
2011-05-05 Paul Eggert <eggert@cs.ucla.edu>
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 <bruno@clisp.org>
fclose, fflush: Respect rules for use of AC_LIBOBJ.

View File

@@ -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
@item
The draft C1X and C++0X @code{static_assert}, and the draft C1X
@code{_Static_assert}, 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
@item
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>}.
@item
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.
@item
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

28
lib/assert.in.h Normal file
View File

@@ -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
@PRAGMA_SYSTEM_HEADER@
#endif
@PRAGMA_COLUMNS@
#@INCLUDE_NEXT@ @NEXT_ASSERT_H@
/* The definition of static_assert is copied here. */

View File

@@ -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 ';'. 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
/* _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
/* 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 ';'. */
# if HAVE__STATIC_ASSERT
# define verify(R) _Static_assert (R, "verify (" #R ")")
# elif HAVE_STATIC_ASSERT
# define verify(R) static_assert (R, "verify (" #R ")")
# else
# define verify(R) \
extern int (* _GL_GENSYM (verify_function) (void)) [verify_true (R)]
# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
# endif
#endif

29
m4/assert_h.m4 Normal file
View File

@@ -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"])
])

47
modules/assert-h Normal file
View File

@@ -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 $@-t $@ && \
{ 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; \
} > $@-t && \
mv $@-t $@
else
assert.h: $(top_builddir)/config.status
rm -f $@
endif
MOSTLYCLEANFILES += assert.h assert.h-t
Include:
<assert.h>
License:
LGPLv2+
Maintainer:
Paul Eggert