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