From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id E45D93945C16; Fri, 1 Apr 2022 12:39:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E45D93945C16 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-7957] libstdc++: Implement std::unreachable() for C++23 (P0627R6) X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 944da70a5d1cdc5bd4327b2d32420f57b6883985 X-Git-Newrev: babaabbcc8346758be0051b32272da18d54f5eea Message-Id: <20220401123936.E45D93945C16@sourceware.org> Date: Fri, 1 Apr 2022 12:39:36 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Apr 2022 12:39:37 -0000 https://gcc.gnu.org/g:babaabbcc8346758be0051b32272da18d54f5eea commit r12-7957-gbabaabbcc8346758be0051b32272da18d54f5eea Author: Jonathan Wakely Date: Fri Apr 1 12:25:02 2022 +0100 libstdc++: Implement std::unreachable() for C++23 (P0627R6) This defines std::unreachable as an assertion for debug mode, a trap when _GLIBCXX_ASSERTIONS is defined, and __builtin_unreachable() otherwise. The reason for only using __builtin_trap() in the second case is to avoid the overhead of setting up a call to __glibcxx_assert_fail that should never happen. UBsan can detect if __builtin_unreachable() is executed, so if a feature test macro for that sanitizer is added, we could change just use __builtin_unreachable() when the sanitizer is enabled. While thinking about what the debug assertion failure should print, I noticed that the __glibcxx_assert_fail function doesn't check for null pointers. This adds a check so we don't try to print them if null. libstdc++-v3/ChangeLog: * include/std/utility (unreachable): Define for C++23. * include/std/version (__cpp_lib_unreachable): Define. * src/c++11/debug.cc (__glibcxx_assert_fail): Check for valid arguments. Handle only the function being given. * testsuite/20_util/unreachable/1.cc: New test. * testsuite/20_util/unreachable/version.cc: New test. Diff: --- libstdc++-v3/include/std/utility | 26 ++++++++++++++++++++++ libstdc++-v3/include/std/version | 1 + libstdc++-v3/src/c++11/debug.cc | 7 ++++-- libstdc++-v3/testsuite/20_util/unreachable/1.cc | 17 ++++++++++++++ .../testsuite/20_util/unreachable/version.cc | 10 +++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 0d7f8954c5a..ad5faa50f57 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -186,6 +186,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr underlying_type_t<_Tp> to_underlying(_Tp __value) noexcept { return static_cast>(__value); } + +#define __cpp_lib_unreachable 202202L + /// Informs the compiler that program control flow never reaches this point. + /** + * Evaluating a call to this function results in undefined behaviour. + * This can be used as an assertion informing the compiler that certain + * conditions are impossible, for when the compiler is unable to determine + * that by itself. + * + * For example, it can be used to prevent warnings about reaching the + * end of a non-void function without returning. + * + * @since C++23 + */ + [[noreturn,__gnu__::__always_inline__]] + inline void + unreachable() + { +#ifdef _GLIBCXX_DEBUG + std::__glibcxx_assert_fail(nullptr, 0, "std::unreachable()", nullptr); +#elif defined _GLIBCXX_ASSERTIONS + __builtin_trap(); +#else + __builtin_unreachable(); +#endif + } #endif // C++23 #endif // C++20 #endif // C++17 diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 44b8a9f88b5..51f2110b68e 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -326,6 +326,7 @@ # define __cpp_lib_string_resize_and_overwrite 202110L #endif #define __cpp_lib_to_underlying 202102L +#define __cpp_lib_unreachable 202202L #endif #endif // C++2b #endif // C++20 diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 98fe2dcc153..4706defedf1 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -52,8 +52,11 @@ namespace std __glibcxx_assert_fail(const char* file, int line, const char* function, const char* condition) noexcept { - fprintf(stderr, "%s:%d: %s: Assertion '%s' failed.\n", - file, line, function, condition); + if (file && function && condition) + fprintf(stderr, "%s:%d: %s: Assertion '%s' failed.\n", + file, line, function, condition); + else if (function) + fprintf(stderr, "%s: Undefined behavior detected.\n", function); abort(); } } diff --git a/libstdc++-v3/testsuite/20_util/unreachable/1.cc b/libstdc++-v3/testsuite/20_util/unreachable/1.cc new file mode 100644 index 00000000000..0c463d52a48 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unreachable/1.cc @@ -0,0 +1,17 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } + +#include + +#ifndef __cpp_lib_unreachable +# error "Feature-test macro for unreachable missing in " +#elif __cpp_lib_unreachable != 202202L +# error "Feature-test macro for unreachable has wrong value in " +#endif + +bool test01(int i) +{ + if (i == 4) + return true; + std::unreachable(); +} // { dg-bogus "control reaches end of non-void function" } diff --git a/libstdc++-v3/testsuite/20_util/unreachable/version.cc b/libstdc++-v3/testsuite/20_util/unreachable/version.cc new file mode 100644 index 00000000000..c7795900c30 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unreachable/version.cc @@ -0,0 +1,10 @@ +// { dg-options "-std=gnu++23" } +// { dg-do preprocess { target c++23 } } + +#include + +#ifndef __cpp_lib_unreachable +# error "Feature-test macro for unreachable missing in " +#elif __cpp_lib_unreachable != 202202L +# error "Feature-test macro for unreachable has wrong value in " +#endif