From 2251b4a5423efa8ee0d7e67537b63e404a1f6afa Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 27 Jul 2020 15:51:16 +0100 Subject: [PATCH] libstdc++: Make std::from_chars always round to nearest Also fix the tests that fail on targets without uselocale. libstdc++-v3/ChangeLog: * src/c++17/floating_from_chars.cc (from_chars_impl): Ensure that FE_NEAREST is used. * testsuite/20_util/from_chars/4.cc: Do not use if constexpr in a { target c++14 } test. [!_GLIBCXX_HAVE_USELOCALE]: Disable all tests. * testsuite/20_util/from_chars/5.cc [!_GLIBCXX_HAVE_USELOCALE]: Likewise. * testsuite/20_util/from_chars/6.cc: New test. --- libstdc++-v3/src/c++17/floating_from_chars.cc | 12 +++++ .../testsuite/20_util/from_chars/4.cc | 9 +++- .../testsuite/20_util/from_chars/5.cc | 6 +++ .../testsuite/20_util/from_chars/6.cc | 49 +++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/from_chars/6.cc diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc b/libstdc++-v3/src/c++17/floating_from_chars.cc index 45de2be283d..f1519e5c7b6 100644 --- a/libstdc++-v3/src/c++17/floating_from_chars.cc +++ b/libstdc++-v3/src/c++17/floating_from_chars.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -289,6 +290,12 @@ namespace { locale_t orig = ::uselocale(loc); +#if _GLIBCXX_USE_C99_FENV_TR1 + const int rounding = std::fegetround(); + if (rounding != FE_TONEAREST) + std::fesetround(FE_TONEAREST); +#endif + const int save_errno = errno; errno = 0; char* endptr; @@ -301,6 +308,11 @@ namespace tmpval = std::strtold(str, &endptr); const int conv_errno = std::__exchange(errno, save_errno); +#if _GLIBCXX_USE_C99_FENV_TR1 + if (rounding != FE_TONEAREST) + std::fesetround(rounding); +#endif + ::uselocale(orig); ::freelocale(loc); diff --git a/libstdc++-v3/testsuite/20_util/from_chars/4.cc b/libstdc++-v3/testsuite/20_util/from_chars/4.cc index 6d692592e95..e7127ed0c48 100644 --- a/libstdc++-v3/testsuite/20_util/from_chars/4.cc +++ b/libstdc++-v3/testsuite/20_util/from_chars/4.cc @@ -27,6 +27,9 @@ // Test std::from_chars floating-point conversions. +// As of July 2020 __cpp_lib_to_chars is not defined, but std::from_chars +// works for floating-point types when _GLIBCXX_HAVE_USELOCALE is defined. +#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE void test01() { @@ -296,8 +299,7 @@ test_max_mantissa() using Float_limits = std::numeric_limits; using UInt_limits = std::numeric_limits; - if constexpr (Float_limits::is_iec559 - && Float_limits::digits < UInt_limits::digits) + if (Float_limits::is_iec559 && Float_limits::digits < UInt_limits::digits) { std::printf("Testing %d-bit float, using %zu-bit integer\n", Float_limits::digits + (int)std::log2(Float_limits::max_exponent) + 1, @@ -355,14 +357,17 @@ test06() test_max_mantissa(); #endif } +#endif int main() { +#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE test01(); test02(); test03(); test04(); test05(); test06(); +#endif } diff --git a/libstdc++-v3/testsuite/20_util/from_chars/5.cc b/libstdc++-v3/testsuite/20_util/from_chars/5.cc index f8fc7f6cd12..9525da8aebe 100644 --- a/libstdc++-v3/testsuite/20_util/from_chars/5.cc +++ b/libstdc++-v3/testsuite/20_util/from_chars/5.cc @@ -25,6 +25,9 @@ // Test std::from_chars error handling. +// As of July 2020 __cpp_lib_to_chars is not defined, but std::from_chars +// works for floating-point types when _GLIBCXX_HAVE_USELOCALE is defined. +#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE void test01() { @@ -152,12 +155,15 @@ test04() } } } +#endif int main() { +#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE test01(); test02(); test03(); test04(); +#endif } diff --git a/libstdc++-v3/testsuite/20_util/from_chars/6.cc b/libstdc++-v3/testsuite/20_util/from_chars/6.cc new file mode 100644 index 00000000000..e592b2eb806 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/from_chars/6.cc @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// . + +// is supported in C++14 as a GNU extension +// { dg-do run { target c++14 } } +// { dg-add-options ieee } + +#include +#include +#include +#include + +void +test01() +{ +#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE +#if _GLIBCXX_USE_C99_FENV_TR1 + double d; + std::fesetround(FE_DOWNWARD); + const std::string s = "0.099999999999999999999999999"; + auto res = std::from_chars(s.data(), s.data() + s.length(), d); + VERIFY( res.ec == std::errc{} ); + VERIFY( res.ptr == s.data() + s.length() ); + // std::from_chars should ignore the current rounding mode + // and always round to nearest. + VERIFY( d == 0.1 ); +#endif +#endif +} + +int +main() +{ + test01(); +} -- 2.30.2