diff mbox series

[committed] libstdc++: Specialize std::disable_sized_sentinel_for for std::move_iterator [PR116549]

Message ID 20240903151914.2701791-1-jwakely@redhat.com
State New
Headers show
Series [committed] libstdc++: Specialize std::disable_sized_sentinel_for for std::move_iterator [PR116549] | expand

Commit Message

Jonathan Wakely Sept. 3, 2024, 3:18 p.m. UTC
Tested x86_64-linux. Pushed to trunk.

-- >8 --

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.
---
 libstdc++-v3/include/bits/stl_iterator.h      |  8 +++
 .../24_iterators/move_iterator/lwg3736.cc     | 52 +++++++++++++++++++
 2 files changed, 60 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3736.cc
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index d3823057270..20c0319f3a7 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1822,6 +1822,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return _ReturnType(__i); }
 
 #if __cplusplus > 201703L && __glibcxx_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
index 00000000000..eaf791b3089
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/lwg3736.cc
@@ -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>> );