]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
stddef-h: Make 'unreachable' usable in C++ mode.
authorBruno Haible <bruno@clisp.org>
Tue, 27 May 2025 23:59:05 +0000 (01:59 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 27 May 2025 23:59:05 +0000 (01:59 +0200)
Reported by Pierre Ossman <ossman@cendio.se>
at <https://savannah.gnu.org/bugs/?67152>.

* m4/stddef_h.m4 (gl_STDDEF_H): Also test whether unreachable is defined
by <stddef.h> in C++ mode.
* lib/stddef.in.h: In C++ mode, include <utility> and either import
'unreachable' from the std namespace or define it as an inline function.
* tests/test-stddef-h.c: Disable some tests in C++ mode.
* tests/test-stddef-h-c++.cc: Perform nearly the same tests in C++ mode
as in C mode.
* tests/test-stddef-h-c++2.cc: Rename some variables. Disable the NULL
test with clang on Windows.
* tests/test-stddef-h-c++3.cc: New file.
* modules/stddef-h-c++-tests (Files): Include it.
(Makefile.am): Link test-stddef-h-c++ with test-stddef-h-c++3.o.

ChangeLog
lib/stddef.in.h
m4/stddef_h.m4
modules/stddef-h-c++-tests
tests/test-stddef-h-c++.cc
tests/test-stddef-h-c++2.cc
tests/test-stddef-h-c++3.cc [new file with mode: 0644]
tests/test-stddef-h.c

index efcb2533210ae410ed680eec1ccea03ab83eb02e..d14ec6f7179d2c9f457f48831416e10fde0bf869 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2025-05-27  Bruno Haible  <bruno@clisp.org>
+
+       stddef-h: Make 'unreachable' usable in C++ mode.
+       Reported by Pierre Ossman <ossman@cendio.se>
+       at <https://savannah.gnu.org/bugs/?67152>.
+       * m4/stddef_h.m4 (gl_STDDEF_H): Also test whether unreachable is defined
+       by <stddef.h> in C++ mode.
+       * lib/stddef.in.h: In C++ mode, include <utility> and either import
+       'unreachable' from the std namespace or define it as an inline function.
+       * tests/test-stddef-h.c: Disable some tests in C++ mode.
+       * tests/test-stddef-h-c++.cc: Perform nearly the same tests in C++ mode
+       as in C mode.
+       * tests/test-stddef-h-c++2.cc: Rename some variables. Disable the NULL
+       test with clang on Windows.
+       * tests/test-stddef-h-c++3.cc: New file.
+       * modules/stddef-h-c++-tests (Files): Include it.
+       (Makefile.am): Link test-stddef-h-c++ with test-stddef-h-c++3.o.
+
 2025-05-27  Bruno Haible  <bruno@clisp.org>
 
        strchrnul: Fix for users of the current macOS SDK.
index dc689b8df80646b83d27c0671639fc560a995652..2754e881e7fd0ac6298dc988ac8bbf752c747f5e 100644 (file)
@@ -188,38 +188,66 @@ typedef union
 #endif
 
 /* ISO C 23 ยง 7.21.1 The unreachable macro  */
-#ifndef unreachable
 
 /* Code borrowed from verify.h.  */
-# ifndef _GL_HAS_BUILTIN_UNREACHABLE
-#  if defined __clang_major__ && __clang_major__ < 5
-#   define _GL_HAS_BUILTIN_UNREACHABLE 0
-#  elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
-#   define _GL_HAS_BUILTIN_UNREACHABLE 1
-#  elif defined __has_builtin
-#   define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
-#  else
-#   define _GL_HAS_BUILTIN_UNREACHABLE 0
-#  endif
+#ifndef _GL_HAS_BUILTIN_UNREACHABLE
+# if defined __clang_major__ && __clang_major__ < 5
+#  define _GL_HAS_BUILTIN_UNREACHABLE 0
+# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
+#  define _GL_HAS_BUILTIN_UNREACHABLE 1
+# elif defined __has_builtin
+#  define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
+# else
+#  define _GL_HAS_BUILTIN_UNREACHABLE 0
 # endif
+#endif
 
-# if _GL_HAS_BUILTIN_UNREACHABLE
-#  define unreachable() __builtin_unreachable ()
-# elif 1200 <= _MSC_VER
-#  define unreachable() __assume (0)
-# else
+#if _GL_HAS_BUILTIN_UNREACHABLE
+# define _gl_unreachable() __builtin_unreachable ()
+#elif 1200 <= _MSC_VER
+# define _gl_unreachable() __assume (0)
+#else
 /* Declare abort(), without including <stdlib.h>.  */
 extern
-#  if defined __cplusplus
+# if defined __cplusplus
 "C"
-#  endif
+# endif
 _Noreturn
 void abort (void)
-#  if defined __cplusplus && (__GLIBC__ >= 2)
+# if defined __cplusplus && (__GLIBC__ >= 2)
 _GL_ATTRIBUTE_NOTHROW
-#  endif
+# endif
 ;
-#  define unreachable() abort ()
+# define _gl_unreachable() abort ()
+#endif
+
+#ifndef __cplusplus
+/* In C, define unreachable as a macro.  */
+
+# ifndef unreachable
+#  define unreachable() _gl_unreachable ()
+# endif
+
+#else
+/* In C++, define unreachable as an inline function.  */
+
+/* With some versions of MSVC, the inclusion of <utility> here causes errors
+   when <cstddef> gets included:
+   type_traits(1164): error C2065: 'max_align_t': undeclared identifier  */
+# if !defined _MSC_VER
+extern "C++" { /* needed for Cygwin */
+#  include <utility>
+}
+# endif
+
+# if defined __cpp_lib_unreachable /* C++23 or newer */
+
+using std::unreachable;
+
+# else
+
+inline void unreachable () { _gl_unreachable (); }
+
 # endif
 
 #endif
index 3bc8cd85fea38da8958083e37eacfd4b476db5e4..bdcb428017829970cd6817209aeda46e19042214 100644 (file)
@@ -1,5 +1,5 @@
 # stddef_h.m4
-# serial 21
+# serial 22
 dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -64,20 +64,45 @@ AC_DEFUN_ONCE([gl_STDDEF_H],
     GL_GENERATE_STDDEF_H=true
   fi
 
-  AC_CACHE_CHECK([for unreachable],
-    [gl_cv_func_unreachable],
+  AC_CACHE_CHECK([for unreachable in C],
+    [gl_cv_c_func_unreachable],
     [AC_LINK_IFELSE(
        [AC_LANG_PROGRAM(
           [[#include <stddef.h>
           ]],
           [[unreachable ();
           ]])],
-       [gl_cv_func_unreachable=yes],
-       [gl_cv_func_unreachable=no])
+       [gl_cv_c_func_unreachable=yes],
+       [gl_cv_c_func_unreachable=no])
     ])
-  if test $gl_cv_func_unreachable = no; then
+  if test $gl_cv_c_func_unreachable = no; then
     GL_GENERATE_STDDEF_H=true
   fi
+  if test "$CXX" != no; then
+    dnl C++ <utility> has std::unreachable,
+    dnl see <https://en.cppreference.com/w/cpp/utility/unreachable>,
+    dnl but we want an unreachable() that is available from <stddef.h>,
+    dnl like in ISO C 23.
+    AC_CACHE_CHECK([for unreachable in <stddef.h> in C++],
+      [gl_cv_cxx_func_unreachable],
+      [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
+       dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
+       cat > conftest.cpp <<\EOF
+#include <stddef.h>
+int main (void) { unreachable (); }
+EOF
+       gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
+       if AC_TRY_EVAL([gl_command]); then
+         gl_cv_cxx_func_unreachable=yes
+       else
+         gl_cv_cxx_func_unreachable=no
+       fi
+       rm -fr conftest*
+      ])
+    if test $gl_cv_cxx_func_unreachable = no; then
+      GL_GENERATE_STDDEF_H=true
+    fi
+  fi
 
   dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114869
   AC_CACHE_CHECK([whether nullptr_t needs <stddef.h>],
index b46418837afe08a10b66860a5d14abc1f8b02ce3..4067a13cfb2d5ddade15c26b180b1c8f00dedc65 100644 (file)
@@ -1,6 +1,7 @@
 Files:
 tests/test-stddef-h-c++.cc
 tests/test-stddef-h-c++2.cc
+tests/test-stddef-h-c++3.cc
 
 Status:
 c++-test
@@ -14,5 +15,5 @@ Makefile.am:
 if ANSICXX
 TESTS += test-stddef-h-c++
 check_PROGRAMS += test-stddef-h-c++
-test_stddef_h_c___SOURCES = test-stddef-h-c++.cc test-stddef-h-c++2.cc
+test_stddef_h_c___SOURCES = test-stddef-h-c++.cc test-stddef-h-c++2.cc test-stddef-h-c++3.cc
 endif
index 8d5b4a9b50a2ea60feaf524943b9ed170430352f..e7142f610521a026000f5a14070d64368c2e82f4 100644 (file)
 /* Written by Bruno Haible <bruno@clisp.org>, 2019.  */
 
 #define GNULIB_NAMESPACE gnulib
-#include <config.h>
-
-#include <stddef.h>
-
-
-int
-main ()
-{
-}
+#include "test-stddef-h.c"
index e207976d133ffa603025a20aa132cf759ff77550..a9d25c2e496a7f0ffb8fd325096829f76c115f3f 100644 (file)
    <https://en.cppreference.com/w/cpp/header/cstddef>.  */
 
 /* Check that appropriate types are defined.  */
-ptrdiff_t b = 1;
-size_t c = 2;
+ptrdiff_t b2 = 1;
+size_t c2 = 2;
 
-#if !defined __cplusplus || defined __GNUC__ || defined __clang__
+#if !(defined __cplusplus && defined _MSC_VER)
 /* Check that NULL can be passed through varargs as a pointer type,
    per POSIX 2008.  */
 static_assert (sizeof NULL == sizeof (void *));
diff --git a/tests/test-stddef-h-c++3.cc b/tests/test-stddef-h-c++3.cc
new file mode 100644 (file)
index 0000000..7724218
--- /dev/null
@@ -0,0 +1,44 @@
+/* Test of <stddef.h> substitute in C++ mode.
+   Copyright (C) 2019-2025 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/>.  */
+
+#include <config.h>
+
+/* Define unreachable.  */
+#include <stddef.h>
+/* Define std::unreachable (in C++23 or newer).  */
+#include <utility>
+
+void
+test_cxx_unreachable_1 ()
+{
+  if (2 < 1)
+    unreachable ();
+#if defined __cpp_lib_unreachable
+  if (3 < 1)
+    std::unreachable ();
+#endif
+}
+
+#if defined __cpp_lib_unreachable
+using std::unreachable;
+
+void
+test_cxx_unreachable_2 ()
+{
+  if (3 < 1)
+    unreachable ();
+}
+#endif
index 1e577d0787d8b4d61bf3708f0133f1caf523358f..f201b411abd44e8c9c01adc2596f7cdf6f76e8de 100644 (file)
 wchar_t a = 'c';
 ptrdiff_t b = 1;
 size_t c = 2;
+#if !defined __cplusplus || __cplusplus >= 201103
 max_align_t mat;
+#endif
 
+#if !(defined __cplusplus && defined _MSC_VER)
 /* Check that NULL can be passed through varargs as a pointer type,
    per POSIX 2008.  */
 static_assert (sizeof NULL == sizeof (void *));
+#endif
 
 /* Check that offsetof produces integer constants with correct type.  */
 struct d
@@ -43,6 +47,7 @@ struct d
 static_assert (sizeof (offsetof (struct d, e)) == sizeof (size_t));
 static_assert (offsetof (struct d, f) == 1);
 
+#if !defined __cplusplus || __cplusplus >= 201103
 /* Check max_align_t's alignment.  */
 static_assert (alignof (double) <= alignof (max_align_t));
 static_assert (alignof (int) <= alignof (max_align_t));
@@ -52,7 +57,7 @@ static_assert (alignof (ptrdiff_t) <= alignof (max_align_t));
 static_assert (alignof (size_t) <= alignof (max_align_t));
 static_assert (alignof (wchar_t) <= alignof (max_align_t));
 static_assert (alignof (struct d) <= alignof (max_align_t));
-#if defined __GNUC__ || defined __clang__ || defined __IBM__ALIGNOF__
+# if defined __GNUC__ || defined __clang__ || defined __IBM__ALIGNOF__
 static_assert (__alignof__ (double) <= __alignof__ (max_align_t));
 static_assert (__alignof__ (int) <= __alignof__ (max_align_t));
 static_assert (__alignof__ (long double) <= __alignof__ (max_align_t));
@@ -61,6 +66,7 @@ static_assert (__alignof__ (ptrdiff_t) <= __alignof__ (max_align_t));
 static_assert (__alignof__ (size_t) <= __alignof__ (max_align_t));
 static_assert (__alignof__ (wchar_t) <= __alignof__ (max_align_t));
 static_assert (__alignof__ (struct d) <= __alignof__ (max_align_t));
+# endif
 #endif
 
 int test_unreachable_optimization (int x);