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.

>
> 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
>
>

Reply via email to