bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PROPOSED 1/2] assert-h: static_assert is a keyword in C23


From: Paul Eggert
Subject: [PROPOSED 1/2] assert-h: static_assert is a keyword in C23
Date: Mon, 12 Sep 2022 22:32:17 -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                     | 13 +++++++
 doc/gnulib.texi               | 27 ++++++++++++-
 doc/posix-headers/assert.texi | 38 ++++++++++++-------
 m4/assert_h.m4                | 43 ++++++++++++++++-----
 modules/assert-h              |  2 +-
 modules/assert-h-tests        |  3 ++
 tests/test-assert.c           | 71 +++++++++++++++++++++++++++++++++++
 7 files changed, 172 insertions(+), 25 deletions(-)
 create mode 100644 tests/test-assert.c

diff --git a/ChangeLog b/ChangeLog
index d812e73f55..9e714143b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2022-09-12  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.
+
 2022-09-12  Bruno Haible  <bruno@clisp.org>
 
        supersede: Avoid a failure when writing to /dev/null in Solaris zones.
diff --git a/doc/gnulib.texi b/doc/gnulib.texi
index e9c2fd8fa6..1bef2a0975 100644
--- a/doc/gnulib.texi
+++ b/doc/gnulib.texi
@@ -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
 
diff --git a/doc/posix-headers/assert.texi b/doc/posix-headers/assert.texi
index 3392a1691a..5af0e8cb8f 100644
--- a/doc/posix-headers/assert.texi
+++ b/doc/posix-headers/assert.texi
@@ -10,28 +10,38 @@ 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 or the
+@code{static_assert} 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}.
diff --git a/m4/assert_h.m4 b/m4/assert_h.m4
index 7af15a2287..6300c859c7 100644
--- a/m4/assert_h.m4
+++ b/m4/assert_h.m4
@@ -12,18 +12,43 @@ AC_DEFUN([gl_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 (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="yes, a keyword"],
+       [AC_COMPILE_IFELSE(
+          [AC_LANG_PROGRAM(
+             [[#include <assert.h>
+               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);
+             ]])],
+          [gl_cv_static_assert="yes, an <assert.h> macro"],
+          [gl_cv_static_assert=no])])])
+
+  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])
 ])
diff --git a/modules/assert-h b/modules/assert-h
index bf7565dc21..b67d44fe4a 100644
--- a/modules/assert-h
+++ b/modules/assert-h
@@ -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
diff --git a/modules/assert-h-tests b/modules/assert-h-tests
index 19375f61c3..670b06947c 100644
--- a/modules/assert-h-tests
+++ b/modules/assert-h-tests
@@ -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
index 0000000000..45b0c0f457
--- /dev/null
+++ b/tests/test-assert.c
@@ -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;
+}
-- 
2.37.2




reply via email to

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