diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-04-21 23:43:27 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-04-21 23:46:54 +0100 |
commit | 87841658d4fa5174d1797ee0abc73b3b3f11cad4 (patch) | |
tree | 6521b688b2dcde6cafaebba2957f917bb10c959c /libstdc++-v3 | |
parent | 0e665f256b4ac8c5f78713ebd4e9378fd4ecf5a8 (diff) | |
download | gcc-87841658d4fa5174d1797ee0abc73b3b3f11cad4.zip gcc-87841658d4fa5174d1797ee0abc73b3b3f11cad4.tar.gz gcc-87841658d4fa5174d1797ee0abc73b3b3f11cad4.tar.bz2 |
libstdc++: Fix __normal_iterator comparisons for C++20
This fixes a regression introduced when I replaced __normal_iterator's
relational operators with operator<=>. If the wrapped iterator type
doesn't define operator<=> then __normal_iterator doesdn't either, which
breaks any use of fancy pointers that don't define <=>. The regression
was found when trying to build cmcstl2.
The solution is to use synth-three-way to define __normal_iterator's
spaceship operator, so that it is still defined even if the wrapped type
only supports operator<.
* include/bits/stl_iterator.h (__normal_iterator): Use synth-three-way
to define operator<=>.
* testsuite/24_iterators/normal_iterator/cmp_c++20.cc: New test.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 4 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_iterator.h | 7 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/24_iterators/normal_iterator/cmp_c++20.cc | 95 |
3 files changed, 102 insertions, 4 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4e0a02f..55df9a3 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,9 @@ 2020-04-21 Jonathan Wakely <jwakely@redhat.com> + * include/bits/stl_iterator.h (__normal_iterator): Use synth-three-way + to define operator<=>. + * testsuite/24_iterators/normal_iterator/cmp_c++20.cc: New test. + * doc/Makefile.am (xml_sources_manual): Add missing XML files. * doc/Makefile.in: Regenerate. * doc/xml/manual/status_cxx1998.xml: Refer to "this section" instead diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 5bfdce6..652f51c 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1048,12 +1048,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() == __rhs.base(); } template<typename _IteratorL, typename _IteratorR, typename _Container> - constexpr auto + constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL> operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) - noexcept(noexcept(__lhs.base() <=> __rhs.base())) - -> decltype(__lhs.base() <=> __rhs.base()) - { return __lhs.base() <=> __rhs.base(); } + noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) + { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } #else // Forward iterator requirements template<typename _IteratorL, typename _IteratorR, typename _Container> diff --git a/libstdc++-v3/testsuite/24_iterators/normal_iterator/cmp_c++20.cc b/libstdc++-v3/testsuite/24_iterators/normal_iterator/cmp_c++20.cc new file mode 100644 index 0000000..a5014e8 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/normal_iterator/cmp_c++20.cc @@ -0,0 +1,95 @@ +// 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 compile { target c++2a } } + +#include <iterator> +#include <vector> +#include <testsuite_allocator.h> + +void +test01() +{ + using V = std::vector<int>; + static_assert( std::totally_ordered<V::iterator> ); + static_assert( std::three_way_comparable<V::iterator> ); + using C = std::compare_three_way_result_t<V::iterator>; + static_assert( std::same_as<C, std::strong_ordering> ); + + static_assert( std::random_access_iterator<V::iterator> ); + static_assert( std::random_access_iterator<V::const_iterator> ); +} + +// User-defined pointer type that supports operator< but not operator<=> +template<typename T> +struct Pointer : __gnu_test::PointerBase<Pointer<T>, T> +{ + using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase; + + friend bool operator<(const Pointer& lhs, const Pointer& rhs) noexcept + { return lhs.value < rhs.value; } + + std::partial_ordering operator<=>(const Pointer&) const = delete; +}; + +// Minimal allocator using Pointer<T> +template<typename T> +struct Alloc +{ + typedef T value_type; + typedef Pointer<T> pointer; + + Alloc() = default; + template<typename U> + Alloc(const Alloc<U>&) { } + + pointer allocate(std::size_t n) + { return pointer(std::allocator<T>().allocate(n)); } + + void deallocate(pointer p, std::size_t n) + { std::allocator<T>().deallocate(p.operator->(), n); } +}; + +void +test02() +{ + using V = std::vector<int, Alloc<int>>; + static_assert( std::totally_ordered<V::iterator> ); + static_assert( std::three_way_comparable<V::iterator> ); + using C = std::compare_three_way_result_t<V::iterator>; + static_assert( std::same_as<C, std::weak_ordering> ); + + static_assert( std::random_access_iterator<V::iterator> ); + static_assert( std::random_access_iterator<V::const_iterator> ); +} + +void +test03() +{ + struct P : Pointer<int> { + bool operator<(const P&) const = delete; + }; + + struct C { + using pointer = P; + }; + + using I = __gnu_cxx::__normal_iterator<P, C>; + static_assert( ! std::totally_ordered<I> ); + static_assert( ! std::three_way_comparable<I> ); +} |