From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 445C63858D3C for ; Fri, 11 Mar 2022 18:32:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 445C63858D3C Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-171-0uKvooFcO4-GnCeS9Khk4w-1; Fri, 11 Mar 2022 13:32:46 -0500 X-MC-Unique: 0uKvooFcO4-GnCeS9Khk4w-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 779F5824FA7; Fri, 11 Mar 2022 18:32:45 +0000 (UTC) Received: from localhost (unknown [10.33.36.3]) by smtp.corp.redhat.com (Postfix) with ESMTP id 22587825F8; Fri, 11 Mar 2022 18:32:44 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: Ensure that std::from_chars is declared when supported Date: Fri, 11 Mar 2022 18:32:44 +0000 Message-Id: <20220311183244.1861699-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Mar 2022 18:32:52 -0000 Patrick, I think this is right, but please take a look to double check. I think we should fix the feature-test macro conditions for gcc-11 too, although it's a bit more complicated there. It should depend on IEEE float and double *and* uselocale. We don't need the other changes on the branch. -- >8 -- This adjusts the declarations in to match when the definition is present. This solves the issue that std::from_chars is present on Solaris 11.3 (using fast_float) but was not declared in the header (because the declarations were guarded by _GLIBCXX_HAVE_USELOCALE). Additionally, do not define __cpp_lib_to_chars unless both from_chars and to_chars are supported (which is only true for IEEE float and double). We might still provide from_chars (via strtold) but if to_chars isn't provided, we shouldn't define the feature test macro. Finally, this simplifies some of the preprocessor checks in the bodies of std::from_chars in src/c++17/floating_from_chars.cc and hoists the repeated code for the strtod version into a new function template. libstdc++-v3/ChangeLog: * include/std/charconv (__cpp_lib_to_chars): Only define when both from_chars and to_chars are supported for floating-point types. (from_chars, to_chars): Adjust preprocessor conditions guarding declarations. * include/std/version (__cpp_lib_to_chars): Adjust condition to match definition. * src/c++17/floating_from_chars.cc (from_chars_strtod): New function template. (from_chars): Simplify preprocessor checks and use from_chars_strtod when appropriate. --- libstdc++-v3/include/std/charconv | 8 +- libstdc++-v3/include/std/version | 3 +- libstdc++-v3/src/c++17/floating_from_chars.cc | 120 ++++++------------ 3 files changed, 45 insertions(+), 86 deletions(-) diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index a3f8c7718b2..2ce9c7d4cb9 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -43,7 +43,8 @@ #include // for std::errc #include -#if _GLIBCXX_HAVE_USELOCALE +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ + && __SIZE_WIDTH__ >= 32 # define __cpp_lib_to_chars 201611L #endif @@ -686,7 +687,7 @@ namespace __detail operator^=(chars_format& __lhs, chars_format __rhs) noexcept { return __lhs = __lhs ^ __rhs; } -#if _GLIBCXX_HAVE_USELOCALE +#if defined __cpp_lib_to_chars || _GLIBCXX_HAVE_USELOCALE from_chars_result from_chars(const char* __first, const char* __last, float& __value, chars_format __fmt = chars_format::general) noexcept; @@ -700,8 +701,7 @@ namespace __detail chars_format __fmt = chars_format::general) noexcept; #endif -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ - && __SIZE_WIDTH__ >= 32 +#if defined __cpp_lib_to_chars // Floating-point std::to_chars // Overloads for float. diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 461e65b5fab..d730a7ea3c7 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -171,7 +171,8 @@ #endif #define __cpp_lib_shared_ptr_weak_type 201606L #define __cpp_lib_string_view 201803L -#if _GLIBCXX_HAVE_USELOCALE +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ + && __SIZE_WIDTH__ >= 32 # define __cpp_lib_to_chars 201611L #endif #define __cpp_lib_unordered_map_try_emplace 201411L diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc b/libstdc++-v3/src/c++17/floating_from_chars.cc index ba0426b3344..4aa2483bc28 100644 --- a/libstdc++-v3/src/c++17/floating_from_chars.cc +++ b/libstdc++-v3/src/c++17/floating_from_chars.cc @@ -65,6 +65,7 @@ extern "C" __ieee128 __strtoieee128(const char*, char**); && __SIZE_WIDTH__ >= 32 # define USE_LIB_FAST_FLOAT 1 # if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__ +// No need to use strtold. # undef USE_STRTOD_FOR_FROM_CHARS # endif #endif @@ -420,6 +421,33 @@ namespace return true; } #endif + + template + from_chars_result + from_chars_strtod(const char* first, const char* last, T& value, + chars_format fmt) noexcept + { + errc ec = errc::invalid_argument; +#if _GLIBCXX_USE_CXX11_ABI + buffer_resource mr; + pmr::string buf(&mr); +#else + string buf; + if (!reserve_string(buf)) + return make_result(first, 0, {}, ec); +#endif + size_t len = 0; + __try + { + if (const char* pat = pattern(first, last, fmt, buf)) [[likely]] + len = from_chars_impl(pat, value, ec); + } + __catch (const std::bad_alloc&) + { + fmt = chars_format{}; + } + return make_result(first, len, fmt, ec); + } #endif // USE_STRTOD_FOR_FROM_CHARS #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 @@ -793,35 +821,15 @@ from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt) noexcept { -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 +#if USE_LIB_FAST_FLOAT if (fmt == chars_format::hex) return __floating_from_chars_hex(first, last, value); else { - static_assert(USE_LIB_FAST_FLOAT); return fast_float::from_chars(first, last, value, fmt); } #else - errc ec = errc::invalid_argument; -#if _GLIBCXX_USE_CXX11_ABI - buffer_resource mr; - pmr::string buf(&mr); -#else - string buf; - if (!reserve_string(buf)) - return make_result(first, 0, {}, ec); -#endif - size_t len = 0; - __try - { - if (const char* pat = pattern(first, last, fmt, buf)) [[likely]] - len = from_chars_impl(pat, value, ec); - } - __catch (const std::bad_alloc&) - { - fmt = chars_format{}; - } - return make_result(first, len, fmt, ec); + return from_chars_strtod(first, last, value, fmt); #endif } @@ -829,35 +837,15 @@ from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt) noexcept { -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 +#if USE_LIB_FAST_FLOAT if (fmt == chars_format::hex) return __floating_from_chars_hex(first, last, value); else { - static_assert(USE_LIB_FAST_FLOAT); return fast_float::from_chars(first, last, value, fmt); } #else - errc ec = errc::invalid_argument; -#if _GLIBCXX_USE_CXX11_ABI - buffer_resource mr; - pmr::string buf(&mr); -#else - string buf; - if (!reserve_string(buf)) - return make_result(first, 0, {}, ec); -#endif - size_t len = 0; - __try - { - if (const char* pat = pattern(first, last, fmt, buf)) [[likely]] - len = from_chars_impl(pat, value, ec); - } - __catch (const std::bad_alloc&) - { - fmt = chars_format{}; - } - return make_result(first, len, fmt, ec); + return from_chars_strtod(first, last, value, fmt); #endif } @@ -865,41 +853,23 @@ from_chars_result from_chars(const char* first, const char* last, long double& value, chars_format fmt) noexcept { -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ - && ! USE_STRTOD_FOR_FROM_CHARS +#if ! USE_STRTOD_FOR_FROM_CHARS + // Either long double is the same as double, or we can't use strtold. + // In the latter case, this might give an incorrect result (e.g. values + // out of range of double give an error, even if they fit in long double). double dbl_value; from_chars_result result; if (fmt == chars_format::hex) result = __floating_from_chars_hex(first, last, dbl_value); else { - static_assert(USE_LIB_FAST_FLOAT); result = fast_float::from_chars(first, last, dbl_value, fmt); } if (result.ec == errc{}) value = dbl_value; return result; #else - errc ec = errc::invalid_argument; -#if _GLIBCXX_USE_CXX11_ABI - buffer_resource mr; - pmr::string buf(&mr); -#else - string buf; - if (!reserve_string(buf)) - return make_result(first, 0, {}, ec); -#endif - size_t len = 0; - __try - { - if (const char* pat = pattern(first, last, fmt, buf)) [[likely]] - len = from_chars_impl(pat, value, ec); - } - __catch (const std::bad_alloc&) - { - fmt = chars_format{}; - } - return make_result(first, len, fmt, ec); + return from_chars_strtod(first, last, value, fmt); #endif } @@ -918,20 +888,8 @@ from_chars_result from_chars(const char* first, const char* last, __ieee128& value, chars_format fmt) noexcept { - buffer_resource mr; - pmr::string buf(&mr); - size_t len = 0; - errc ec = errc::invalid_argument; - __try - { - if (const char* pat = pattern(first, last, fmt, buf)) [[likely]] - len = from_chars_impl(pat, value, ec); - } - __catch (const std::bad_alloc&) - { - fmt = chars_format{}; - } - return make_result(first, len, fmt, ec); + // fast_float doesn't support IEEE binary128 format, but we can use strtold. + return from_chars_strtod(first, last, value, fmt); } #endif -- 2.34.1