On Mon, Sep 8, 2025 at 8:45 AM Tomasz Kaminski <tkami...@redhat.com> wrote:
> > > On Fri, Sep 5, 2025 at 10:57 PM Jonathan Wakely <jwak...@redhat.com> > wrote: > >> 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. >> > Could add a word here, on the motivation for checking that. If we allow > different > types, we may get ones for which equality is transparent, but hashes are > not equal > for equivalent object of different types. One example would be > chrono::durations, > with different Ratios. > Outside of that LGTM. > >> 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. >> --- >> >> Tested powerpc64le-linux. >> >> libstdc++-v3/include/std/functional | 8 +++++ >> .../20_util/function_objects/121782.cc | 30 +++++++++++++++++++ >> 2 files changed, 38 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..cc2f16b64b71 100644 >> --- a/libstdc++-v3/include/std/functional >> +++ b/libstdc++-v3/include/std/functional >> @@ -1256,6 +1256,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> operator()(_RandomAccessIterator2 __first, >> _RandomAccessIterator2 __last) const >> { >> +#ifdef __glibcxx_concepts // >= C++20 >> + 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 +1321,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> operator()(_RandomAccessIterator2 __first, >> _RandomAccessIterator2 __last) const >> { >> +#ifdef __glibcxx_concepts // >= C++20 >> + 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 >> >>