]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Ensure that _Utf_view is always a view.
authorTomasz Kamiński <tkaminsk@redhat.com>
Fri, 14 Nov 2025 16:43:59 +0000 (17:43 +0100)
committerTomasz Kamiński <tkaminsk@redhat.com>
Fri, 14 Nov 2025 17:27:01 +0000 (18:27 +0100)
Previously, _Utf_view accepted any input_range, including reference-to-array
types like char(&)[2], and stored it as the _M_base member. In such cases,
_Utf_view was not assignable, failing the requirements of view concept.

This patch addresses the issue by adding the ranges::view constraint to the
second template parameter of _Utf_view, and for clarity renaming it from
_Range to _View. The constructor is also adjusted to accept its argument
by value (views must be O(1) move-constructible). This prevents implicitly
generated CTAD from deducing a reference type.

This makes _Utf_view consistent with both other standard views and the
wording from P2728R8: Unicode in the Library, Part 1: UTF Transcoding [1].

The explicit CTAD from viewable_range is not defined for _Utf_view because
it depends on views::all_t, views::ref_view, and views::owning_view,
which are declared in <ranges>. Consequently, users must explicitly cast
the argument to a view or specify it as a template parameter.

[1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2728r8.html

libstdc++-v3/ChangeLog:

* include/bits/unicode.h (_Utf_view): Rename the template parameter
from _Range to _View and constrain it with ranges::view.
(_Utf_view::_Utf_view): Accept by value instead of rvalue reference.
* include/std/format (__format::__write_padded): Replace _Utf_view
over const char32_t(&)[1] with span<const char32_t, 1>.
* testsuite/ext/unicode/view.cc: Add checks if specialization
of _Utf_view satisfy view. Wrap arrays into std::span before
constructing _Utf_view.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/include/bits/unicode.h
libstdc++-v3/include/std/format
libstdc++-v3/testsuite/ext/unicode/view.cc

index 44872db4ed68a4287e98ffb46822117918b13092..09f7c2d7bfb3352305c37645e9dc7f46c00a275d 100644 (file)
@@ -695,13 +695,14 @@ namespace __unicode
        friend class _Utf_iterator;
     };
 
-  template<typename _ToFormat, ranges::input_range _Range>
+  template<typename _ToFormat, ranges::input_range _View>
+    requires ranges::view<_View>
     class _Utf_view
-    : public ranges::view_interface<_Utf_view<_ToFormat, _Range>>
+    : public ranges::view_interface<_Utf_view<_ToFormat, _View>>
     {
-      using _Iterator = _Utf_iterator<ranges::range_value_t<_Range>,
-                                     _ToFormat, ranges::iterator_t<_Range>,
-                                     ranges::sentinel_t<_Range>>;
+      using _Iterator = _Utf_iterator<ranges::range_value_t<_View>,
+                                     _ToFormat, ranges::iterator_t<_View>,
+                                     ranges::sentinel_t<_View>>;
 
       template<typename _Iter, typename _Sent>
        constexpr auto
@@ -725,11 +726,11 @@ namespace __unicode
            return _Iterator(__last, __last);
        }
 
-      _Range _M_base;
+      _View _M_base;
 
     public:
       constexpr explicit
-      _Utf_view(_Range&& __r) : _M_base(std::forward<_Range>(__r)) { }
+      _Utf_view(_View __r) : _M_base(std::move(__r)) { }
 
       constexpr auto begin()
       { return _M_begin(ranges::begin(_M_base), ranges::end(_M_base)); }
index 1102ac8f6e8ab7be23a9905d49bebf0ff59ab6b1..f64f35a202e0536db3a558547774471f272f0cb8 100644 (file)
@@ -845,7 +845,7 @@ namespace __format
          {
            // Encode fill char as multiple code units of type _CharT.
            const char32_t __arr[1]{ __fill_char };
-           _Utf_view<_CharT, const char32_t(&)[1]> __v(__arr);
+           _Utf_view<_CharT, span<const char32_t, 1>> __v(__arr);
            basic_string<_CharT> __padstr(__v.begin(), __v.end());
            __padding = __padstr;
            while (__l-- > 0)
index 40c8fcf34fb761aff80400f84416fec90aff5d22..677a21d8c1f5ae642431c8735debc91b05d1b1c9 100644 (file)
@@ -7,6 +7,10 @@
 namespace uc = std::__unicode;
 using namespace std::string_view_literals;
 
+static_assert( std::ranges::view<uc::_Utf8_view<std::string_view>> );
+static_assert( std::ranges::view<uc::_Utf16_view<std::string_view>> );
+static_assert( std::ranges::view<uc::_Utf32_view<std::string_view>> );
+
 template<std::ranges::range View>
 constexpr void
 compare(View v, std::basic_string_view<std::ranges::range_value_t<View>> s)
@@ -87,18 +91,18 @@ test_illformed_utf16()
   compare(uc::_Utf16_view(s.substr(0, 1)), r);
   compare(uc::_Utf16_view(s.substr(1, 1)), r);
   std::array s2{ s[0], s[0] };
-  compare(uc::_Utf16_view(s2), u"\uFFFD\uFFFD"sv);
+  compare(uc::_Utf16_view(std::span(s2)), u"\uFFFD\uFFFD"sv);
   std::array s3{ s[0], s[0], s[1] };
-  compare(uc::_Utf16_view(s3), u"\uFFFD\N{CLOWN FACE}"sv);
+  compare(uc::_Utf16_view(std::span(s3)), u"\uFFFD\N{CLOWN FACE}"sv);
   std::array s4{ s[1], s[0] };
-  compare(uc::_Utf16_view(s4), u"\uFFFD\uFFFD"sv);
+  compare(uc::_Utf16_view(std::span(s4)), u"\uFFFD\uFFFD"sv);
   std::array s5{ s[1], s[0], s[1] };
-  compare(uc::_Utf16_view(s5), u"\uFFFD\N{CLOWN FACE}"sv);
+  compare(uc::_Utf16_view(std::span(s5)), u"\uFFFD\N{CLOWN FACE}"sv);
 
   std::array<char16_t, 2> s6{ 0xDC00, 0xDC01 };
-  compare(uc::_Utf16_view(s6), u"\uFFFD\uFFFD"sv);
+  compare(uc::_Utf16_view(std::span(s6)), u"\uFFFD\uFFFD"sv);
   std::array<char16_t, 2> s7{ 0xD7FF, 0xDC00 };
-  compare(uc::_Utf16_view(s7), u"\uD7FF\uFFFD"sv);
+  compare(uc::_Utf16_view(std::span(s7)), u"\uD7FF\uFFFD"sv);
 }
 
 constexpr void