]> Savannah Git Hosting - gnulib.git/commitdiff
assert-h: static_assert is a keyword in C23
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 13 Sep 2022 22:29:35 +0000 (17:29 -0500)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 13 Sep 2022 22:52:20 +0000 (17:52 -0500)
* 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.

ChangeLog
doc/gnulib.texi
doc/posix-headers/assert.texi
m4/assert_h.m4
modules/assert-h
modules/assert-h-tests
tests/test-assert.c [new file with mode: 0644]

index 31fb6837f4674a223e828e01f411a5d27bd02d66..bba1a1a4e4658b8c15fb4f9c4b5e20d4e67eaf1e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
index e9c2fd8fa6b1027ace540fdd695012a0dd52bb70..1bef2a0975ad7f1e4326a370c058593832a92321 100644 (file)
@@ -865,7 +865,8 @@ This chapter describes which keywords specified by ISO C are
 substituted by Gnulib.
 
 @menu
-* bool::  @code{bool}, @code{false}, and @code{true}
+* 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
 
index 3392a1691ad4224fb79c9564f4bb1f2b1f35ed08..f3d50533f9f46f1a6e6be81f356bb354bf2809d1 100644 (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}.
index 7af15a22877acc7f730a9e2fc9647999f7da81a2..36b3c78c91f1f28c43d84f4c62fca86c07e724d9 100644 (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])
 ])
index bf7565dc21ce666a930144946ba0143aae6652db..b67d44fe4aa8b1448e303091097a3dab65f2b4b2 100644 (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
index 19375f61c318f779cdbb2447d965c7436541a37b..670b06947cea66d8251711cf8f2726c7aaacdeb1 100644 (file)
@@ -1,7 +1,10 @@
 Files:
+tests/test-assert.c
 
 Depends-on:
 
 configure.ac:
 
 Makefile.am:
+TESTS += test-assert
+check_PROGRAMS += test-assert
diff --git a/tests/test-assert.c b/tests/test-assert.c
new file mode 100644 (file)
index 0000000..45b0c0f
--- /dev/null
@@ -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;
+}