libstdc++: Restore ability to use <charconv> in C++14 (PR 94520)
This C++17 header is supported in C++14 as a GNU extension, but stopped working last year because I made it depend on an internal helper which is only defined for C++17 and up. PR libstdc++/94520 * include/std/charconv (__integer_to_chars_result_type) (__integer_from_chars_result_type): Use __or_ instead of __or_v_ to allow use in C++14. * testsuite/20_util/from_chars/1.cc: Run test as C++14 and replace use of std::string_view with std::string. * testsuite/20_util/from_chars/2.cc: Likewise. * testsuite/20_util/to_chars/1.cc: Likewise. * testsuite/20_util/to_chars/2.cc: Likewise.
This commit is contained in:
parent
89b01e86ff
commit
c104e8f1b6
6 changed files with 112 additions and 92 deletions
|
@ -1,3 +1,15 @@
|
|||
2020-04-07 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/94520
|
||||
* include/std/charconv (__integer_to_chars_result_type)
|
||||
(__integer_from_chars_result_type): Use __or_ instead of __or_v_ to
|
||||
allow use in C++14.
|
||||
* testsuite/20_util/from_chars/1.cc: Run test as C++14 and replace
|
||||
use of std::string_view with std::string.
|
||||
* testsuite/20_util/from_chars/2.cc: Likewise.
|
||||
* testsuite/20_util/to_chars/1.cc: Likewise.
|
||||
* testsuite/20_util/to_chars/2.cc: Likewise.
|
||||
|
||||
2020-04-06 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/94498
|
||||
|
|
|
@ -68,9 +68,9 @@ namespace __detail
|
|||
{
|
||||
template<typename _Tp>
|
||||
using __integer_to_chars_result_type
|
||||
= enable_if_t<__or_v<__is_signed_integer<_Tp>,
|
||||
__is_unsigned_integer<_Tp>,
|
||||
is_same<char, remove_cv_t<_Tp>>>,
|
||||
= enable_if_t<__or_<__is_signed_integer<_Tp>,
|
||||
__is_unsigned_integer<_Tp>,
|
||||
is_same<char, remove_cv_t<_Tp>>>::value,
|
||||
to_chars_result>;
|
||||
|
||||
// Pick an unsigned type of suitable size. This is used to reduce the
|
||||
|
@ -564,9 +564,9 @@ namespace __detail
|
|||
|
||||
template<typename _Tp>
|
||||
using __integer_from_chars_result_type
|
||||
= enable_if_t<__or_v<__is_signed_integer<_Tp>,
|
||||
__is_unsigned_integer<_Tp>,
|
||||
is_same<char, remove_cv_t<_Tp>>>,
|
||||
= enable_if_t<__or_<__is_signed_integer<_Tp>,
|
||||
__is_unsigned_integer<_Tp>,
|
||||
is_same<char, remove_cv_t<_Tp>>>::value,
|
||||
from_chars_result>;
|
||||
|
||||
} // namespace __detail
|
||||
|
|
|
@ -15,21 +15,23 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target c++17 } }
|
||||
// <charconv> is supported in C++14 as a GNU extension
|
||||
// { dg-do run { target c++14 } }
|
||||
|
||||
#include <charconv>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
template<typename I>
|
||||
bool
|
||||
check_from_chars(I expected, std::string_view s, int base = 0, char term = '\0')
|
||||
check_from_chars(I expected, std::string s, int base = 0, char term = '\0')
|
||||
{
|
||||
const char* begin = s.data();
|
||||
const char* end = s.data() + s.length();
|
||||
I val;
|
||||
std::from_chars_result r = base == 0
|
||||
? std::from_chars(s.begin(), s.end(), val)
|
||||
: std::from_chars(s.begin(), s.end(), val, base);
|
||||
return r.ec == std::errc{} && (r.ptr == s.end() || *r.ptr == term) && val == expected;
|
||||
? std::from_chars(begin, end, val)
|
||||
: std::from_chars(begin, end, val, base);
|
||||
return r.ec == std::errc{} && (r.ptr == end || *r.ptr == term) && val == expected;
|
||||
}
|
||||
|
||||
#include <climits>
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target c++17 } }
|
||||
// <charconv> is supported in C++14 as a GNU extension
|
||||
// { dg-do run { target c++14 } }
|
||||
|
||||
#include <charconv>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
// Test std::from_chars error handling.
|
||||
|
@ -29,45 +29,45 @@ test01()
|
|||
{
|
||||
std::from_chars_result r;
|
||||
int i = 999;
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
|
||||
s = "";
|
||||
r = std::from_chars(s.begin(), s.end(), i);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), i);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
VERIFY( i == 999 );
|
||||
|
||||
s = "*";
|
||||
r = std::from_chars(s.begin(), s.end(), i);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), i);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
VERIFY( i == 999 );
|
||||
|
||||
s = "-";
|
||||
r = std::from_chars(s.begin(), s.end(), i);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), i);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
VERIFY( i == 999 );
|
||||
|
||||
s = "-*";
|
||||
r = std::from_chars(s.begin(), s.end(), i);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), i);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
VERIFY( i == 999 );
|
||||
|
||||
unsigned u = 888;
|
||||
s = "-1";
|
||||
r = std::from_chars(s.begin(), s.end(), u);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), u);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
s = "-a";
|
||||
r = std::from_chars(s.begin(), s.end(), u);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), u);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
s = "-";
|
||||
r = std::from_chars(s.begin(), s.end(), u);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), u);
|
||||
VERIFY( r.ec == std::errc::invalid_argument );
|
||||
VERIFY( r.ptr == s.begin() );
|
||||
VERIFY( r.ptr == s.data() );
|
||||
VERIFY( u == 888 );
|
||||
|
||||
for (int base = 2; base <= 36; ++base)
|
||||
|
@ -93,107 +93,107 @@ void
|
|||
test02()
|
||||
{
|
||||
std::from_chars_result r;
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
|
||||
signed char c = -5;
|
||||
s = "-10000001";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "-10000001*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 9 );
|
||||
VERIFY( r.ptr == s.data() + 9 );
|
||||
s = "-10000001000*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 12 );
|
||||
VERIFY( r.ptr == s.data() + 12 );
|
||||
s = "-129";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "-129*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 4 );
|
||||
VERIFY( r.ptr == s.data() + 4 );
|
||||
s = "-100";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "-100*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 4 );
|
||||
VERIFY( r.ptr == s.data() + 4 );
|
||||
s = "-81";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "-81*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 3 );
|
||||
VERIFY( r.ptr == s.data() + 3 );
|
||||
s = "128";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "128*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 3 );
|
||||
VERIFY( r.ptr == s.data() + 3 );
|
||||
s = "80";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "80*";
|
||||
r = std::from_chars(s.begin(), s.end(), c, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), c, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 2 );
|
||||
VERIFY( r.ptr == s.data() + 2 );
|
||||
VERIFY( c == -5 );
|
||||
|
||||
unsigned char uc = 9;
|
||||
s = "100000000";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "100000000*";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 9 );
|
||||
VERIFY( r.ptr == s.data() + 9 );
|
||||
s = "100000000000*";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 2);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 2);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 12 );
|
||||
VERIFY( r.ptr == s.data() + 12 );
|
||||
s = "256";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "256**";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 3 );
|
||||
VERIFY( r.ptr == s.data() + 3 );
|
||||
s = "256000**";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 10);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 10);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 6 );
|
||||
VERIFY( r.ptr == s.data() + 6 );
|
||||
s = "100";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.end() );
|
||||
VERIFY( r.ptr == s.data() + s.length() );
|
||||
s = "100**";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 3 );
|
||||
VERIFY( r.ptr == s.data() + 3 );
|
||||
s = "100000**";
|
||||
r = std::from_chars(s.begin(), s.end(), uc, 16);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), uc, 16);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 6 );
|
||||
VERIFY( r.ptr == s.data() + 6 );
|
||||
VERIFY( uc == 9 );
|
||||
|
||||
unsigned long long ull = 123;
|
||||
s = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz****";
|
||||
r = std::from_chars(s.begin(), s.end(), ull, 36);
|
||||
r = std::from_chars(s.data(), s.data() + s.length(), ull, 36);
|
||||
VERIFY( r.ec == std::errc::result_out_of_range );
|
||||
VERIFY( r.ptr == s.begin() + 42 );
|
||||
VERIFY( r.ptr == s.data() + 42 );
|
||||
VERIFY( ull == 123 );
|
||||
}
|
||||
|
||||
|
|
|
@ -15,23 +15,29 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target c++17 } }
|
||||
// { dg-do run { target c++14 } }
|
||||
// { dg-require-string-conversions "" }
|
||||
|
||||
#include <charconv>
|
||||
#include <string_view>
|
||||
#if __cplusplus >= 201703L
|
||||
# include <string_view>
|
||||
using std::string_view;
|
||||
#else
|
||||
// <charconv> is supported in C++14 as a GNU extension
|
||||
# include <string>
|
||||
using string_view = std::string;
|
||||
#endif
|
||||
|
||||
template<typename I>
|
||||
bool
|
||||
check_to_chars(I val, std::string_view expected, int base = 0)
|
||||
check_to_chars(I val, string_view expected, int base = 0)
|
||||
{
|
||||
// Space for minus sign, 64 binary digits, final '*', and null terminator:
|
||||
char buf[67] = "******************************************************************";
|
||||
std::to_chars_result r = base == 0
|
||||
? std::to_chars(buf, buf+sizeof(buf), val)
|
||||
: std::to_chars(buf, buf+sizeof(buf), val, base);
|
||||
return r.ec == std::errc{} && *r.ptr == '*' && std::string_view(buf, r.ptr - buf) == expected;
|
||||
return r.ec == std::errc{} && *r.ptr == '*' && string_view(buf, r.ptr - buf) == expected;
|
||||
}
|
||||
|
||||
#include <string>
|
||||
|
@ -78,7 +84,7 @@ test01()
|
|||
VERIFY( check_to_chars<signed long long>(123, "123") );
|
||||
VERIFY( check_to_chars<unsigned long long>(123, "123") );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-79, "-79") );
|
||||
VERIFY( check_to_chars<signed char>(-79, "-79") );
|
||||
VERIFY( check_to_chars<signed short>(-79, "-79") );
|
||||
|
@ -160,7 +166,7 @@ test02()
|
|||
VERIFY( check_to_chars<signed long long>(123, "123", 10) );
|
||||
VERIFY( check_to_chars<unsigned long long>(123, "123", 10) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-79, "-79", 10) );
|
||||
VERIFY( check_to_chars<signed char>(-79, "-79", 10) );
|
||||
VERIFY( check_to_chars<signed short>(-79, "-79", 10) );
|
||||
|
@ -385,7 +391,7 @@ test03()
|
|||
VERIFY( check_to_chars<signed long long>(1, "1", base) );
|
||||
VERIFY( check_to_chars<unsigned long long>(1, "1", base) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-1, "-1", base) );
|
||||
VERIFY( check_to_chars<signed char>(-1, "-1", base) );
|
||||
VERIFY( check_to_chars<signed short>(-1, "-1", base) );
|
||||
|
@ -407,7 +413,7 @@ test03()
|
|||
VERIFY( check_to_chars<signed long long>(2, "2", base) );
|
||||
VERIFY( check_to_chars<unsigned long long>(2, "2", base) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-2, "-2", base) );
|
||||
VERIFY( check_to_chars<signed char>(-2, "-2", base) );
|
||||
VERIFY( check_to_chars<signed short>(-2, "-2", base) );
|
||||
|
@ -466,7 +472,7 @@ test04()
|
|||
VERIFY( check_to_chars<signed long long>(123, to_string(123), 8) );
|
||||
VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 8) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-79, to_string(-79), 8) );
|
||||
VERIFY( check_to_chars<signed char>(-79, to_string(-79), 8) );
|
||||
VERIFY( check_to_chars<signed short>(-79, to_string(-79), 8) );
|
||||
|
@ -534,7 +540,7 @@ test05()
|
|||
VERIFY( check_to_chars<signed long long>(123, to_string(123), 16) );
|
||||
VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 16) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-79, to_string(-79), 16) );
|
||||
VERIFY( check_to_chars<signed char>(-79, to_string(-79), 16) );
|
||||
VERIFY( check_to_chars<signed short>(-79, to_string(-79), 16) );
|
||||
|
@ -610,7 +616,7 @@ test06()
|
|||
VERIFY( check_to_chars<signed long long>(123, to_string(123), 2) );
|
||||
VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 2) );
|
||||
|
||||
if constexpr (std::is_signed_v<char>)
|
||||
if (std::is_signed<char>::value)
|
||||
VERIFY( check_to_chars<char>(-79, to_string(-79), 2) );
|
||||
VERIFY( check_to_chars<signed char>(-79, to_string(-79), 2) );
|
||||
VERIFY( check_to_chars<signed short>(-79, to_string(-79), 2) );
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target c++17 } }
|
||||
// <charconv> is supported in C++14 as a GNU extension
|
||||
// { dg-do run { target c++14 } }
|
||||
|
||||
#include <charconv>
|
||||
#include <testsuite_hooks.h>
|
||||
|
|
Loading…
Add table
Reference in a new issue