[libcxx-commits] [libcxx] 6880a2a - [libc++] Suppress unsigned-integer-overflow warning in <charconv> (#225801)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 13 06:52:30 PDT 2026


Author: hchataing
Date: 2026-10-13T15:52:24+02:00
New Revision: 6880a2a498646d518b580ef8ba34bbca68258984

URL: https://github.com/llvm/llvm-project/commit/6880a2a498646d518b580ef8ba34bbca68258984
DIFF: https://github.com/llvm/llvm-project/commit/6880a2a498646d518b580ef8ba34bbca68258984.diff

LOG: [libc++] Suppress unsigned-integer-overflow warning in <charconv> (#225801)

Invoking __complement with 0 as parameter triggers the unsigned integer
overflow UBSan.

Added: 
    

Modified: 
    libcxx/include/__charconv/traits.h
    libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
    libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
    libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp
    libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
    libcxx/test/support/charconv_test_helpers.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h
index b8c840d1ebe326..a13c30a19c23dc 100644
--- a/libcxx/include/__charconv/traits.h
+++ b/libcxx/include/__charconv/traits.h
@@ -155,7 +155,8 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp> {
 } // namespace __itoa
 
 template <typename _Tp>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Tp __complement(_Tp __x) {
+inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK _Tp
+__complement(_Tp __x) {
   static_assert(is_unsigned<_Tp>::value, "cast to unsigned first");
   return _Tp(~__x + 1);
 }

diff  --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
index a02c7ac466f046..512bda55c7966b 100644
--- a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
@@ -17,6 +17,7 @@
 //                              double& value, chars_format fmt = chars_format::general)
 
 #include <array>
+#include <cassert>
 #include <charconv>
 #include <cmath>
 #include <cstring>
@@ -24,8 +25,8 @@
 #include <stdexcept>
 #include <system_error>
 
-#include "charconv_test_helpers.h"
 #include "test_macros.h"
+#include "type_algorithms.h"
 
 template <class F>
 void test_infinity(std::chars_format fmt) {
@@ -325,8 +326,8 @@ void test_fmt_independent(std::chars_format fmt) {
   }
 }
 
-template <class F>
 struct test_basics {
+  template <class F>
   void operator()() {
     for (auto fmt : {std::chars_format::scientific,
                      std::chars_format::fixed,
@@ -335,8 +336,8 @@ struct test_basics {
   }
 };
 
-template <class F>
 struct test_fixed {
+  template <class F>
   void operator()() {
     std::from_chars_result r;
     F x = 0.25;
@@ -600,8 +601,8 @@ struct test_fixed {
   }
 };
 
-template <class F>
 struct test_scientific {
+  template <class F>
   void operator()() {
     std::from_chars_result r;
     F x = 0.25;
@@ -874,8 +875,8 @@ struct test_scientific {
   }
 };
 
-template <class F>
 struct test_general {
+  template <class F>
   void operator()() {
     std::from_chars_result r;
     F x = 0.25;
@@ -1194,8 +1195,8 @@ struct test_general {
   }
 };
 
-template <class F>
 struct test_hex {
+  template <class F>
   void operator()() {
     std::from_chars_result r;
     F x = 0.25;
@@ -1547,12 +1548,13 @@ void test_random_errors() {
 }
 
 int main(int, char**) {
-  run<test_basics>(all_floats);
-  run<test_scientific>(all_floats);
-  run<test_fixed>(all_floats);
-  run<test_general>(all_floats);
+  using all_floats = types::type_list<float, double>; // TODO: Add long double
+  types::for_each(all_floats(), test_basics());
+  types::for_each(all_floats(), test_scientific());
+  types::for_each(all_floats(), test_fixed());
+  types::for_each(all_floats(), test_general());
 
-  run<test_hex>(all_floats);
+  types::for_each(all_floats(), test_hex());
 
   test_random_errors();
 

diff  --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
index 4708da4c38b9b6..ab6f6724cfc887 100644
--- a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
@@ -8,6 +8,9 @@
 
 // UNSUPPORTED: c++03, c++11, c++14
 
+// FIXME: Enable this for all tests once possible
+// ADDITIONAL_COMPILE_FLAGS(ubsan): -fsanitize=unsigned-integer-overflow
+
 // <charconv>
 
 // constexpr from_chars_result from_chars(const char* first, const char* last,
@@ -19,9 +22,9 @@
 #include "test_macros.h"
 #include "charconv_test_helpers.h"
 
-template <typename T>
 struct test_basics
 {
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
         std::from_chars_result r;
@@ -83,9 +86,9 @@ struct test_basics
     }
 };
 
-template <typename T>
 struct test_signed
 {
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
         std::from_chars_result r;
@@ -134,13 +137,22 @@ struct test_signed
             // the member ec is equal to errc::invalid_argument.
             assert(r.ec == std::errc::invalid_argument);
         }
+
+        {
+            // Ensure "-0" does not trigger unsigned integer overflow.
+            char s[] = "-0";
+            r = std::from_chars(s, s + sizeof(s), x);
+            assert(r.ec == std::errc{});
+            assert(r.ptr == s + 2);
+            assert(x == 0);
+        }
     }
 };
 
 TEST_CONSTEXPR_CXX23 bool test()
 {
-    run<test_basics>(integrals);
-    run<test_signed>(all_signed);
+    types::for_each(integrals(), test_basics());
+    types::for_each(types::signed_integer_types(), test_signed());
 
     return true;
 }

diff  --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp
index b1f2c77b34f8af..a9681202ba400f 100644
--- a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp
@@ -21,66 +21,62 @@
 #include "test_macros.h"
 #include "charconv_test_helpers.h"
 
-template <typename T>
-struct test_basics : roundtrip_test_base<T>
+struct test_basics : roundtrip_test_base
 {
-    using roundtrip_test_base<T>::test;
-
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
-        test(0);
-        test(42);
-        test(32768);
-        test(0, 10);
-        test(42, 10);
-        test(32768, 10);
-        test(0xf, 16);
-        test(0xdeadbeaf, 16);
-        test(0755, 8);
+        test<T>(0);
+        test<T>(42);
+        test<T>(32768);
+        test<T>(0, 10);
+        test<T>(42, 10);
+        test<T>(32768, 10);
+        test<T>(0xf, 16);
+        test<T>(0xdeadbeaf, 16);
+        test<T>(0755, 8);
 
         for (int b = 2; b < 37; ++b)
         {
             using xl = std::numeric_limits<T>;
 
-            test(1, b);
-            test(-1, b);
-            test(xl::lowest(), b);
-            test((xl::max)(), b);
-            test((xl::max)() / 2, b);
+            test<T>(1, b);
+            test<T>(-1, b);
+            test<T>(xl::lowest(), b);
+            test<T>((xl::max)(), b);
+            test<T>((xl::max)() / 2, b);
         }
     }
 };
 
-template <typename T>
-struct test_signed : roundtrip_test_base<T>
+struct test_signed : roundtrip_test_base
 {
-    using roundtrip_test_base<T>::test;
-
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
-        test(-1);
-        test(-12);
-        test(-1, 10);
-        test(-12, 10);
-        test(-21734634, 10);
-        test(-2647, 2);
-        test(-0xcc1, 16);
+        test<T>(-1);
+        test<T>(-12);
+        test<T>(-1, 10);
+        test<T>(-12, 10);
+        test<T>(-21734634, 10);
+        test<T>(-2647, 2);
+        test<T>(-0xcc1, 16);
 
         for (int b = 2; b < 37; ++b)
         {
             using xl = std::numeric_limits<T>;
 
-            test(0, b);
-            test(xl::lowest(), b);
-            test((xl::max)(), b);
+            test<T>(0, b);
+            test<T>(xl::lowest(), b);
+            test<T>((xl::max)(), b);
         }
     }
 };
 
 TEST_CONSTEXPR_CXX23 bool test()
 {
-    run<test_basics>(integrals);
-    run<test_signed>(all_signed);
+    types::for_each(integrals(), test_basics());
+    types::for_each(types::signed_integer_types(), test_signed());
 
     return true;
 }

diff  --git a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
index e89b340bdfcbe9..4d07ad78d5d8f8 100644
--- a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
@@ -51,252 +51,246 @@ TEST_CONSTEXPR_CXX23 __int128_t make_i128(__int128_t a, __int128_t b, std::int64
 }
 #endif
 
-template <typename T>
-struct test_basics : to_chars_test_base<T>
+struct test_basics : to_chars_test_base
 {
-    using to_chars_test_base<T>::test;
-    using to_chars_test_base<T>::test_value;
-
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
-        test(0, "0");
-        test(42, "42");
-        test(32768, "32768");
-        test(0, "0", 10);
-        test(42, "42", 10);
-        test(32768, "32768", 10);
-        test(0xf, "f", 16);
-        test(0xdeadbeaf, "deadbeaf", 16);
-        test(0755, "755", 8);
+        test<T>(0, "0");
+        test<T>(42, "42");
+        test<T>(32768, "32768");
+        test<T>(0, "0", 10);
+        test<T>(42, "42", 10);
+        test<T>(32768, "32768", 10);
+        test<T>(0xf, "f", 16);
+        test<T>(0xdeadbeaf, "deadbeaf", 16);
+        test<T>(0755, "755", 8);
 
         // Test each len till len of UINT64_MAX = 20 because to_chars algorithm
         // makes branches based on decimal digits count in the value string
         // representation.
         // Test driver automatically skips values not fitting into source type.
-        test(1UL, "1");
-        test(12UL, "12");
-        test(123UL, "123");
-        test(1234UL, "1234");
-        test(12345UL, "12345");
-        test(123456UL, "123456");
-        test(1234567UL, "1234567");
-        test(12345678UL, "12345678");
-        test(123456789UL, "123456789");
-        test(1234567890UL, "1234567890");
-        test(12345678901UL, "12345678901");
-        test(123456789012UL, "123456789012");
-        test(1234567890123UL, "1234567890123");
-        test(12345678901234UL, "12345678901234");
-        test(123456789012345UL, "123456789012345");
-        test(1234567890123456UL, "1234567890123456");
-        test(12345678901234567UL, "12345678901234567");
-        test(123456789012345678UL, "123456789012345678");
-        test(1234567890123456789UL, "1234567890123456789");
-        test(12345678901234567890UL, "12345678901234567890");
+        test<T>(1UL, "1");
+        test<T>(12UL, "12");
+        test<T>(123UL, "123");
+        test<T>(1234UL, "1234");
+        test<T>(12345UL, "12345");
+        test<T>(123456UL, "123456");
+        test<T>(1234567UL, "1234567");
+        test<T>(12345678UL, "12345678");
+        test<T>(123456789UL, "123456789");
+        test<T>(1234567890UL, "1234567890");
+        test<T>(12345678901UL, "12345678901");
+        test<T>(123456789012UL, "123456789012");
+        test<T>(1234567890123UL, "1234567890123");
+        test<T>(12345678901234UL, "12345678901234");
+        test<T>(123456789012345UL, "123456789012345");
+        test<T>(1234567890123456UL, "1234567890123456");
+        test<T>(12345678901234567UL, "12345678901234567");
+        test<T>(123456789012345678UL, "123456789012345678");
+        test<T>(1234567890123456789UL, "1234567890123456789");
+        test<T>(12345678901234567890UL, "12345678901234567890");
 #ifndef TEST_HAS_NO_INT128
-        test(make_u128(12UL, 3456789012345678901UL), "123456789012345678901");
-        test(make_u128(123UL, 4567890123456789012UL), "1234567890123456789012");
-        test(make_u128(1234UL, 5678901234567890123UL), "12345678901234567890123");
-        test(make_u128(12345UL, 6789012345678901234UL), "123456789012345678901234");
-        test(make_u128(123456UL, 7890123456789012345UL), "1234567890123456789012345");
-        test(make_u128(1234567UL, 8901234567890123456UL), "12345678901234567890123456");
-        test(make_u128(12345678UL, 9012345678901234567UL), "123456789012345678901234567");
-        test(make_u128(123456789UL, 123456789012345678UL), "1234567890123456789012345678");
-        test(make_u128(123UL, 4567890123456UL, 7890123456789UL), "12345678901234567890123456789");
-        test(make_u128(1234UL, 5678901234567UL, 8901234567890UL), "123456789012345678901234567890");
-        test(make_u128(12345UL, 6789012345678UL, 9012345678901UL), "1234567890123456789012345678901");
-        test(make_u128(123456UL, 7890123456789UL, 123456789012UL), "12345678901234567890123456789012");
-        test(make_u128(1234567UL, 8901234567890UL, 1234567890123UL), "123456789012345678901234567890123");
-        test(make_u128(12345678UL, 9012345678901UL, 2345678901234UL), "1234567890123456789012345678901234");
-        test(make_u128(123456789UL, 123456789012UL, 3456789012345UL), "12345678901234567890123456789012345");
-        test(make_u128(1234567890UL, 1234567890123UL, 4567890123456UL), "123456789012345678901234567890123456");
-        test(make_u128(12345678901UL, 2345678901234UL, 5678901234567UL), "1234567890123456789012345678901234567");
-        test(make_u128(123456789012UL, 3456789012345UL, 6789012345678UL), "12345678901234567890123456789012345678");
-        test(make_u128(1234567890123UL, 4567890123456UL, 7890123456789UL), "123456789012345678901234567890123456789");
+        test<T>(make_u128(12UL, 3456789012345678901UL), "123456789012345678901");
+        test<T>(make_u128(123UL, 4567890123456789012UL), "1234567890123456789012");
+        test<T>(make_u128(1234UL, 5678901234567890123UL), "12345678901234567890123");
+        test<T>(make_u128(12345UL, 6789012345678901234UL), "123456789012345678901234");
+        test<T>(make_u128(123456UL, 7890123456789012345UL), "1234567890123456789012345");
+        test<T>(make_u128(1234567UL, 8901234567890123456UL), "12345678901234567890123456");
+        test<T>(make_u128(12345678UL, 9012345678901234567UL), "123456789012345678901234567");
+        test<T>(make_u128(123456789UL, 123456789012345678UL), "1234567890123456789012345678");
+        test<T>(make_u128(123UL, 4567890123456UL, 7890123456789UL), "12345678901234567890123456789");
+        test<T>(make_u128(1234UL, 5678901234567UL, 8901234567890UL), "123456789012345678901234567890");
+        test<T>(make_u128(12345UL, 6789012345678UL, 9012345678901UL), "1234567890123456789012345678901");
+        test<T>(make_u128(123456UL, 7890123456789UL, 123456789012UL), "12345678901234567890123456789012");
+        test<T>(make_u128(1234567UL, 8901234567890UL, 1234567890123UL), "123456789012345678901234567890123");
+        test<T>(make_u128(12345678UL, 9012345678901UL, 2345678901234UL), "1234567890123456789012345678901234");
+        test<T>(make_u128(123456789UL, 123456789012UL, 3456789012345UL), "12345678901234567890123456789012345");
+        test<T>(make_u128(1234567890UL, 1234567890123UL, 4567890123456UL), "123456789012345678901234567890123456");
+        test<T>(make_u128(12345678901UL, 2345678901234UL, 5678901234567UL), "1234567890123456789012345678901234567");
+        test<T>(make_u128(123456789012UL, 3456789012345UL, 6789012345678UL), "12345678901234567890123456789012345678");
+        test<T>(make_u128(1234567890123UL, 4567890123456UL, 7890123456789UL), "123456789012345678901234567890123456789");
 #endif
 
         // Test special cases with zeros inside a value string representation,
         // to_chars algorithm processes them in a special way and should not
         // skip trailing zeros
         // Test driver automatically skips values not fitting into source type.
-        test(0UL, "0");
-        test(10UL, "10");
-        test(100UL, "100");
-        test(1000UL, "1000");
-        test(10000UL, "10000");
-        test(100000UL, "100000");
-        test(1000000UL, "1000000");
-        test(10000000UL, "10000000");
-        test(100000000UL, "100000000");
-        test(1000000000UL, "1000000000");
-        test(10000000000UL, "10000000000");
-        test(100000000000UL, "100000000000");
-        test(1000000000000UL, "1000000000000");
-        test(10000000000000UL, "10000000000000");
-        test(100000000000000UL, "100000000000000");
-        test(1000000000000000UL, "1000000000000000");
-        test(10000000000000000UL, "10000000000000000");
-        test(100000000000000000UL, "100000000000000000");
-        test(1000000000000000000UL, "1000000000000000000");
-        test(10000000000000000000UL, "10000000000000000000");
+        test<T>(0UL, "0");
+        test<T>(10UL, "10");
+        test<T>(100UL, "100");
+        test<T>(1000UL, "1000");
+        test<T>(10000UL, "10000");
+        test<T>(100000UL, "100000");
+        test<T>(1000000UL, "1000000");
+        test<T>(10000000UL, "10000000");
+        test<T>(100000000UL, "100000000");
+        test<T>(1000000000UL, "1000000000");
+        test<T>(10000000000UL, "10000000000");
+        test<T>(100000000000UL, "100000000000");
+        test<T>(1000000000000UL, "1000000000000");
+        test<T>(10000000000000UL, "10000000000000");
+        test<T>(100000000000000UL, "100000000000000");
+        test<T>(1000000000000000UL, "1000000000000000");
+        test<T>(10000000000000000UL, "10000000000000000");
+        test<T>(100000000000000000UL, "100000000000000000");
+        test<T>(1000000000000000000UL, "1000000000000000000");
+        test<T>(10000000000000000000UL, "10000000000000000000");
 #ifndef TEST_HAS_NO_INT128
-        test(make_u128(10UL, 0), "100000000000000000000");
-        test(make_u128(100UL, 0), "1000000000000000000000");
-        test(make_u128(1000UL, 0), "10000000000000000000000");
-        test(make_u128(10000UL, 0), "100000000000000000000000");
-        test(make_u128(100000UL, 0), "1000000000000000000000000");
-        test(make_u128(1000000UL, 0), "10000000000000000000000000");
-        test(make_u128(10000000UL, 0), "100000000000000000000000000");
-        test(make_u128(100000000UL, 0), "1000000000000000000000000000");
-        test(make_u128(100UL, 0, 0), "10000000000000000000000000000");
-        test(make_u128(1000UL, 0, 0), "100000000000000000000000000000");
-        test(make_u128(10000UL, 0, 0), "1000000000000000000000000000000");
-        test(make_u128(100000UL, 0, 0), "10000000000000000000000000000000");
-        test(make_u128(1000000UL, 0, 0), "100000000000000000000000000000000");
-        test(make_u128(10000000UL, 0, 0), "1000000000000000000000000000000000");
-        test(make_u128(100000000UL, 0, 0), "10000000000000000000000000000000000");
-        test(make_u128(1000000000UL, 0, 0), "100000000000000000000000000000000000");
-        test(make_u128(10000000000UL, 0, 0), "1000000000000000000000000000000000000");
-        test(make_u128(100000000000UL, 0, 0), "10000000000000000000000000000000000000");
-        test(make_u128(1000000000000UL, 0, 0), "100000000000000000000000000000000000000");
+        test<T>(make_u128(10UL, 0), "100000000000000000000");
+        test<T>(make_u128(100UL, 0), "1000000000000000000000");
+        test<T>(make_u128(1000UL, 0), "10000000000000000000000");
+        test<T>(make_u128(10000UL, 0), "100000000000000000000000");
+        test<T>(make_u128(100000UL, 0), "1000000000000000000000000");
+        test<T>(make_u128(1000000UL, 0), "10000000000000000000000000");
+        test<T>(make_u128(10000000UL, 0), "100000000000000000000000000");
+        test<T>(make_u128(100000000UL, 0), "1000000000000000000000000000");
+        test<T>(make_u128(100UL, 0, 0), "10000000000000000000000000000");
+        test<T>(make_u128(1000UL, 0, 0), "100000000000000000000000000000");
+        test<T>(make_u128(10000UL, 0, 0), "1000000000000000000000000000000");
+        test<T>(make_u128(100000UL, 0, 0), "10000000000000000000000000000000");
+        test<T>(make_u128(1000000UL, 0, 0), "100000000000000000000000000000000");
+        test<T>(make_u128(10000000UL, 0, 0), "1000000000000000000000000000000000");
+        test<T>(make_u128(100000000UL, 0, 0), "10000000000000000000000000000000000");
+        test<T>(make_u128(1000000000UL, 0, 0), "100000000000000000000000000000000000");
+        test<T>(make_u128(10000000000UL, 0, 0), "1000000000000000000000000000000000000");
+        test<T>(make_u128(100000000000UL, 0, 0), "10000000000000000000000000000000000000");
+        test<T>(make_u128(1000000000000UL, 0, 0), "100000000000000000000000000000000000000");
 #endif
 
         for (int b = 2; b < 37; ++b)
         {
             using xl = std::numeric_limits<T>;
 
-            test_value(1, b);
-            test_value(xl::lowest(), b);
-            test_value((xl::max)(), b);
-            test_value((xl::max)() / 2, b);
+            test_value<T>(1, b);
+            test_value<T>(xl::lowest(), b);
+            test_value<T>((xl::max)(), b);
+            test_value<T>((xl::max)() / 2, b);
         }
     }
 };
 
-template <typename T>
-struct test_signed : to_chars_test_base<T>
+struct test_signed : to_chars_test_base
 {
-    using to_chars_test_base<T>::test;
-    using to_chars_test_base<T>::test_value;
-
+    template <typename T>
     TEST_CONSTEXPR_CXX23 void operator()()
     {
-        test(-1, "-1");
-        test(-12, "-12");
-        test(-1, "-1", 10);
-        test(-12, "-12", 10);
-        test(-21734634, "-21734634", 10);
-        test(-2647, "-101001010111", 2);
-        test(-0xcc1, "-cc1", 16);
+        test<T>(-1, "-1");
+        test<T>(-12, "-12");
+        test<T>(-1, "-1", 10);
+        test<T>(-12, "-12", 10);
+        test<T>(-21734634, "-21734634", 10);
+        test<T>(-2647, "-101001010111", 2);
+        test<T>(-0xcc1, "-cc1", 16);
 
         // Test each len till len of INT64_MAX = 19 because to_chars algorithm
         // makes branches based on decimal digits count in the value string
         // representation.
         // Test driver automatically skips values not fitting into source type.
-        test(-1L, "-1");
-        test(-12L, "-12");
-        test(-123L, "-123");
-        test(-1234L, "-1234");
-        test(-12345L, "-12345");
-        test(-123456L, "-123456");
-        test(-1234567L, "-1234567");
-        test(-12345678L, "-12345678");
-        test(-123456789L, "-123456789");
-        test(-1234567890L, "-1234567890");
-        test(-12345678901L, "-12345678901");
-        test(-123456789012L, "-123456789012");
-        test(-1234567890123L, "-1234567890123");
-        test(-12345678901234L, "-12345678901234");
-        test(-123456789012345L, "-123456789012345");
-        test(-1234567890123456L, "-1234567890123456");
-        test(-12345678901234567L, "-12345678901234567");
-        test(-123456789012345678L, "-123456789012345678");
-        test(-1234567890123456789L, "-1234567890123456789");
+        test<T>(-1L, "-1");
+        test<T>(-12L, "-12");
+        test<T>(-123L, "-123");
+        test<T>(-1234L, "-1234");
+        test<T>(-12345L, "-12345");
+        test<T>(-123456L, "-123456");
+        test<T>(-1234567L, "-1234567");
+        test<T>(-12345678L, "-12345678");
+        test<T>(-123456789L, "-123456789");
+        test<T>(-1234567890L, "-1234567890");
+        test<T>(-12345678901L, "-12345678901");
+        test<T>(-123456789012L, "-123456789012");
+        test<T>(-1234567890123L, "-1234567890123");
+        test<T>(-12345678901234L, "-12345678901234");
+        test<T>(-123456789012345L, "-123456789012345");
+        test<T>(-1234567890123456L, "-1234567890123456");
+        test<T>(-12345678901234567L, "-12345678901234567");
+        test<T>(-123456789012345678L, "-123456789012345678");
+        test<T>(-1234567890123456789L, "-1234567890123456789");
 #ifndef TEST_HAS_NO_INT128
-        test(make_i128(-1L, 2345678901234567890L), "-12345678901234567890");
-        test(make_i128(-12L, 3456789012345678901L), "-123456789012345678901");
-        test(make_i128(-123L, 4567890123456789012L), "-1234567890123456789012");
-        test(make_i128(-1234L, 5678901234567890123L), "-12345678901234567890123");
-        test(make_i128(-12345L, 6789012345678901234L), "-123456789012345678901234");
-        test(make_i128(-123456L, 7890123456789012345L), "-1234567890123456789012345");
-        test(make_i128(-1234567L, 8901234567890123456L), "-12345678901234567890123456");
-        test(make_i128(-12345678L, 9012345678901234567L), "-123456789012345678901234567");
-        test(make_i128(-123456789L, 123456789012345678L), "-1234567890123456789012345678");
-        test(make_i128(-1234567890L, 1234567890123456789L), "-12345678901234567890123456789");
-        test(make_i128(-123L, 4567890123456L, 7890123456789L), "-12345678901234567890123456789");
-        test(make_i128(-1234L, 5678901234567L, 8901234567890L), "-123456789012345678901234567890");
-        test(make_i128(-12345L, 6789012345678L, 9012345678901L), "-1234567890123456789012345678901");
-        test(make_i128(-123456L, 7890123456789L, 123456789012L), "-12345678901234567890123456789012");
-        test(make_i128(-1234567L, 8901234567890L, 1234567890123L), "-123456789012345678901234567890123");
-        test(make_i128(-12345678L, 9012345678901L, 2345678901234L), "-1234567890123456789012345678901234");
-        test(make_i128(-123456789L, 123456789012L, 3456789012345L), "-12345678901234567890123456789012345");
-        test(make_i128(-1234567890L, 1234567890123L, 4567890123456L), "-123456789012345678901234567890123456");
-        test(make_i128(-12345678901L, 2345678901234L, 5678901234567L), "-1234567890123456789012345678901234567");
-        test(make_i128(-123456789012L, 3456789012345L, 6789012345678L), "-12345678901234567890123456789012345678");
-        test(make_i128(-1234567890123L, 4567890123456L, 7890123456789L), "-123456789012345678901234567890123456789");
+        test<T>(make_i128(-1L, 2345678901234567890L), "-12345678901234567890");
+        test<T>(make_i128(-12L, 3456789012345678901L), "-123456789012345678901");
+        test<T>(make_i128(-123L, 4567890123456789012L), "-1234567890123456789012");
+        test<T>(make_i128(-1234L, 5678901234567890123L), "-12345678901234567890123");
+        test<T>(make_i128(-12345L, 6789012345678901234L), "-123456789012345678901234");
+        test<T>(make_i128(-123456L, 7890123456789012345L), "-1234567890123456789012345");
+        test<T>(make_i128(-1234567L, 8901234567890123456L), "-12345678901234567890123456");
+        test<T>(make_i128(-12345678L, 9012345678901234567L), "-123456789012345678901234567");
+        test<T>(make_i128(-123456789L, 123456789012345678L), "-1234567890123456789012345678");
+        test<T>(make_i128(-1234567890L, 1234567890123456789L), "-12345678901234567890123456789");
+        test<T>(make_i128(-123L, 4567890123456L, 7890123456789L), "-12345678901234567890123456789");
+        test<T>(make_i128(-1234L, 5678901234567L, 8901234567890L), "-123456789012345678901234567890");
+        test<T>(make_i128(-12345L, 6789012345678L, 9012345678901L), "-1234567890123456789012345678901");
+        test<T>(make_i128(-123456L, 7890123456789L, 123456789012L), "-12345678901234567890123456789012");
+        test<T>(make_i128(-1234567L, 8901234567890L, 1234567890123L), "-123456789012345678901234567890123");
+        test<T>(make_i128(-12345678L, 9012345678901L, 2345678901234L), "-1234567890123456789012345678901234");
+        test<T>(make_i128(-123456789L, 123456789012L, 3456789012345L), "-12345678901234567890123456789012345");
+        test<T>(make_i128(-1234567890L, 1234567890123L, 4567890123456L), "-123456789012345678901234567890123456");
+        test<T>(make_i128(-12345678901L, 2345678901234L, 5678901234567L), "-1234567890123456789012345678901234567");
+        test<T>(make_i128(-123456789012L, 3456789012345L, 6789012345678L), "-12345678901234567890123456789012345678");
+        test<T>(make_i128(-1234567890123L, 4567890123456L, 7890123456789L), "-123456789012345678901234567890123456789");
 #endif
 
         // Test special cases with zeros inside a value string representation,
         // to_chars algorithm processes them in a special way and should not
         // skip trailing zeros
         // Test driver automatically skips values not fitting into source type.
-        test(-10L, "-10");
-        test(-100L, "-100");
-        test(-1000L, "-1000");
-        test(-10000L, "-10000");
-        test(-100000L, "-100000");
-        test(-1000000L, "-1000000");
-        test(-10000000L, "-10000000");
-        test(-100000000L, "-100000000");
-        test(-1000000000L, "-1000000000");
-        test(-10000000000L, "-10000000000");
-        test(-100000000000L, "-100000000000");
-        test(-1000000000000L, "-1000000000000");
-        test(-10000000000000L, "-10000000000000");
-        test(-100000000000000L, "-100000000000000");
-        test(-1000000000000000L, "-1000000000000000");
-        test(-10000000000000000L, "-10000000000000000");
-        test(-100000000000000000L, "-100000000000000000");
-        test(-1000000000000000000L, "-1000000000000000000");
+        test<T>(-10L, "-10");
+        test<T>(-100L, "-100");
+        test<T>(-1000L, "-1000");
+        test<T>(-10000L, "-10000");
+        test<T>(-100000L, "-100000");
+        test<T>(-1000000L, "-1000000");
+        test<T>(-10000000L, "-10000000");
+        test<T>(-100000000L, "-100000000");
+        test<T>(-1000000000L, "-1000000000");
+        test<T>(-10000000000L, "-10000000000");
+        test<T>(-100000000000L, "-100000000000");
+        test<T>(-1000000000000L, "-1000000000000");
+        test<T>(-10000000000000L, "-10000000000000");
+        test<T>(-100000000000000L, "-100000000000000");
+        test<T>(-1000000000000000L, "-1000000000000000");
+        test<T>(-10000000000000000L, "-10000000000000000");
+        test<T>(-100000000000000000L, "-100000000000000000");
+        test<T>(-1000000000000000000L, "-1000000000000000000");
 #ifndef TEST_HAS_NO_INT128
-        test(make_i128(-1L, 0L), "-10000000000000000000");
-        test(make_i128(-10L, 0L), "-100000000000000000000");
-        test(make_i128(-100L, 0L), "-1000000000000000000000");
-        test(make_i128(-1000L, 0L), "-10000000000000000000000");
-        test(make_i128(-10000L, 0L), "-100000000000000000000000");
-        test(make_i128(-100000L, 0L), "-1000000000000000000000000");
-        test(make_i128(-1000000L, 0L), "-10000000000000000000000000");
-        test(make_i128(-10000000L, 0L), "-100000000000000000000000000");
-        test(make_i128(-100000000L, 0L), "-1000000000000000000000000000");
-        test(make_i128(-1000000000L, 0L), "-10000000000000000000000000000");
-        test(make_i128(-100L, 0L, 0L), "-10000000000000000000000000000");
-        test(make_i128(-1000L, 0L, 0L), "-100000000000000000000000000000");
-        test(make_i128(-10000L, 0L, 0L), "-1000000000000000000000000000000");
-        test(make_i128(-100000L, 0L, 0L), "-10000000000000000000000000000000");
-        test(make_i128(-1000000L, 0L, 0L), "-100000000000000000000000000000000");
-        test(make_i128(-10000000L, 0L, 0L), "-1000000000000000000000000000000000");
-        test(make_i128(-100000000L, 0L, 0L), "-10000000000000000000000000000000000");
-        test(make_i128(-1000000000L, 0L, 0L), "-100000000000000000000000000000000000");
-        test(make_i128(-10000000000L, 0L, 0L), "-1000000000000000000000000000000000000");
-        test(make_i128(-100000000000L, 0L, 0L), "-10000000000000000000000000000000000000");
-        test(make_i128(-1000000000000L, 0L, 0L), "-100000000000000000000000000000000000000");
+        test<T>(make_i128(-1L, 0L), "-10000000000000000000");
+        test<T>(make_i128(-10L, 0L), "-100000000000000000000");
+        test<T>(make_i128(-100L, 0L), "-1000000000000000000000");
+        test<T>(make_i128(-1000L, 0L), "-10000000000000000000000");
+        test<T>(make_i128(-10000L, 0L), "-100000000000000000000000");
+        test<T>(make_i128(-100000L, 0L), "-1000000000000000000000000");
+        test<T>(make_i128(-1000000L, 0L), "-10000000000000000000000000");
+        test<T>(make_i128(-10000000L, 0L), "-100000000000000000000000000");
+        test<T>(make_i128(-100000000L, 0L), "-1000000000000000000000000000");
+        test<T>(make_i128(-1000000000L, 0L), "-10000000000000000000000000000");
+        test<T>(make_i128(-100L, 0L, 0L), "-10000000000000000000000000000");
+        test<T>(make_i128(-1000L, 0L, 0L), "-100000000000000000000000000000");
+        test<T>(make_i128(-10000L, 0L, 0L), "-1000000000000000000000000000000");
+        test<T>(make_i128(-100000L, 0L, 0L), "-10000000000000000000000000000000");
+        test<T>(make_i128(-1000000L, 0L, 0L), "-100000000000000000000000000000000");
+        test<T>(make_i128(-10000000L, 0L, 0L), "-1000000000000000000000000000000000");
+        test<T>(make_i128(-100000000L, 0L, 0L), "-10000000000000000000000000000000000");
+        test<T>(make_i128(-1000000000L, 0L, 0L), "-100000000000000000000000000000000000");
+        test<T>(make_i128(-10000000000L, 0L, 0L), "-1000000000000000000000000000000000000");
+        test<T>(make_i128(-100000000000L, 0L, 0L), "-10000000000000000000000000000000000000");
+        test<T>(make_i128(-1000000000000L, 0L, 0L), "-100000000000000000000000000000000000000");
 #endif
 
         for (int b = 2; b < 37; ++b)
         {
             using xl = std::numeric_limits<T>;
 
-            test_value(0, b);
-            test_value(xl::lowest(), b);
-            test_value((xl::max)(), b);
+            test_value<T>(0, b);
+            test_value<T>(xl::lowest(), b);
+            test_value<T>((xl::max)(), b);
         }
     }
 };
 
 TEST_CONSTEXPR_CXX23 bool test()
 {
-    run<test_basics>(integrals);
-    run<test_signed>(all_signed);
+    types::for_each(integrals(), test_basics());
+    types::for_each(types::signed_integer_types(), test_signed());
 
     return true;
 }

diff  --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h
index fcae09478457b6..3d163322a6f4f5 100644
--- a/libcxx/test/support/charconv_test_helpers.h
+++ b/libcxx/test/support/charconv_test_helpers.h
@@ -21,6 +21,7 @@
 #include <type_traits>
 
 #include "test_macros.h"
+#include "type_algorithms.h"
 
 #if TEST_STD_VER < 11
 #error This file requires C++11
@@ -78,10 +79,9 @@ fits_in(T v)
   return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(), std::is_signed<X>());
 }
 
-template <typename X>
 struct to_chars_test_base
 {
-    template <typename T, std::size_t N, typename... Ts>
+    template <typename X, typename T, std::size_t N, typename... Ts>
     TEST_CONSTEXPR_CXX23 void test(T v, char const (&expect)[N], Ts... args)
     {
         std::to_chars_result r;
@@ -102,7 +102,7 @@ struct to_chars_test_base
         assert(std::equal(buf, buf + len, expect));
     }
 
-    template <typename... Ts>
+    template <typename X, typename... Ts>
     TEST_CONSTEXPR_CXX23 void test_value(X v, Ts... args)
     {
         std::to_chars_result r;
@@ -119,12 +119,12 @@ struct to_chars_test_base
 
 #ifndef TEST_HAS_NO_INT128
         if (sizeof(X) == sizeof(__int128_t)) {
-            auto a = fromchars128_impl(buf, r.ptr, args...);
+            auto a = fromchars128_impl<X>(buf, r.ptr, args...);
             assert(v == a);
         } else
 #endif
         {
-            auto a = fromchars_impl(buf, r.ptr, args...);
+            auto a = fromchars_impl<X>(buf, r.ptr, args...);
             assert(v == a);
         }
 
@@ -202,6 +202,7 @@ struct to_chars_test_base
         return r;
     }
 
+    template <typename X>
     static TEST_CONSTEXPR_CXX23 auto fromchars128_impl(char const* p, char const* ep, int base = 10)
     -> decltype(fromchars128_impl(p, ep, base, std::is_signed<X>()))
     {
@@ -210,6 +211,7 @@ struct to_chars_test_base
 
 #endif
 
+    template <typename X>
     static TEST_CONSTEXPR_CXX23 auto fromchars_impl(char const* p, char const* ep, int base = 10)
     -> decltype(fromchars_impl(p, ep, base, std::is_signed<X>()))
     {
@@ -219,10 +221,9 @@ struct to_chars_test_base
     char buf[150];
 };
 
-template <typename X>
 struct roundtrip_test_base
 {
-    template <typename T, typename... Ts>
+    template <typename X, typename T, typename... Ts>
     TEST_CONSTEXPR_CXX23 void test(T v, Ts... args)
     {
         std::from_chars_result r2;
@@ -269,62 +270,7 @@ struct roundtrip_test_base
     char buf[150];
 };
 
-template <typename... T>
-struct type_list
-{
-};
-
-template <typename L1, typename L2>
-struct type_concat;
-
-template <typename... Xs, typename... Ys>
-struct type_concat<type_list<Xs...>, type_list<Ys...>>
-{
-    using type = type_list<Xs..., Ys...>;
-};
-
-template <typename L1, typename L2>
-using concat_t = typename type_concat<L1, L2>::type;
-
-template <typename L1, typename L2>
-constexpr auto concat(L1, L2) -> concat_t<L1, L2>
-{
-    return {};
-}
-
-auto all_signed = type_list<
-    char,
-    signed char,
-    short,
-    int,
-    long,
-    long long
-#ifndef TEST_HAS_NO_INT128
-    ,
-    __int128_t
-#endif
-    >();
-auto all_unsigned = type_list<
-    unsigned char,
-    unsigned short,
-    unsigned int,
-    unsigned long,
-    unsigned long long
-#ifndef TEST_HAS_NO_INT128
-    ,
-    __uint128_t
-#endif
-    >();
-auto integrals = concat(all_signed, all_unsigned);
-
-auto all_floats = type_list< float, double >(); //TODO: Add long double
-
-template <template <typename> class Fn, typename... Ts>
-TEST_CONSTEXPR_CXX23 void
-run(type_list<Ts...>)
-{
-    int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};
-    (void)ls;
-}
+using integrals =
+    types::concatenate_t<types::type_list<char>, types::signed_integer_types, types::unsigned_integer_types>;
 
 #endif // SUPPORT_CHARCONV_TEST_HELPERS_H


        


More information about the libcxx-commits mailing list