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

assert-h: static_assert is a keyword in C23

* m4/assert_h.m4 (gl_ASSERT_H): Also test for static_assert
keyword a la C23, and define HAVE_C_STATIC_ASSERT if so.
If not, arrange for config.h to #define static_assert
by including <assert.h>, and then do "#undef assert"
so that the assert macro still needs an explicit include.
This should be safe even on very old hosts, as assert.h
has been re-includable for decades.
* tests/tests-assert.c: New test.
* modules/assert-h-tests (Files, Makefile.am): Add it.
This commit is contained in:
Paul Eggert
2022-09-13 17:29:35 -05:00
parent c34d193387
commit c504bec035
7 changed files with 171 additions and 27 deletions

View File

@@ -7,6 +7,17 @@
2022-09-13 Paul Eggert <eggert@cs.ucla.edu>
assert-h: static_assert is a keyword in C23
* m4/assert_h.m4 (gl_ASSERT_H): Also test for static_assert
keyword a la C23, and define HAVE_C_STATIC_ASSERT if so.
If not, arrange for config.h to #define static_assert
by including <assert.h>, and then do "#undef assert"
so that the assert macro still needs an explicit include.
This should be safe even on very old hosts, as assert.h
has been re-includable for decades.
* tests/tests-assert.c: New test.
* modules/assert-h-tests (Files, Makefile.am): Add it.
stdalign-tests: port to C23
* tests/test-stdalign.c: Do not test __alignas_is_defined,
_Alignof, or _Alignas as they are obsolescent.

View File

@@ -866,6 +866,7 @@ substituted by Gnulib.
@menu
* bool:: @code{bool}, @code{false}, and @code{true}
* static_assert:: @code{static_assert}
@end menu
@node bool
@@ -889,6 +890,30 @@ On pre-C23 platforms, the keyword substitutes are macros.
On pre-C23 platforms, the keyword substitutes assume C99 or later.
@end itemize
@node static_assert
@section @code{static_assert}
Gnulib module: assert-h
The @code{assert-h} module arranges for both @code{static_assert} and
@code{<assert.h>} to be like standard C@. @xref{assert.h}.
Portability problems fixed by Gnulib:
@itemize
@item
Pre-C11 platforms lack @code{static_assert}.
@item
On pre-C23 platforms, @code{<assert.h>} must be included before
using @code{static_assert}.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item
On pre-C23 platforms, @code{static_assert} is a macro.
@end itemize
@node Header File Substitutes
@chapter ISO C and POSIX Header File Substitutes

View File

@@ -10,28 +10,37 @@ See also the Gnulib modules @code{assert} and @code{verify}.
Portability problems fixed by Gnulib:
@itemize
@item
On older platforms @code{static_assert} and @code{_Static_assert} do
not allow the second string-literal argument to be omitted. For
example, GCC versions before 9.1 do not support the single-argument
@code{static_assert} that was standardized by C2x and C++17.
On older C platforms @code{<assert.h>} must be included before using
@code{static_assert}. For example, GCC versions before 13 do not
support the @code{static_assert} keyword that was standardized by C23.
@item
Even-older platforms do not support @code{static_assert} or
@code{_Static_assert} at all. For example, GCC versions before 4.6 do
not support @code{_Static_assert}, and G++ versions before 4.3 do not
support @code{static_assert}, which was standardized by C11 and C++11.
On older platforms @code{static_assert} does not allow the second
string-literal argument to be omitted. For example, GCC versions
before 9.1 do not support the single-argument @code{static_assert}
that was standardized by C23 and C++17.
@item
Even-older platforms do not support @code{static_assert} at all.
For example, GCC versions before 4.6 and G++ versions before 4.3
do not support the two-argument form, which was standardized
by C11 and C++11.
@item
Older C platforms might not support the obsolescent
@code{_Static_assert} keyword or macro.
This portability problem should not matter with code using this
module, as such code should use @code{static_assert} instead.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item
C @code{_Static_assert} and C++ @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 C @code{static_assert} and @code{_Static_assert} can also
A @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.
Gnulib substitute can be used only as an ordinary declaration
in code intended to be portable to C99 or earlier.
@item
In C23 and C++11 and later, @code{static_assert} is a keyword.
In C11 and C17 it is a macro. Any Gnulib substitute is also a macro.
@item
In C99 and later, @code{assert} can be applied to any scalar expression.
In C89, the argument to @code{assert} is of type @code{int}.

View File

@@ -8,22 +8,47 @@ dnl From Paul Eggert.
AC_DEFUN([gl_ASSERT_H],
[
GL_GENERATE_ASSERT_H=false
AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert],
[AC_COMPILE_IFELSE(
[gl_save_CFLAGS=$CFLAGS
for gl_working in "yes, a keyword" "yes, an <assert.h> macro"; do
AS_CASE([$gl_working],
[*assert.h*], [CFLAGS="$gl_save_CFLAGS -DINCLUDE_ASSERT_H"])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <assert.h>
static_assert (2 + 2 == 4, "arithmetic doesn't work");
[[#ifdef INCLUDE_ASSERT_H
#include <assert.h>
#endif
static_assert (2 + 2 == 4, "arithmetic does not work");
static_assert (2 + 2 == 4);
]],
[[
static_assert (sizeof (char) == 1, "sizeof doesn't work");
static_assert (sizeof (char) == 1, "sizeof does not work");
static_assert (sizeof (char) == 1);
]])],
[gl_cv_static_assert=yes],
[gl_cv_static_assert=no])])
if test $gl_cv_static_assert = no; then
GL_GENERATE_ASSERT_H=true
gl_NEXT_HEADERS([assert.h])
fi
[gl_cv_static_assert=$gl_working],
[gl_cv_static_assert=no])
CFLAGS=$gl_save_CFLAGS
test "$gl_cv_static_assert" != no && break
done])
GL_GENERATE_ASSERT_H=false
AS_CASE([$gl_cv_static_assert],
[yes*keyword*],
[AC_DEFINE([HAVE_C_STATIC_ASSERT], [1],
[Define to 1 if the static_assert keyword works.])],
[no],
[GL_GENERATE_ASSERT_H=true
gl_NEXT_HEADERS([assert.h])])
dnl The "zz" puts this toward config.h's end, to avoid potential
dnl collisions with other definitions. #undef assert so that
dnl programs are not tempted to use it without specifically
dnl including assert.h. Break the #undef apart with a comment
dnl so that 'configure' does not comment it out.
AH_VERBATIM([zzstatic_assert],
[#if !defined HAVE_C_STATIC_ASSERT && __cpp_static_assert < 201411
#include <assert.h>
#undef/**/assert
#endif])
])

View File

@@ -1,5 +1,5 @@
Description:
An <assert.h> that conforms to C11.
An <assert.h> and static_assert that are like C23.
Files:
lib/assert.in.h

View File

@@ -1,7 +1,10 @@
Files:
tests/test-assert.c
Depends-on:
configure.ac:
Makefile.am:
TESTS += test-assert
check_PROGRAMS += test-assert

71
tests/test-assert.c Normal file
View File

@@ -0,0 +1,71 @@
/* Test assert.h and static_assert.
Copyright 2022 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 of the License, 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, see <https://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
#include <config.h>
#define STATIC_ASSERT_TESTS \
static_assert (2 + 2 == 4, "arithmetic does not work"); \
static_assert (2 + 2 == 4); \
static_assert (sizeof (char) == 1, "sizeof does not work"); \
static_assert (sizeof (char) == 1)
STATIC_ASSERT_TESTS;
static char const *
assert (char const *p, int i)
{
return p + i;
}
static char const *
f (char const *p)
{
return assert (p, 0);
}
#include <assert.h>
STATIC_ASSERT_TESTS;
static int
g (void)
{
assert (f ("this should work"));
return 0;
}
#define NDEBUG 1
#include <assert.h>
STATIC_ASSERT_TESTS;
static int
h (void)
{
assert (f ("this should work"));
return 0;
}
int
main (void)
{
STATIC_ASSERT_TESTS;
g ();
h ();
return 0;
}