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:
22
ChangeLog
22
ChangeLog
@@ -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>
|
2011-05-05 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
fclose, fflush: Respect rules for use of AC_LIBOBJ.
|
fclose, fflush: Respect rules for use of AC_LIBOBJ.
|
||||||
|
@@ -3,12 +3,31 @@
|
|||||||
|
|
||||||
POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/basedefs/assert.h.html}
|
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:
|
Portability problems fixed by Gnulib:
|
||||||
@itemize
|
@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
|
@end itemize
|
||||||
|
|
||||||
Portability problems not fixed by Gnulib:
|
Portability problems not fixed by Gnulib:
|
||||||
@itemize
|
@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
|
@end itemize
|
||||||
|
28
lib/assert.in.h
Normal file
28
lib/assert.in.h
Normal 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. */
|
130
lib/verify.h
130
lib/verify.h
@@ -17,42 +17,37 @@
|
|||||||
|
|
||||||
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
||||||
|
|
||||||
#ifndef VERIFY_H
|
#ifndef _GL_VERIFY_H
|
||||||
# define VERIFY_H 1
|
# 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
|
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
|
later, in C mode, and its use here generates easier-to-read diagnostics
|
||||||
when verify (R) fails.
|
when verify (R) fails.
|
||||||
|
|
||||||
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 7.2 or the C++0X draft N3242 section 7.(4).
|
C++0X draft N3242 section 7.(4).
|
||||||
This will likely be supported by future GCC versions, in C++ mode.
|
This will likely be supported by future GCC versions, in C++ mode.
|
||||||
|
|
||||||
For now, use this only with GCC. Eventually whether _Static_assert
|
Use this only with GCC. If we were willing to slow 'configure'
|
||||||
and static_assert works should be determined by '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
|
# if (4 < __GNUC__ || (__GNUC__ == 4 && 6 <= __GNUC_MINOR__)) && !defined __cplusplus
|
||||||
# define HAVE__STATIC_ASSERT 1
|
# define _GL_HAVE__STATIC_ASSERT 1
|
||||||
# endif
|
# endif
|
||||||
/* The condition (99 < __GNUC__) is temporary, until we know about the
|
/* The condition (99 < __GNUC__) is temporary, until we know about the
|
||||||
first G++ release that supports static_assert. */
|
first G++ release that supports static_assert. */
|
||||||
# if (99 < __GNUC__) && defined __cplusplus
|
# if (99 < __GNUC__) && defined __cplusplus
|
||||||
# define HAVE_STATIC_ASSERT 1
|
# define _GL_HAVE_STATIC_ASSERT 1
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Each of these macros verifies that its argument R is nonzero. To
|
/* Each of these macros verifies that its argument R is nonzero. To
|
||||||
be portable, R should be an integer constant expression. Unlike
|
be portable, R should be an integer constant expression. Unlike
|
||||||
assert (R), there is no run-time overhead.
|
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,
|
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.
|
that is an operand of sizeof.
|
||||||
|
|
||||||
The code below uses several ideas for C++ compilers, and for C
|
The code below uses several ideas for C++ compilers, and for C
|
||||||
@@ -64,7 +59,9 @@
|
|||||||
constant and nonnegative.
|
constant and nonnegative.
|
||||||
|
|
||||||
* Next this expression W is wrapped in a type
|
* 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
|
If W is negative, this yields a compile-time error. No compiler can
|
||||||
deal with a bit-field of negative size.
|
deal with a bit-field of negative size.
|
||||||
|
|
||||||
@@ -78,7 +75,7 @@
|
|||||||
|
|
||||||
void function (int n) { verify (n < 0); }
|
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
|
somehow be embedded into a declaration. To be portable, this
|
||||||
declaration must declare an object, a constant, a function, or a
|
declaration must declare an object, a constant, a function, or a
|
||||||
typedef name. If the declared entity uses the type directly,
|
typedef name. If the declared entity uses the type directly,
|
||||||
@@ -116,11 +113,11 @@
|
|||||||
Which of the following alternatives can be used?
|
Which of the following alternatives can be used?
|
||||||
|
|
||||||
extern int dummy [sizeof (struct {...})];
|
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 {...})]);
|
||||||
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 {...})];
|
||||||
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
|
In the second and sixth case, the struct type is exported to the
|
||||||
outer scope; two such declarations therefore collide. GCC warns
|
outer scope; two such declarations therefore collide. GCC warns
|
||||||
@@ -159,44 +156,75 @@
|
|||||||
possible. */
|
possible. */
|
||||||
# define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
|
# define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
|
||||||
|
|
||||||
/* Verify requirement R at compile-time, as an integer constant expression.
|
/* Verify requirement R at compile-time, as an integer constant expression
|
||||||
Return 1. */
|
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
|
# ifdef __cplusplus
|
||||||
template <int w>
|
template <int w>
|
||||||
struct verify_type__ { unsigned int verify_error_if_negative_size__: w; };
|
struct _gl_verify_type {
|
||||||
# define verify_true(R) \
|
unsigned int _gl_verify_error_if_negative: w;
|
||||||
(!!sizeof (verify_type__<(R) ? 1 : -1>))
|
};
|
||||||
# elif HAVE__STATIC_ASSERT
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
# define verify_true(R) \
|
_gl_verify_type<(R) ? 1 : -1>
|
||||||
(!!sizeof \
|
# elif defined _GL_HAVE__STATIC_ASSERT
|
||||||
(struct { \
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
_Static_assert (R, "verify_true (" #R ")"); \
|
struct { \
|
||||||
int verify_dummy__; \
|
_Static_assert (R, DIAGNOSTIC); \
|
||||||
}))
|
int _gl_dummy; \
|
||||||
# elif HAVE_STATIC_ASSERT
|
}
|
||||||
# define verify_true(R) \
|
|
||||||
(!!sizeof \
|
|
||||||
(struct { \
|
|
||||||
static_assert (R, "verify_true (" #R ")"); \
|
|
||||||
int verify_dummy__; \
|
|
||||||
}))
|
|
||||||
# else
|
# else
|
||||||
# define verify_true(R) \
|
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||||
(!!sizeof \
|
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
|
||||||
(struct { unsigned int verify_error_if_negative_size__: (R) ? 1 : -1; }))
|
|
||||||
# endif
|
# 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
|
/* Verify requirement R at compile-time, as a declaration without a
|
||||||
trailing ';'. */
|
trailing ';'. */
|
||||||
|
|
||||||
# if HAVE__STATIC_ASSERT
|
# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
|
||||||
# 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)]
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
29
m4/assert_h.m4
Normal file
29
m4/assert_h.m4
Normal 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
47
modules/assert-h
Normal 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
|
Reference in New Issue
Block a user