C++17 has a 'Requires:' precondition that the two random access iterator
types have the same value type. In C++20 that is a 'Mandates:'
requirement which we must diagnose.

Although we could diagnose it in C++17, that might be a breaking change
for any users relying on it today. Also I am lazy and wanted to use
C++20's std::iter_value_t for the checks. So this only enforces the
requirement for C++20 and later.

libstdc++-v3/ChangeLog:

        * include/std/functional (boyer_moore_searcher::operator()): Add
        static_assert.
        (boyer_moore_horspool_searcher::operator()): Likewise.
        * testsuite/20_util/function_objects/121782.cc: New test.
---

I've just realised I forgot to put PR 121782 in the commit message.

Tested powerpc64le-linux. Pushed to trunk.

 libstdc++-v3/include/std/functional           | 12 ++++++++
 .../20_util/function_objects/121782.cc        | 30 +++++++++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/20_util/function_objects/121782.cc

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 5b329daf184e..bf40995659d1 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1256,6 +1256,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        operator()(_RandomAccessIterator2 __first,
                   _RandomAccessIterator2 __last) const
        {
+#ifdef __glibcxx_concepts // >= C++20
+         // Value types must be the same for hash function and predicate
+         // to give consistent results for lookup in the map.
+         static_assert(is_same_v<iter_value_t<_RAIter>,
+                                 iter_value_t<_RandomAccessIterator2>>);
+#endif
          const auto& __pred = this->_M_pred();
          auto __patlen = _M_pat_end - _M_pat;
          if (__patlen == 0)
@@ -1317,6 +1323,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator()(_RandomAccessIterator2 __first,
               _RandomAccessIterator2 __last) const
     {
+#ifdef __glibcxx_concepts // >= C++20
+      // Value types must be the same for hash function and predicate
+      // to give consistent results for lookup in the map.
+      static_assert(is_same_v<iter_value_t<_RAIter>,
+                             iter_value_t<_RandomAccessIterator2>>);
+#endif
       auto __patlen = _M_pat_end - _M_pat;
       if (__patlen == 0)
        return std::make_pair(__first, __first);
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/121782.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/121782.cc
new file mode 100644
index 000000000000..f18fb1ef25cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/121782.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++17 } }
+// libstdc++/121782
+// Missing Mandates for operator() of std::boyer_moore_[horspool]_searcher
+
+// N.B. we only enforce this for C++20 and later.
+// { dg-error "static assertion failed" "" { target c++20 } 0 }
+
+#include <algorithm>
+#include <functional>
+#include <testsuite_iterators.h>
+
+template<typename T>
+using Range = __gnu_test::random_access_container<T>;
+
+void
+test_bm(Range<char> needle, Range<unsigned char> haystack)
+{
+  std::boyer_moore_searcher s(needle.begin(), needle.end());
+  (void) std::search(haystack.begin(), haystack.end(), s); // { dg-error 
"here" "" { target c++20 } }
+  // { dg-error "'char' is not the same as 'unsigned char'" "" { target c++20 
} 0 }
+}
+
+void
+test_bmh(Range<char> needle, Range<signed char> haystack)
+{
+  std::boyer_moore_horspool_searcher s(needle.begin(), needle.end());
+  (void) std::search(haystack.begin(), haystack.end(), s); // { dg-error 
"here" "" { target c++20 } }
+  // { dg-error "'char' is not the same as 'signed char'" "" { target c++20 } 
0 }
+}
+
-- 
2.51.0

Reply via email to