]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Specialize std::disable_sized_sentinel_for for std::move_iterator [PR116549]
authorJonathan Wakely <jwakely@redhat.com>
Mon, 2 Sep 2024 10:29:13 +0000 (11:29 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 16 Apr 2025 17:44:29 +0000 (18:44 +0100)
LWG 3736 added a partial specialization of this variable template for
two std::move_iterator types. This is needed for the case where the
types satisfy std::sentinel_for and are subtractable, but do not model
the semantics requirements of std::sized_sentinel_for.

libstdc++-v3/ChangeLog:

PR libstdc++/116549
* include/bits/stl_iterator.h (disable_sized_sentinel_for):
Define specialization for two move_iterator types, as per LWG
3736.
* testsuite/24_iterators/move_iterator/lwg3736.cc: New test.

(cherry picked from commit 819deae0a5bee079a7d5582fafaa098c26144ae8)

libstdc++-v3/include/bits/stl_iterator.h
libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3736.cc [new file with mode: 0644]

index 2d4fc3435e19e1532f3ad4823576f7d5749fc127..2de447ce7528be6dbd3e4ab85915f2ab5f7fb827 100644 (file)
@@ -1829,6 +1829,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return _ReturnType(__i); }
 
 #if __cplusplus > 201703L && __cpp_lib_concepts
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3736.  move_iterator missing disable_sized_sentinel_for specialization
+  template<typename _Iterator1, typename _Iterator2>
+    requires (!sized_sentinel_for<_Iterator1, _Iterator2>)
+    inline constexpr bool
+    disable_sized_sentinel_for<move_iterator<_Iterator1>,
+                              move_iterator<_Iterator2>> = true;
+
   // [iterators.common] Common iterators
 
   namespace __detail
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3736.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3736.cc
new file mode 100644 (file)
index 0000000..eaf791b
--- /dev/null
@@ -0,0 +1,52 @@
+// { dg-do compile { target c++20 } }
+
+// 3736.  move_iterator missing disable_sized_sentinel_for specialization
+
+#include <iterator>
+
+template<typename Iter> using MoveIter = std::move_iterator<Iter>;
+
+using std::sized_sentinel_for;
+using std::disable_sized_sentinel_for;
+
+// These assertions always passed, even without LWG 3736:
+static_assert(sized_sentinel_for<MoveIter<int*>, MoveIter<int*>>);
+static_assert(sized_sentinel_for<MoveIter<int*>, MoveIter<const int*>>);
+static_assert(not sized_sentinel_for<MoveIter<int*>, MoveIter<long*>>);
+static_assert(not sized_sentinel_for<MoveIter<int*>, std::default_sentinel_t>);
+static_assert(not disable_sized_sentinel_for<MoveIter<int*>, MoveIter<int*>>);
+
+// These types don't satisfy sized_sentinel_for anyway (because the subtraction
+// is ill-formed) but LWG 3736 makes the variable template explicitly false:
+static_assert(disable_sized_sentinel_for<MoveIter<int*>, MoveIter<long*>>);
+
+struct Iter
+{
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = int;
+  using pointer = int*;
+  using reference = int&;
+  using difference_type = long;
+
+  Iter() = default;
+  Iter& operator++();
+  Iter operator++(int);
+  Iter& operator--();
+  Iter operator--(int);
+  reference operator*() const;
+  pointer operator->() const;
+  Iter& operator+=(difference_type);
+  Iter& operator-=(difference_type);
+  friend Iter operator+(Iter, difference_type);
+  friend Iter operator+(difference_type, Iter);
+  friend Iter operator-(Iter, difference_type);
+  friend difference_type operator-(Iter, Iter);
+  bool operator==(Iter) const;
+};
+
+// Specialize the variable template so that Iter is not its own sized sentinel:
+template<> constexpr bool std::disable_sized_sentinel_for<Iter, Iter> = true;
+static_assert( not sized_sentinel_for<Iter, Iter> );
+
+// LWG 3736 means that affects std::move_iterator<Iter> as well:
+static_assert( not sized_sentinel_for<MoveIter<Iter>, MoveIter<Iter>> );