Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Remove assumptions that std::array::iterator is a raw pointer #74624

Merged
merged 2 commits into from Dec 18, 2023

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Dec 6, 2023

This patch removes assumptions that std::array's iterators are raw pointers in the source code and in our test suite. While this is true right now, this doesn't have to be true and ion the future we might want to enable bounded iterators in std::array, which would require this change.

This is a pre-requisite for landing #74482

This patch removes assumptions that std::array's iterators are raw
pointers in the source code and in our test suite. While this is true
right now, this doesn't have to be true and ion the future we might
want to enable bounded iterators in std::array, which would require
this change.

This is a pre-requisite for landing llvm#74482
@ldionne ldionne requested a review from a team as a code owner December 6, 2023 16:38
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 6, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Dec 6, 2023

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

This patch removes assumptions that std::array's iterators are raw pointers in the source code and in our test suite. While this is true right now, this doesn't have to be true and ion the future we might want to enable bounded iterators in std::array, which would require this change.

This is a pre-requisite for landing #74482


Patch is 54.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/74624.diff

9 Files Affected:

  • (modified) libcxx/include/__format/buffer.h (+8-4)
  • (modified) libcxx/include/__format/formatter_integral.h (+18-14)
  • (modified) libcxx/include/__format/formatter_output.h (+22-12)
  • (modified) libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp (+3-2)
  • (modified) libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp (+8-10)
  • (modified) libcxx/test/std/containers/sequences/array/types.pass.cpp (-4)
  • (modified) libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp (+4-1)
  • (modified) libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp (+337-257)
  • (modified) libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp (+2-2)
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 8aa58d6464bbf..24608a0b1d200 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -130,8 +130,10 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
   /// A std::transform wrapper.
   ///
   /// Like @ref __copy it may need to do type conversion.
-  template <__fmt_char_type _InCharT, class _UnaryOperation>
-  _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
+  template <contiguous_iterator _Iterator,
+            class _UnaryOperation,
+            __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
+  _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
     _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
 
     size_t __n = static_cast<size_t>(__last - __first);
@@ -590,8 +592,10 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
     __size_ += __n;
   }
 
-  template <__fmt_char_type _InCharT, class _UnaryOperation>
-  _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
+  template <contiguous_iterator _Iterator,
+            class _UnaryOperation,
+            __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
+  _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
     _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
 
     size_t __n = static_cast<size_t>(__last - __first);
diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index 598decb0a95ea..93a41f9417588 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -20,6 +20,8 @@
 #include <__format/format_error.h>
 #include <__format/formatter_output.h>
 #include <__format/parser_std_format_spec.h>
+#include <__iterator/concepts.h>
+#include <__memory/pointer_traits.h>
 #include <__system_error/errc.h>
 #include <__type_traits/make_unsigned.h>
 #include <__utility/unreachable.h>
@@ -49,7 +51,8 @@ namespace __formatter {
 // Generic
 //
 
-_LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) {
   if (__negative)
     *__buf++ = '-';
   else
@@ -148,14 +151,15 @@ _LIBCPP_HIDE_FROM_ABI auto __format_char(
 // Integer
 //
 
-/** Wrapper around @ref to_chars, returning the output pointer. */
-template <integral _Tp>
-_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, int __base) {
+/** Wrapper around @ref to_chars, returning the output iterator. */
+template <contiguous_iterator _Iterator, integral _Tp>
+_LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) {
   // TODO FMT Evaluate code overhead due to not calling the internal function
   // directly. (Should be zero overhead.)
-  to_chars_result __r = std::to_chars(__first, __last, __value, __base);
+  to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base);
   _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
-  return __r.ptr;
+  auto __diff = __r.ptr - std::to_address(__first);
+  return __first + __diff;
 }
 
 /**
@@ -203,9 +207,9 @@ consteval size_t __buffer_size() noexcept
        + 1;                          // Reserve space for the sign.
 }
 
-template <class _OutIt, class _CharT>
-_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first,
-                                                              const char* __last, string&& __grouping, _CharT __sep,
+template <class _OutIt, contiguous_iterator _Iterator, class _CharT>
+_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, _Iterator __begin, _Iterator __first,
+                                                              _Iterator __last, string&& __grouping, _CharT __sep,
                                                               __format_spec::__parsed_specifications<_CharT> __specs) {
   int __size = (__first - __begin) +    // [sign][prefix]
                (__last - __first) +     // data
@@ -269,22 +273,22 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, c
 
 
 
-template <unsigned_integral _Tp, class _CharT, class _FormatContext>
+template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext>
 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
     _Tp __value,
     _FormatContext& __ctx,
     __format_spec::__parsed_specifications<_CharT> __specs,
     bool __negative,
-    char* __begin,
-    char* __end,
+    _Iterator __begin,
+    _Iterator __end,
     const char* __prefix,
     int __base) {
-  char* __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
+  _Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
   if (__specs.__std_.__alternate_form_ && __prefix)
     while (*__prefix)
       *__first++ = *__prefix++;
 
-  char* __last = __formatter::__to_buffer(__first, __end, __value, __base);
+  _Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base);
 
 #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
   if (__specs.__std_.__locale_specific_form_) {
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index 2909fcd9baf1e..6c7892d86900d 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -23,8 +23,9 @@
 #include <__format/unicode.h>
 #include <__iterator/back_insert_iterator.h>
 #include <__iterator/concepts.h>
-#include <__iterator/iterator_traits.h> // iter_value_t
+#include <__iterator/iterator_traits.h>
 #include <__memory/addressof.h>
+#include <__memory/pointer_traits.h>
 #include <__utility/move.h>
 #include <__utility/unreachable.h>
 #include <cstddef>
@@ -110,26 +111,32 @@ _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterat
   }
 }
 
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
-_LIBCPP_HIDE_FROM_ABI auto
-__copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it)
+template <contiguous_iterator _Iterator,
+          __fmt_char_type _CharT    = typename iterator_traits<_Iterator>::value_type,
+          __fmt_char_type _OutCharT = _CharT>
+_LIBCPP_HIDE_FROM_ABI auto __copy(_Iterator __first, _Iterator __last, output_iterator<const _OutCharT&> auto __out_it)
     -> decltype(__out_it) {
   return __formatter::__copy(basic_string_view{__first, __last}, std::move(__out_it));
 }
 
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
-_LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
+template <contiguous_iterator _Iterator,
+          __fmt_char_type _CharT    = typename iterator_traits<_Iterator>::value_type,
+          __fmt_char_type _OutCharT = _CharT>
+_LIBCPP_HIDE_FROM_ABI auto __copy(_Iterator __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
     -> decltype(__out_it) {
-  return __formatter::__copy(basic_string_view{__first, __n}, std::move(__out_it));
+  return __formatter::__copy(basic_string_view{std::to_address(__first), __n}, std::move(__out_it));
 }
 
 /// Transform wrapper.
 ///
 /// This uses a "mass output function" of __format::__output_buffer when possible.
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation>
+template <contiguous_iterator _Iterator,
+          __fmt_char_type _CharT    = typename iterator_traits<_Iterator>::value_type,
+          __fmt_char_type _OutCharT = _CharT,
+          class _UnaryOperation>
 _LIBCPP_HIDE_FROM_ABI auto
-__transform(const _CharT* __first,
-            const _CharT* __last,
+__transform(_Iterator __first,
+            _Iterator __last,
             output_iterator<const _OutCharT&> auto __out_it,
             _UnaryOperation __operation) -> decltype(__out_it) {
   if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
@@ -260,8 +267,11 @@ __write(_Iterator __first,
   return __formatter::__write(__first, __last, std::move(__out_it), __specs, __last - __first);
 }
 
-template <class _CharT, class _ParserCharT, class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last,
+template <contiguous_iterator _Iterator,
+          class _CharT = typename iterator_traits<_Iterator>::value_type,
+          class _ParserCharT,
+          class _UnaryOperation>
+_LIBCPP_HIDE_FROM_ABI auto __write_transformed(_Iterator __first, _Iterator __last,
                                                output_iterator<const _CharT&> auto __out_it,
                                                __format_spec::__parsed_specifications<_ParserCharT> __specs,
                                                _UnaryOperation __op) -> decltype(__out_it) {
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
index 3936edb8bd083..168fa40a243c5 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 // UNSUPPORTED: no-filesystem
 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
 
 // <print>
 
@@ -32,9 +33,9 @@ constexpr void test(std::basic_string_view<CharT> expected, std::string_view inp
   std::array<CharT, 1024> buffer;
   std::ranges::fill(buffer, CharT('*'));
 
-  CharT* out = std::__unicode::__transcode(input.begin(), input.end(), buffer.data());
+  auto out = std::__unicode::__transcode(input.begin(), input.end(), buffer.begin());
 
-  assert(std::basic_string_view<CharT>(buffer.data(), out) == expected);
+  assert(std::basic_string_view<CharT>(buffer.begin(), out) == expected);
 
   out = std::find_if(out, buffer.end(), [](CharT c) { return c != CharT('*'); });
   assert(out == buffer.end());
diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
index 3a335c44ed1e1..0de22022526a6 100644
--- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
@@ -547,24 +547,22 @@ class ConstexprIterator {
 
 #endif // TEST_STD_VER > 17
 
-template <class T, std::size_t N = 32>
+template <class T, std::size_t StorageSize = 32>
 class Input {
-  using Array = std::array<T, N>;
-
   std::size_t size_ = 0;
-  Array values_ = {};
+  T values_[StorageSize] = {};
 
 public:
-  template <std::size_t N2>
-  TEST_CONSTEXPR_CXX20 Input(std::array<T, N2> from) {
-    static_assert(N2 <= N, "");
+  template <std::size_t N>
+  TEST_CONSTEXPR_CXX20 Input(std::array<T, N> from) {
+    static_assert(N <= StorageSize, "");
 
     std::copy(from.begin(), from.end(), begin());
-    size_ = N2;
+    size_ = N;
   }
 
-  TEST_CONSTEXPR_CXX20 typename Array::iterator begin() { return values_.begin(); }
-  TEST_CONSTEXPR_CXX20 typename Array::iterator end() { return values_.begin() + size_; }
+  TEST_CONSTEXPR_CXX20 T* begin() { return values_; }
+  TEST_CONSTEXPR_CXX20 T* end() { return values_ + size_; }
   TEST_CONSTEXPR_CXX20 std::size_t size() const { return size_; }
 };
 
diff --git a/libcxx/test/std/containers/sequences/array/types.pass.cpp b/libcxx/test/std/containers/sequences/array/types.pass.cpp
index f86e008d2e8de..c509810507962 100644
--- a/libcxx/test/std/containers/sequences/array/types.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/types.pass.cpp
@@ -54,8 +54,6 @@ int main(int, char**)
         typedef std::array<T, 10> C;
         static_assert((std::is_same<C::reference, T&>::value), "");
         static_assert((std::is_same<C::const_reference, const T&>::value), "");
-        LIBCPP_STATIC_ASSERT((std::is_same<C::iterator, T*>::value), "");
-        LIBCPP_STATIC_ASSERT((std::is_same<C::const_iterator, const T*>::value), "");
         test_iterators<C>();
         static_assert((std::is_same<C::pointer, T*>::value), "");
         static_assert((std::is_same<C::const_pointer, const T*>::value), "");
@@ -76,8 +74,6 @@ int main(int, char**)
         typedef std::array<T, 0> C;
         static_assert((std::is_same<C::reference, T&>::value), "");
         static_assert((std::is_same<C::const_reference, const T&>::value), "");
-        LIBCPP_STATIC_ASSERT((std::is_same<C::iterator, T*>::value), "");
-        LIBCPP_STATIC_ASSERT((std::is_same<C::const_iterator, const T*>::value), "");
         test_iterators<C>();
         static_assert((std::is_same<C::pointer, T*>::value), "");
         static_assert((std::is_same<C::const_pointer, const T*>::value), "");
diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
index 73b13ccc34cf8..e893b5ae62874 100644
--- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
@@ -114,7 +114,10 @@ class throw_operator_minus {
   friend difference_type operator-(throw_operator_minus, throw_operator_minus) { throw 42; };
 
   friend bool operator==(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ == y.it_; }
-  friend auto operator<=>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <=> y.it_; }
+  friend bool operator<(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ < y.it_; }
+  friend bool operator>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ > y.it_; }
+  friend bool operator<=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <= y.it_; }
+  friend bool operator>=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ >= y.it_; }
 };
 
 template <class It>
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
index 87e2f9628757b..2df7834477291 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -61,7 +61,7 @@ void test(std::basic_string_view<CharT> fmt, ArithmeticT arg, std::basic_string<
 
   if (expected.empty()) {
     std::array<char, 128> buffer;
-    expected.append(buffer.begin(), std::to_chars(buffer.begin(), buffer.end(), arg).ptr);
+    expected.append(buffer.data(), std::to_chars(buffer.data(), buffer.data() + buffer.size(), arg).ptr);
   }
 
   assert(result == expected);
@@ -84,321 +84,401 @@ void test_termination_condition(StringT f, ArithmeticT arg, StringT expected = {
 
 template <class CharT, class ArithmeticT>
 void test_hex_lower_case_precision(ArithmeticT value) {
-  std::array<char, 25'000> buffer;
-  char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
-  test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
-  std::size_t size = buffer.end() - end;
-  std::fill_n(end, size, '#');
-  test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
-  test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
-  test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::fill_n(buffer.begin(), size, '0');
-  if (std::signbit(value)) {
-    buffer[0] = '-';
-    buffer[size] = '0';
+  {
+    std::array<char, 25'000> buffer;
+    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    std::size_t size = end_ptr - buffer.data();
+    auto end = buffer.begin() + size;
+    test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+    std::size_t unused = buffer.end() - end;
+    std::fill_n(end, unused, '#');
+    test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+    test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+    test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::fill_n(buffer.begin(), unused, '0');
+    if (std::signbit(value)) {
+      buffer[0] = '-';
+      buffer[unused] = '0';
+    }
+    test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
   }
-  test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
 #ifndef TEST_HAS_NO_LOCALIZATION
-  end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
-  test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
-  size = buffer.end() - end;
-  std::fill_n(end, size, '#');
-  test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
-  test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
-  test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
-  std::fill_n(buffer.begin(), size, '0');
-  if (std::signbit(value)) {
-    buffer[0] = '-';
-    buffer[size] = '0';
+  {
+    std::array<char, 25'000> buffer;
+    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    std::size_t size = end_ptr - buffer.data();
+    auto end = buffer.begin() + size;
+    test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+    std::size_t unused = buffer.end() - end;
+    std::fill_n(end, unused, '#');
+    test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+    test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+    test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+    std::fill_n(buffer.begin(), unused, '0');
+    if (std::signbit(value)) {
+      buffer[0] = '-';
+      buffer[unused] = '0';
+    }
+    test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
   }
-  test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()}...
[truncated]

Copy link

github-actions bot commented Dec 6, 2023

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 1f283a60a4bb896fa2d37ce00a3018924be82b9f 489fc76e28a2ca39fb902a1dc3f8c211d1485d5e -- libcxx/include/__format/buffer.h libcxx/include/__format/formatter_integral.h libcxx/include/__format/formatter_output.h libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp libcxx/test/std/containers/sequences/array/types.pass.cpp libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
View the diff from clang-format here.
diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index cbb3505bca..c345a28e06 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -212,9 +212,14 @@ consteval size_t __buffer_size() noexcept
 
 template <class _OutIt, contiguous_iterator _Iterator, class _CharT>
   requires same_as<char, iter_value_t<_Iterator>>
-_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, _Iterator __begin, _Iterator __first,
-                                                              _Iterator __last, string&& __grouping, _CharT __sep,
-                                                              __format_spec::__parsed_specifications<_CharT> __specs) {
+_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(
+    _OutIt __out_it,
+    _Iterator __begin,
+    _Iterator __first,
+    _Iterator __last,
+    string&& __grouping,
+    _CharT __sep,
+    __format_spec::__parsed_specifications<_CharT> __specs) {
   int __size = (__first - __begin) +    // [sign][prefix]
                (__last - __first) +     // data
                (__grouping.size() - 1); // number of separator characters
@@ -275,8 +280,6 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, _
   return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
 }
 
-
-
 template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext>
   requires same_as<char, iter_value_t<_Iterator>>
 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index 6c7892d869..9496a82485 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -134,11 +134,9 @@ template <contiguous_iterator _Iterator,
           __fmt_char_type _CharT    = typename iterator_traits<_Iterator>::value_type,
           __fmt_char_type _OutCharT = _CharT,
           class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI auto
-__transform(_Iterator __first,
-            _Iterator __last,
-            output_iterator<const _OutCharT&> auto __out_it,
-            _UnaryOperation __operation) -> decltype(__out_it) {
+_LIBCPP_HIDE_FROM_ABI auto __transform(
+    _Iterator __first, _Iterator __last, output_iterator<const _OutCharT&> auto __out_it, _UnaryOperation __operation)
+    -> decltype(__out_it) {
   if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
     __out_it.__get_container()->__transform(__first, __last, std::move(__operation));
     return __out_it;
@@ -271,10 +269,12 @@ template <contiguous_iterator _Iterator,
           class _CharT = typename iterator_traits<_Iterator>::value_type,
           class _ParserCharT,
           class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI auto __write_transformed(_Iterator __first, _Iterator __last,
-                                               output_iterator<const _CharT&> auto __out_it,
-                                               __format_spec::__parsed_specifications<_ParserCharT> __specs,
-                                               _UnaryOperation __op) -> decltype(__out_it) {
+_LIBCPP_HIDE_FROM_ABI auto __write_transformed(
+    _Iterator __first,
+    _Iterator __last,
+    output_iterator<const _CharT&> auto __out_it,
+    __format_spec::__parsed_specifications<_ParserCharT> __specs,
+    _UnaryOperation __op) -> decltype(__out_it) {
   _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range");
 
   ptrdiff_t __size = __last - __first;
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
index 2df7834477..498efd79a7 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -86,9 +86,10 @@ template <class CharT, class ArithmeticT>
 void test_hex_lower_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -100,7 +101,7 @@ void test_hex_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -109,9 +110,10 @@ void test_hex_lower_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -123,7 +125,7 @@ void test_hex_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -135,9 +137,10 @@ template <class CharT, class ArithmeticT>
 void test_hex_upper_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000A}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -150,7 +153,7 @@ void test_hex_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -159,9 +162,10 @@ void test_hex_upper_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000LA}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -174,7 +178,7 @@ void test_hex_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -186,9 +190,10 @@ template <class CharT, class ArithmeticT>
 void test_scientific_lower_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000e}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -200,7 +205,7 @@ void test_scientific_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -209,9 +214,10 @@ void test_scientific_lower_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000Le}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -223,7 +229,7 @@ void test_scientific_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -235,9 +241,10 @@ template <class CharT, class ArithmeticT>
 void test_scientific_upper_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000E}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -250,7 +257,7 @@ void test_scientific_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -259,9 +266,10 @@ void test_scientific_upper_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000LE}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -274,7 +282,7 @@ void test_scientific_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -286,9 +294,10 @@ template <class CharT, class ArithmeticT>
 void test_fixed_lower_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000f}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -300,7 +309,7 @@ void test_fixed_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -309,9 +318,10 @@ void test_fixed_lower_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -323,7 +333,7 @@ void test_fixed_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -335,9 +345,10 @@ template <class CharT, class ArithmeticT>
 void test_fixed_upper_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000F}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -350,7 +361,7 @@ void test_fixed_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -359,9 +370,10 @@ void test_fixed_upper_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000LF}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -374,7 +386,7 @@ void test_fixed_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -386,9 +398,10 @@ template <class CharT, class ArithmeticT>
 void test_general_lower_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000g}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -400,7 +413,7 @@ void test_general_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -409,9 +422,10 @@ void test_general_lower_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     test_termination_condition(STR(".20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
     std::size_t unused = buffer.end() - end;
@@ -423,7 +437,7 @@ void test_general_lower_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -435,9 +449,10 @@ template <class CharT, class ArithmeticT>
 void test_general_upper_case_precision(ArithmeticT value) {
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000G}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -450,7 +465,7 @@ void test_general_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
@@ -459,9 +474,10 @@ void test_general_upper_case_precision(ArithmeticT value) {
 #ifndef TEST_HAS_NO_LOCALIZATION
   {
     std::array<char, 25'000> buffer;
-    char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+    char* end_ptr =
+        std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
     std::size_t size = end_ptr - buffer.data();
-    auto end = buffer.begin() + size;
+    auto end         = buffer.begin() + size;
     std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
     test_termination_condition(STR(".20000LG}"), value, std::basic_string<CharT>{buffer.begin(), end});
 
@@ -474,7 +490,7 @@ void test_general_upper_case_precision(ArithmeticT value) {
     test_termination_condition(STR("#>25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
     std::fill_n(buffer.begin(), unused, '0');
     if (std::signbit(value)) {
-      buffer[0] = '-';
+      buffer[0]      = '-';
       buffer[unused] = '0';
     }
     test_termination_condition(STR("025000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
index ff5bfe0fb4..3a957a1995 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
@@ -58,8 +58,9 @@ void test(StringT expected, StringViewT fmt, PointerT arg, std::size_t offset) {
     std::array<char, 128> buffer;
     buffer[0] = CharT('0');
     buffer[1] = CharT('x');
-    expected.append(buffer.data(),
-                    std::to_chars(buffer.data() + 2, buffer.data() + buffer.size(), reinterpret_cast<std::uintptr_t>(arg), 16).ptr);
+    expected.append(
+        buffer.data(),
+        std::to_chars(buffer.data() + 2, buffer.data() + buffer.size(), reinterpret_cast<std::uintptr_t>(arg), 16).ptr);
   }
   assert(result == expected);
 }

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I like the idea not to depend one the type of std::array's iterator. I'm a bit concerned about adding more instantiations in format. I really like to avoid that when possible.

_LIBCPP_HIDE_FROM_ABI auto
__transform(const _CharT* __first,
const _CharT* __last,
__transform(_Iterator __first,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal here was to reduce the number of instantiations to _CharT == char and _CharT == wchar_t. Would it be possible to adjust the caller to keep this code unchanged?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that, but the downside is that we'd have to use std::to_address and in that case we'd be manipulating raw pointers. So if we enable OOB-checked iterators for example, we wouldn't catch OOB accesses inside std::format. Do you still want me to make the change? I can, I just wanted to expose the tradeoff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way we can do an OOB check ahead of time?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way we can do an OOB check ahead of time?

I think that might be possible, but I would approach it from the top down. So I would write this code in a generic fashion, and then I would ensure that it ends up only being called with (optionally OOB-checked) raw pointers to reduce the number of instantiations.

Also, at the end of the day, we're not instantiating this function with more unique types before/after this patch. We're just allowing the single type it's instantiated with to go from char* to array<char>::iterator seamlessly. The only additional weight we're adding is the concept constrained signature but it should only be instantiated with one iterator type regardless.

@@ -49,7 +51,8 @@ namespace __formatter {
// Generic
//

_LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) {
template <contiguous_iterator _Iterator>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These iterators should be constrained to have a char value_type the current constrains loosen these restrictions. (I'm fine with new concept contiguous_char_iterator if you prefer that.)

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@ldionne ldionne merged commit a35629c into llvm:main Dec 18, 2023
42 of 44 checks passed
@ldionne ldionne deleted the review/proof-against-array-iterators branch December 18, 2023 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants