From: Bruno Haible Date: Tue, 27 May 2025 23:59:05 +0000 (+0200) Subject: stddef-h: Make 'unreachable' usable in C++ mode. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d19a73d049ef692e5d16f474dd6c5cc98669f53c;p=thirdparty%2Fgnulib.git stddef-h: Make 'unreachable' usable in C++ mode. Reported by Pierre Ossman at . * m4/stddef_h.m4 (gl_STDDEF_H): Also test whether unreachable is defined by in C++ mode. * lib/stddef.in.h: In C++ mode, include 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. --- diff --git a/ChangeLog b/ChangeLog index efcb253321..d14ec6f717 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2025-05-27 Bruno Haible + + stddef-h: Make 'unreachable' usable in C++ mode. + Reported by Pierre Ossman + at . + * m4/stddef_h.m4 (gl_STDDEF_H): Also test whether unreachable is defined + by in C++ mode. + * lib/stddef.in.h: In C++ mode, include 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 strchrnul: Fix for users of the current macOS SDK. diff --git a/lib/stddef.in.h b/lib/stddef.in.h index dc689b8df8..2754e881e7 100644 --- a/lib/stddef.in.h +++ b/lib/stddef.in.h @@ -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 . */ 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 here causes errors + when gets included: + type_traits(1164): error C2065: 'max_align_t': undeclared identifier */ +# if !defined _MSC_VER +extern "C++" { /* needed for Cygwin */ +# include +} +# endif + +# if defined __cpp_lib_unreachable /* C++23 or newer */ + +using std::unreachable; + +# else + +inline void unreachable () { _gl_unreachable (); } + # endif #endif diff --git a/m4/stddef_h.m4 b/m4/stddef_h.m4 index 3bc8cd85fe..bdcb428017 100644 --- a/m4/stddef_h.m4 +++ b/m4/stddef_h.m4 @@ -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 ]], [[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++ has std::unreachable, + dnl see , + dnl but we want an unreachable() that is available from , + dnl like in ISO C 23. + AC_CACHE_CHECK([for unreachable in 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 . + cat > conftest.cpp <<\EOF +#include +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 ], diff --git a/modules/stddef-h-c++-tests b/modules/stddef-h-c++-tests index b46418837a..4067a13cfb 100644 --- a/modules/stddef-h-c++-tests +++ b/modules/stddef-h-c++-tests @@ -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 diff --git a/tests/test-stddef-h-c++.cc b/tests/test-stddef-h-c++.cc index 8d5b4a9b50..e7142f6105 100644 --- a/tests/test-stddef-h-c++.cc +++ b/tests/test-stddef-h-c++.cc @@ -17,12 +17,4 @@ /* Written by Bruno Haible , 2019. */ #define GNULIB_NAMESPACE gnulib -#include - -#include - - -int -main () -{ -} +#include "test-stddef-h.c" diff --git a/tests/test-stddef-h-c++2.cc b/tests/test-stddef-h-c++2.cc index e207976d13..a9d25c2e49 100644 --- a/tests/test-stddef-h-c++2.cc +++ b/tests/test-stddef-h-c++2.cc @@ -23,10 +23,10 @@ . */ /* 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 index 0000000000..77242183c8 --- /dev/null +++ b/tests/test-stddef-h-c++3.cc @@ -0,0 +1,44 @@ +/* Test of 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 . */ + +#include + +/* Define unreachable. */ +#include +/* Define std::unreachable (in C++23 or newer). */ +#include + +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 diff --git a/tests/test-stddef-h.c b/tests/test-stddef-h.c index 1e577d0787..f201b411ab 100644 --- a/tests/test-stddef-h.c +++ b/tests/test-stddef-h.c @@ -24,11 +24,15 @@ 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);