diff options
| -rw-r--r-- | libstdc++-v3/include/bits/cpp_type_traits.h | 60 | ||||
| -rw-r--r-- | libstdc++-v3/include/bits/deque.tcc | 8 | ||||
| -rw-r--r-- | libstdc++-v3/include/bits/ranges_algo.h | 5 | ||||
| -rw-r--r-- | libstdc++-v3/include/bits/stl_algobase.h | 7 | ||||
| -rw-r--r-- | libstdc++-v3/include/std/array | 22 | ||||
| -rw-r--r-- | libstdc++-v3/testsuite/23_containers/array/comparison_operators/96851.cc | 119 | ||||
| -rw-r--r-- | libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc | 6 |
7 files changed, 200 insertions, 27 deletions
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h index 979ad9c..b48d1ad 100644 --- a/libstdc++-v3/include/bits/cpp_type_traits.h +++ b/libstdc++-v3/include/bits/cpp_type_traits.h @@ -482,6 +482,66 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) : __is_nonvolatile_trivially_copyable<_Tp> { }; + // Whether memcmp can be used to determine ordering for a type + // e.g. in std::lexicographical_compare or three-way comparisons. + // True for unsigned integer-like types where comparing each byte in turn + // as an unsigned char yields the right result. This is true for all + // unsigned integers on big endian targets, but only unsigned narrow + // character types (and std::byte) on little endian targets. + template<typename _Tp, bool _TreatAsBytes = +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + __is_integer<_Tp>::__value +#else + __is_byte<_Tp>::__value +#endif + > + struct __is_memcmp_ordered + { + static const bool __value = _Tp(-1) > _Tp(1); // is unsigned + }; + + template<typename _Tp> + struct __is_memcmp_ordered<_Tp, false> + { + static const bool __value = false; + }; + + // Whether two types can be compared using memcmp. + template<typename _Tp, typename _Up, bool = sizeof(_Tp) == sizeof(_Up)> + struct __is_memcmp_ordered_with + { + static const bool __value = __is_memcmp_ordered<_Tp>::__value + && __is_memcmp_ordered<_Up>::__value; + }; + + template<typename _Tp, typename _Up> + struct __is_memcmp_ordered_with<_Tp, _Up, false> + { + static const bool __value = false; + }; + +#if __cplusplus >= 201703L +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + // std::byte is not an integer, but it can be compared using memcmp. + template<> + struct __is_memcmp_ordered<std::byte, false> + { static constexpr bool __value = true; }; +#endif + + // std::byte can only be compared to itself, not to other types. + template<> + struct __is_memcmp_ordered_with<std::byte, std::byte, true> + { static constexpr bool __value = true; }; + + template<typename _Tp, bool _SameSize> + struct __is_memcmp_ordered_with<_Tp, std::byte, _SameSize> + { static constexpr bool __value = false; }; + + template<typename _Up, bool _SameSize> + struct __is_memcmp_ordered_with<std::byte, _Up, _SameSize> + { static constexpr bool __value = false; }; +#endif + // // Move iterator type // diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index 7d1ec86..651ae70 100644 --- a/libstdc++-v3/include/bits/deque.tcc +++ b/libstdc++-v3/include/bits/deque.tcc @@ -1269,9 +1269,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER const _Tp2* __first2, const _Tp2* __last2) { const bool __simple = - (__is_byte<_Tp1>::__value && __is_byte<_Tp2>::__value - && !__gnu_cxx::__numeric_traits<_Tp1>::__is_signed - && !__gnu_cxx::__numeric_traits<_Tp2>::__is_signed + (__is_memcmp_ordered_with<_Tp1, _Tp2>::__value && __is_pointer<_Ptr>::__value #if __cplusplus > 201703L && __cpp_lib_concepts // For C++20 iterator_traits<volatile T*>::value_type is non-volatile @@ -1327,9 +1325,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER _GLIBCXX_STD_C::_Deque_iterator<_Tp2, _Ref2, _Ptr2> __last2) { const bool __simple = - (__is_byte<_Tp1>::__value && __is_byte<_Tp2>::__value - && !__gnu_cxx::__numeric_traits<_Tp1>::__is_signed - && !__gnu_cxx::__numeric_traits<_Tp2>::__is_signed + (__is_memcmp_ordered_with<_Tp1, _Tp2>::__value && __is_pointer<_Ptr1>::__value && __is_pointer<_Ptr2>::__value #if __cplusplus > 201703L && __cpp_lib_concepts diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 94ca7b6..a553965 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -3475,10 +3475,7 @@ namespace ranges // This condition is consistent with the one in // __lexicographical_compare_aux in <bits/stl_algobase.h>. constexpr bool __use_memcmp - = (__is_byte<_ValueType1>::__value - && __is_byte<_ValueType2>::__value - && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed - && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed + = (__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value && __ptr_to_nonvolatile<_Iter1> && __ptr_to_nonvolatile<_Iter2> && (is_same_v<_Comp, ranges::less> diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index ff5b450..3e9ec32 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -1368,9 +1368,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; const bool __simple = - (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value - && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed - && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed + (__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value && __is_pointer<_II1>::__value && __is_pointer<_II2>::__value #if __cplusplus > 201703L && __cpp_lib_concepts @@ -1785,8 +1783,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO // or std::byte, suitable for comparison by memcmp. template<typename _Iter> concept __is_byte_iter = contiguous_iterator<_Iter> - && __is_byte<iter_value_t<_Iter>>::__value != 0 - && !__gnu_cxx::__numeric_traits<iter_value_t<_Iter>>::__is_signed; + && __is_memcmp_ordered<iter_value_t<_Iter>>::__value; // 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. diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index f7b0dca..3bb6f48 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -258,16 +258,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER constexpr __detail::__synth3way_t<_Tp> operator<=>(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) { - if constexpr (_Nm && __is_byte<_Tp>::__value) - return __builtin_memcmp(__a.data(), __b.data(), _Nm) <=> 0; - else +#ifdef __cpp_lib_is_constant_evaluated + if constexpr (_Nm && __is_memcmp_ordered<_Tp>::__value) + if (!std::is_constant_evaluated()) + { + constexpr size_t __n = _Nm * sizeof(_Tp); + return __builtin_memcmp(__a.data(), __b.data(), __n) <=> 0; + } +#endif + + for (size_t __i = 0; __i < _Nm; ++__i) { - for (size_t __i = 0; __i < _Nm; ++__i) - { - auto __c = __detail::__synth3way(__a[__i], __b[__i]); - if (__c != 0) - return __c; - } + auto __c = __detail::__synth3way(__a[__i], __b[__i]); + if (__c != 0) + return __c; } return strong_ordering::equal; } diff --git a/libstdc++-v3/testsuite/23_containers/array/comparison_operators/96851.cc b/libstdc++-v3/testsuite/23_containers/array/comparison_operators/96851.cc new file mode 100644 index 0000000..b2a464b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/array/comparison_operators/96851.cc @@ -0,0 +1,119 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <array> +#include <testsuite_hooks.h> + +template<typename T> +constexpr auto +cmp_array(T t) +{ + std::array<T, 2> a{ T{1}, t }; + std::array<T, 2> b{ T{1}, T{2} }; + return a <=> b; +} + +void +test01() +{ + static_assert( cmp_array((unsigned char)1) < 0 ); + static_assert( cmp_array((unsigned char)2) == 0 ); + static_assert( cmp_array((unsigned char)3) > 0 ); + + static_assert( cmp_array((signed char)-1) < 0 ); + static_assert( cmp_array((signed char)2) == 0 ); + static_assert( cmp_array((signed char)3) > 0 ); + + static_assert( cmp_array(std::byte{1}) < 0 ); + static_assert( cmp_array(std::byte{2}) == 0 ); + static_assert( cmp_array(std::byte{3}) > 0 ); + + static_assert( cmp_array((unsigned int)1) < 0 ); + static_assert( cmp_array((unsigned int)2) == 0 ); + static_assert( cmp_array((unsigned int)333) > 0 ); + static_assert( cmp_array((unsigned int)4444) > 0 ); + static_assert( cmp_array((unsigned int)55555) > 0 ); + static_assert( cmp_array((unsigned int)0x66666666) > 0 ); + + static_assert( cmp_array((signed int)-1) < 0 ); + static_assert( cmp_array((signed int)2) == 0 ); + static_assert( cmp_array((signed int)333) > 0 ); + static_assert( cmp_array((signed int)-4444) < 0 ); + static_assert( cmp_array((signed int)55555) > 0 ); + static_assert( cmp_array((signed int)-0x66666666) < 0 ); +} + +void +test02() +{ + unsigned char uc = 1; + VERIFY( cmp_array(uc) < 0 ); + uc = 2; + VERIFY( cmp_array(uc) == 0 ); + uc = 3; + VERIFY( cmp_array(uc) > 0 ); + + signed char sc = -1; + VERIFY( cmp_array(sc) < 0 ); + sc = 2; + VERIFY( cmp_array(sc) == 0 ); + sc = 3; + VERIFY( cmp_array(sc) > 0 ); + + std::byte b{1}; + VERIFY( cmp_array(b) < 0 ); + b = std::byte{2}; + VERIFY( cmp_array(b) == 0 ); + b = std::byte{3}; + VERIFY( cmp_array(b) > 0 ); + + unsigned int ui = 1; + VERIFY( cmp_array(ui) < 0 ); + ui = 2; + VERIFY( cmp_array(ui) == 0 ); + ui = 333; + VERIFY( cmp_array(ui) > 0 ); + ui = 4444; + VERIFY( cmp_array(ui) > 0 ); + ui = 555555; + VERIFY( cmp_array(ui) > 0 ); + ui = 0x66666666; + VERIFY( cmp_array(ui) > 0 ); + + signed int si = -1; + VERIFY( cmp_array(si) < 0 ); + si = 2; + VERIFY( cmp_array(si) == 0 ); + si = 333; + VERIFY( cmp_array(si) > 0 ); + si = -4444; + VERIFY( cmp_array(si) < 0 ); + si = 555555; + VERIFY( cmp_array(si) > 0 ); + si = -0x66666666; + VERIFY( cmp_array(si) < 0 ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc index 6072d07..a264031 100644 --- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc @@ -27,6 +27,6 @@ int n1 = std::get<1>(a); int n2 = std::get<1>(std::move(a)); int n3 = std::get<1>(ca); -// { dg-error "static assertion failed" "" { target *-*-* } 336 } -// { dg-error "static assertion failed" "" { target *-*-* } 345 } -// { dg-error "static assertion failed" "" { target *-*-* } 353 } +// { dg-error "static assertion failed" "" { target *-*-* } 340 } +// { dg-error "static assertion failed" "" { target *-*-* } 349 } +// { dg-error "static assertion failed" "" { target *-*-* } 357 } |
