diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index d534e02871f62f3c58d13c92cfb1d69be0a58d55..74ff42d4f393caea92116e8b0d2c59c463a9e08b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -1806,11 +1806,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #if __cpp_lib_three_way_comparison - // Iter points to a contiguous range of unsigned narrow character type - // or std::byte, suitable for comparison by memcmp. - template<typename _Iter> - concept __is_byte_iter = contiguous_iterator<_Iter> - && __is_memcmp_ordered<iter_value_t<_Iter>>::__value; + // Both iterators refer to contiguous ranges of unsigned narrow characters, + // or std::byte, or big-endian unsigned integers, suitable for comparison + // using memcmp. + template<typename _Iter1, typename _Iter2> + concept __memcmp_ordered_with + = (__is_memcmp_ordered_with<iter_value_t<_Iter1>, + iter_value_t<_Iter2>>::__value) + && contiguous_iterator<_Iter1> && contiguous_iterator<_Iter2>; // Return a struct with two members, initialized to the smaller of x and y // (or x if they compare equal) and the result of the comparison x <=> y. @@ -1860,20 +1863,20 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO if (!std::__is_constant_evaluated()) if constexpr (same_as<_Comp, __detail::_Synth3way> || same_as<_Comp, compare_three_way>) - if constexpr (__is_byte_iter<_InputIter1>) - if constexpr (__is_byte_iter<_InputIter2>) - { - const auto [__len, __lencmp] = _GLIBCXX_STD_A:: - __min_cmp(__last1 - __first1, __last2 - __first2); - if (__len) - { - const auto __c - = __builtin_memcmp(&*__first1, &*__first2, __len) <=> 0; - if (__c != 0) - return __c; - } - return __lencmp; - } + if constexpr (__memcmp_ordered_with<_InputIter1, _InputIter2>) + { + const auto [__len, __lencmp] = _GLIBCXX_STD_A:: + __min_cmp(__last1 - __first1, __last2 - __first2); + if (__len) + { + const auto __blen = __len * sizeof(*__first1); + const auto __c + = __builtin_memcmp(&*__first1, &*__first2, __blen) <=> 0; + if (__c != 0) + return __c; + } + return __lencmp; + } while (__first1 != __last1) { diff --git a/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc new file mode 100644 index 0000000000000000000000000000000000000000..d51ae1a3d50d55c739f6af79c09bbd2f25c02a99 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc @@ -0,0 +1,15 @@ +// { dg-do run { target c++20 } } + +// PR libstdc++/113960 +// std::map with std::vector as input overwrites itself with c++20, on s390x + +#include <algorithm> +#include <testsuite_hooks.h> + +int main() +{ + unsigned short a1[] { 1, 2, 3 }; + unsigned short a2[] { 1, 2, 4 }; + // Incorrect memcmp comparison for big endian targets. + VERIFY( std::lexicographical_compare_three_way(a1, a1+3, a2, a2+3) < 0 ); +}