libstdc++: Restore ability to use <charconv> in C++14 (PR 94520)
authorJonathan Wakely <jwakely@redhat.com>
Tue, 7 Apr 2020 16:18:21 +0000 (17:18 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 7 Apr 2020 16:18:21 +0000 (17:18 +0100)
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.

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/charconv
libstdc++-v3/testsuite/20_util/from_chars/1.cc
libstdc++-v3/testsuite/20_util/from_chars/2.cc
libstdc++-v3/testsuite/20_util/to_chars/1.cc
libstdc++-v3/testsuite/20_util/to_chars/2.cc

index 4d7b57801897294b4b796f634b8b4afa88a41df0..b95a89373db8c8cf8aa956939f6e67994a040af7 100644 (file)
@@ -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
index 35f8efc7e359dac763895f8fdb0e778a38241271..8c9ce9d280e7b7c8007a0f5921a687dee7fb4c0a 100644 (file)
@@ -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
index 6ce95590793b1337cbd86674ef72ce11cd76659e..916025bc7c6f6d5e623cf4be37d2d8c4ecb636bb 100644 (file)
 // 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>
index caff17e66b2ace3b543d9679e0ab18eada683367..902092fd42312c719fb71055d5778d383bf5eb82 100644 (file)
 // 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 );
 }
 
index 7e2f1cec08d01ea9cc28b660c7d56bb2522ef37b..9c45921901077e1bd01585c3e577b6f77069359d 100644 (file)
 // 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) );
index cc9c79066da78c31ead36c6a1ad309da549d16b8..8b9119f701f592afeffaac6f7d0c219d05c6cb41 100644 (file)
@@ -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>