Okay.

Thank you!

вт, 21 июл. 2026 г. в 15:36, Jonathan Wakely <[email protected]>:

> On Tue, 21 Jul 2026 at 13:30, Jonathan Wakely <[email protected]> wrote:
> >
> > On Tue, 21 Jul 2026 at 12:42, Ян Чуркин <[email protected]> wrote:
> > >
> > > Hi.
> > >
> > > I wanted to follow up on this patch. Could you let me know whether it
> is still under consideration for merging or if the decision has been made
> not to merge it?
> >
> > I plan to merge it.
>
> The mismatch test needs a fix for C++98 compatibility though, as it uses
> 'auto'.
> The test for __cplusplus >= 201402L should use
> __cpp_lib_robust_nonmodifying_seq_ops instead.
> I'll take care of those.
>
> >
> >
> > >
> > > Thank you!
> > >
> > >
> > > пт, 26 июн. 2026 г. в 22:49, Ян Чуркин <[email protected]>:
> > >>
> > >> Thank you!
> > >>
> > >> I sent the updated patch with the code comments and copyrights
> removed. In both tests I added a note that the tested case is UB handled as
> QoI.
> > >>
> > >> пт, 26 июн. 2026 г. в 22:47, Yan Churkin <[email protected]>:
> > >>>
> > >>> std::__find_if, std::__mismatch and std::__push_heap drove their
> loops
> > >>> with a condition of the form
> > >>>
> > >>>   while (__first != __last && PREDICATE_CALL(...))
> > >>>
> > >>> If the predicate/comparator result type has an ADL-reachable
> > >>> operator&&(bool, T), overload resolution selects that user-defined
> > >>> operator&& for the loop condition.  It does not short-circuit, so the
> > >>> operand that dereferences *__first is evaluated even when
> > >>> __first == __last, dereferencing the past-the-end iterator.
> > >>>
> > >>> Such a result type does not model boolean-testable, so this is
> undefined
> > >>> behaviour and not a conformance issue.  Handle it anyway as a QoI
> > >>> extension, consistent with std::equal, std::binary_search and
> > >>> std::__partition, by forcing the predicate result to bool so the
> > >>> built-in && is used.  This has no effect on well-behaved predicates;
> the
> > >>> ranges:: versions are unaffected because their wrappers already
> return
> > >>> bool.
> > >>>
> > >>>         PR libstdc++/125981
> > >>>
> > >>> libstdc++-v3/ChangeLog:
> > >>>
> > >>>         * include/bits/stl_algobase.h (__find_if): Force the
> predicate
> > >>>         result to bool so an ADL-found, non-short-circuiting
> operator&& /
> > >>>         operator! cannot dereference the past-the-end iterator.
> > >>>         (__mismatch): Likewise for both overloads.
> > >>>         * include/bits/stl_heap.h (__push_heap): Likewise for the
> > >>>         comparator result.
> > >>>         * testsuite/25_algorithms/find_if/overloaded_logical_ops.cc:
> New test.
> > >>>         *
> testsuite/25_algorithms/mismatch/overloaded_logical_ops.cc: New test.
> > >>>
> > >>> Signed-off-by: Yan Churkin <[email protected]>
> > >>> ---
> > >>>  libstdc++-v3/include/bits/stl_algobase.h      |  6 +--
> > >>>  libstdc++-v3/include/bits/stl_heap.h          |  3 +-
> > >>>  .../find_if/overloaded_logical_ops.cc         | 50 +++++++++++++++++
> > >>>  .../mismatch/overloaded_logical_ops.cc        | 53
> +++++++++++++++++++
> > >>>  4 files changed, 108 insertions(+), 4 deletions(-)
> > >>>  create mode 100644
> libstdc++-v3/testsuite/25_algorithms/find_if/overloaded_logical_ops.cc
> > >>>  create mode 100644
> libstdc++-v3/testsuite/25_algorithms/mismatch/overloaded_logical_ops.cc
> > >>>
> > >>> diff --git a/libstdc++-v3/include/bits/stl_algobase.h
> b/libstdc++-v3/include/bits/stl_algobase.h
> > >>> index 1350736a8..33b117781 100644
> > >>> --- a/libstdc++-v3/include/bits/stl_algobase.h
> > >>> +++ b/libstdc++-v3/include/bits/stl_algobase.h
> > >>> @@ -1930,7 +1930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
> > >>>      __mismatch(_InputIterator1 __first1, _InputIterator1 __last1,
> > >>>                _InputIterator2 __first2, _BinaryPredicate
> __binary_pred)
> > >>>      {
> > >>> -      while (__first1 != __last1 && __binary_pred(*__first1,
> *__first2))
> > >>> +      while (__first1 != __last1 && bool(__binary_pred(*__first1,
> *__first2)))
> > >>>         {
> > >>>           ++__first1;
> > >>>           ++__first2;
> > >>> @@ -2011,7 +2011,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
> > >>>                _BinaryPredicate __binary_pred)
> > >>>      {
> > >>>        while (__first1 != __last1 && __first2 != __last2
> > >>> -            && __binary_pred(*__first1, *__first2))
> > >>> +            && bool(__binary_pred(*__first1, *__first2)))
> > >>>         {
> > >>>           ++__first1;
> > >>>           ++__first2;
> > >>> @@ -2097,7 +2097,7 @@ _GLIBCXX_END_NAMESPACE_ALGO
> > >>>      __find_if(_Iterator __first, _Iterator __last, _Predicate
> __pred)
> > >>>      {
> > >>>  #pragma GCC unroll 4
> > >>> -      while (__first != __last && !__pred(*__first))
> > >>> +      while (__first != __last && !bool(__pred(*__first)))
> > >>>         ++__first;
> > >>>        return __first;
> > >>>      }
> > >>> diff --git a/libstdc++-v3/include/bits/stl_heap.h
> b/libstdc++-v3/include/bits/stl_heap.h
> > >>> index 8c5c5df52..3c26e6a53 100644
> > >>> --- a/libstdc++-v3/include/bits/stl_heap.h
> > >>> +++ b/libstdc++-v3/include/bits/stl_heap.h
> > >>> @@ -143,7 +143,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > >>>                 _Compare& __comp)
> > >>>      {
> > >>>        _Distance __parent = (__holeIndex - 1) / 2;
> > >>> -      while (__holeIndex > __topIndex && __comp(*(__first +
> __parent), __value))
> > >>> +      while (__holeIndex > __topIndex
> > >>> +            && bool(__comp(*(__first + __parent), __value)))
> > >>>         {
> > >>>           *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first +
> __parent));
> > >>>           __holeIndex = __parent;
> > >>> diff --git
> a/libstdc++-v3/testsuite/25_algorithms/find_if/overloaded_logical_ops.cc
> b/libstdc++-v3/testsuite/25_algorithms/find_if/overloaded_logical_ops.cc
> > >>> new file mode 100644
> > >>> index 000000000..a26f4d557
> > >>> --- /dev/null
> > >>> +++
> b/libstdc++-v3/testsuite/25_algorithms/find_if/overloaded_logical_ops.cc
> > >>> @@ -0,0 +1,50 @@
> > >>> +// The predicate's result type does not model boolean-testable (it
> has an
> > >>> +// ADL-reachable operator&& and operator!), so this is undefined
> behaviour.
> > >>> +// libstdc++ supports it as a QoI extension: std::find_if does not
> evaluate
> > >>> +// the predicate on, or dereference, the past-the-end iterator.
> > >>> +
> > >>> +#include <algorithm>
> > >>> +#include <testsuite_hooks.h>
> > >>> +#include <testsuite_iterators.h>
> > >>> +
> > >>> +using __gnu_test::test_container;
> > >>> +using __gnu_test::forward_iterator_wrapper;
> > >>> +
> > >>> +int truth = 0;
> > >>> +
> > >>> +struct Logic
> > >>> +{
> > >>> +  Logic operator!() const { return Logic(); }
> > >>> +  operator bool() const { return truth != 0; }
> > >>> +};
> > >>> +
> > >>> +struct Value
> > >>> +{
> > >>> +  Logic operator>(Value) const { return Logic(); }
> > >>> +};
> > >>> +
> > >>> +bool operator&&(bool, Logic) { return false; }
> > >>> +
> > >>> +struct Pred
> > >>> +{
> > >>> +  Logic operator()(Value v) const { return v > v; }
> > >>> +};
> > >>> +
> > >>> +void
> > >>> +test01()
> > >>> +{
> > >>> +  Value arr[1] = { };
> > >>> +
> > >>> +  test_container<Value, forward_iterator_wrapper> empty(arr, arr);
> > >>> +  VERIFY( std::find_if(empty.begin(), empty.end(), Pred()).ptr ==
> arr );
> > >>> +
> > >>> +  test_container<Value, forward_iterator_wrapper> con(arr, arr + 1);
> > >>> +  VERIFY( std::find_if(con.begin(), con.end(), Pred()).ptr == arr +
> 1 );
> > >>> +}
> > >>> +
> > >>> +int
> > >>> +main()
> > >>> +{
> > >>> +  test01();
> > >>> +  return 0;
> > >>> +}
> > >>> diff --git
> a/libstdc++-v3/testsuite/25_algorithms/mismatch/overloaded_logical_ops.cc
> b/libstdc++-v3/testsuite/25_algorithms/mismatch/overloaded_logical_ops.cc
> > >>> new file mode 100644
> > >>> index 000000000..dd52d070b
> > >>> --- /dev/null
> > >>> +++
> b/libstdc++-v3/testsuite/25_algorithms/mismatch/overloaded_logical_ops.cc
> > >>> @@ -0,0 +1,53 @@
> > >>> +// The predicate's result type does not model boolean-testable (it
> has an
> > >>> +// ADL-reachable operator&& and operator!), so this is undefined
> behaviour.
> > >>> +// libstdc++ supports it as a QoI extension: std::mismatch does not
> evaluate
> > >>> +// the predicate on, or dereference, the past-the-end iterator.
> > >>> +
> > >>> +#include <algorithm>
> > >>> +#include <testsuite_hooks.h>
> > >>> +#include <testsuite_iterators.h>
> > >>> +
> > >>> +using __gnu_test::test_container;
> > >>> +using __gnu_test::forward_iterator_wrapper;
> > >>> +
> > >>> +int truth = 0;
> > >>> +
> > >>> +struct Logic
> > >>> +{
> > >>> +  Logic operator!() const { return Logic(); }
> > >>> +  operator bool() const { return truth != 0; }
> > >>> +};
> > >>> +
> > >>> +struct Value { };
> > >>> +
> > >>> +bool operator&&(bool, Logic) { return false; }
> > >>> +
> > >>> +struct Eq
> > >>> +{
> > >>> +  Logic operator()(Value, Value) const { return Logic(); }
> > >>> +};
> > >>> +
> > >>> +void
> > >>> +test01()
> > >>> +{
> > >>> +  Value arr[1] = { };
> > >>> +
> > >>> +  test_container<Value, forward_iterator_wrapper> empty(arr, arr);
> > >>> +  test_container<Value, forward_iterator_wrapper> other(arr, arr +
> 1);
> > >>> +  auto r = std::mismatch(empty.begin(), empty.end(), other.begin(),
> Eq());
> > >>> +  VERIFY( r.first.ptr == arr );
> > >>> +
> > >>> +#if __cplusplus >= 201402L
> > >>> +  test_container<Value, forward_iterator_wrapper> e2(arr, arr);
> > >>> +  test_container<Value, forward_iterator_wrapper> o2(arr, arr + 1);
> > >>> +  auto r2 = std::mismatch(e2.begin(), e2.end(), o2.begin(),
> o2.end(), Eq());
> > >>> +  VERIFY( r2.first.ptr == arr );
> > >>> +#endif
> > >>> +}
> > >>> +
> > >>> +int
> > >>> +main()
> > >>> +{
> > >>> +  test01();
> > >>> +  return 0;
> > >>> +}
> > >>> --
> > >>> 2.43.0
> > >>>
>
>

Reply via email to