From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 004553858C52; Thu, 29 Feb 2024 17:49:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 004553858C52 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1709228999; bh=e4F4JstC8rHxPpLw/fI2vfPakSGdpGsvpMKdvQ+bmJQ=; h=From:To:Subject:Date:From; b=IMGb2+TJtRax3R5bcnBdxDJZ8LGcjac2MYxJQF9NsTzejst3PVcYO/MeNhNcLtVfP zMi4S207rehxLUZIQzQc4f6hiMvDrk7zdp3YJFkGm4RLL1bh8azx0qjwMkBapZAVUR tyTxy6uFxBtAWKw1eP1BVDH7wTONmisMAWCGRpO8= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r14-9242] libstdc++: Fix conditions for using memcmp in std::lexicographical_compare_three_way [PR113960] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 2f43ad6a60adb8dd4af9a3c78dfe78597e891c9e X-Git-Newrev: f5cdda8acb06c20335855ed353ab9a441c12128a Message-Id: <20240229174959.004553858C52@sourceware.org> Date: Thu, 29 Feb 2024 17:49:58 +0000 (GMT) List-Id: https://gcc.gnu.org/g:f5cdda8acb06c20335855ed353ab9a441c12128a commit r14-9242-gf5cdda8acb06c20335855ed353ab9a441c12128a Author: Jonathan Wakely Date: Tue Feb 27 17:50:34 2024 +0000 libstdc++: Fix conditions for using memcmp in std::lexicographical_compare_three_way [PR113960] The change in r11-2981-g2f983fa69005b6 meant that std::lexicographical_compare_three_way started to use memcmp for unsigned integers on big endian targets, but for that to be valid we need the two value types to have the same size and we need to use that size to compute the length passed to memcmp. I already defined a __is_memcmp_ordered_with trait that does the right checks, std::lexicographical_compare_three_way just needs to use it. libstdc++-v3/ChangeLog: PR libstdc++/113960 * include/bits/stl_algobase.h (__is_byte_iter): Replace with ... (__memcmp_ordered_with): New concept. (lexicographical_compare_three_way): Use __memcmp_ordered_with instead of __is_byte_iter. Use correct length for memcmp. * testsuite/25_algorithms/lexicographical_compare_three_way/113960.cc: New test. Diff: --- libstdc++-v3/include/bits/stl_algobase.h | 41 ++++++++++++---------- .../lexicographical_compare_three_way/113960.cc | 15 ++++++++ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index d534e02871f..74ff42d4f39 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 - concept __is_byte_iter = contiguous_iterator<_Iter> - && __is_memcmp_ordered>::__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 + concept __memcmp_ordered_with + = (__is_memcmp_ordered_with, + 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 00000000000..d51ae1a3d50 --- /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 +#include + +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 ); +}