As Casey pointed out, our operator- overloads for reverse_iterator and move_iterator are not conforming. For reverse_iterator the overload taking a single template argument is not SFINAE friendly, and for move_iterator it enables some expressions that aren't supposed to be valid.
This removes the problematic operator- overloads for C++11 and later. Anyone writing a greedy operator- in their own namespace should constrain it to be less greedy. (This matches what libc++ implements, and they don't seem to have a problem with it). Because the synopsis of <iterator> is so different in each standard I've added multiple testcases for it. PR libstdc++/71771 * include/bits/stl_iterator.h (operator-(reverse_iterator<Iter>, reverse_iterator<Iter>): Only define for C++98 mode. (operator-(move_iterator<Iter>, move_iterator<Iter>): Don't define. * testsuite/24_iterators/headers/iterator/synopsis.cc: Use -std=gnu++98. * testsuite/24_iterators/headers/iterator/synopsis_c++11.cc: New test. * testsuite/24_iterators/headers/iterator/synopsis_c++14.cc: New test. * testsuite/24_iterators/headers/iterator/synopsis_c++17.cc: New test. * testsuite/24_iterators/move_iterator/greedy_ops.cc: Don't test difference operator. * testsuite/24_iterators/reverse_iterator/greedy_ops.cc: Only test difference operator for C++98. * testsuite/24_iterators/reverse_iterator/71771.cc: New test. Tested powerpc64le-linux, committed to trunk.
commit 52f7505b75b76bf60c431d5deeca297f9614a1e8 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Aug 23 00:17:46 2016 +0100 Implement resolution of LWG DR 685 precisely PR libstdc++/71771 * include/bits/stl_iterator.h (operator-(reverse_iterator<Iter>, reverse_iterator<Iter>): Only define for C++98 mode. (operator-(move_iterator<Iter>, move_iterator<Iter>): Don't define. * testsuite/24_iterators/headers/iterator/synopsis.cc: Use -std=gnu++98. * testsuite/24_iterators/headers/iterator/synopsis_c++11.cc: New test. * testsuite/24_iterators/headers/iterator/synopsis_c++14.cc: New test. * testsuite/24_iterators/headers/iterator/synopsis_c++17.cc: New test. * testsuite/24_iterators/move_iterator/greedy_ops.cc: Don't test difference operator. * testsuite/24_iterators/reverse_iterator/greedy_ops.cc: Only test difference operator for C++98. * testsuite/24_iterators/reverse_iterator/71771.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 037e966..a98fff1 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -330,19 +330,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const reverse_iterator<_Iterator>& __y) { return !(__x < __y); } - template<typename _Iterator> - inline _GLIBCXX17_CONSTEXPR - typename reverse_iterator<_Iterator>::difference_type - operator-(const reverse_iterator<_Iterator>& __x, - const reverse_iterator<_Iterator>& __y) - { return __y.base() - __x.base(); } - - template<typename _Iterator> - inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> - operator+(typename reverse_iterator<_Iterator>::difference_type __n, - const reverse_iterator<_Iterator>& __x) - { return reverse_iterator<_Iterator>(__x.base() - __n); } - // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 280. Comparison of reverse_iterator to const reverse_iterator. template<typename _IteratorL, typename _IteratorR> @@ -380,21 +367,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator>=(const reverse_iterator<_IteratorL>& __x, const reverse_iterator<_IteratorR>& __y) { return !(__x < __y); } + //@} + +#if __cplusplus < 201103L + template<typename _Iterator> + inline typename reverse_iterator<_Iterator>::difference_type + operator-(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __y.base() - __x.base(); } template<typename _IteratorL, typename _IteratorR> -#if __cplusplus >= 201103L - // DR 685. + inline typename reverse_iterator<_IteratorL>::difference_type + operator-(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return __y.base() - __x.base(); } +#else + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 685. reverse_iterator/move_iterator difference has invalid signatures + template<typename _IteratorL, typename _IteratorR> inline _GLIBCXX17_CONSTEXPR auto operator-(const reverse_iterator<_IteratorL>& __x, const reverse_iterator<_IteratorR>& __y) -> decltype(__y.base() - __x.base()) -#else - inline typename reverse_iterator<_IteratorL>::difference_type - operator-(const reverse_iterator<_IteratorL>& __x, - const reverse_iterator<_IteratorR>& __y) -#endif { return __y.base() - __x.base(); } - //@} +#endif + + template<typename _Iterator> + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> + operator+(typename reverse_iterator<_Iterator>::difference_type __n, + const reverse_iterator<_Iterator>& __x) + { return reverse_iterator<_Iterator>(__x.base() - __n); } #if __cplusplus >= 201103L // Same as C++14 make_reverse_iterator but used in C++03 mode too. @@ -1192,13 +1194,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __x.base() - __y.base(); } template<typename _Iterator> - inline _GLIBCXX17_CONSTEXPR auto - operator-(const move_iterator<_Iterator>& __x, - const move_iterator<_Iterator>& __y) - -> decltype(__x.base() - __y.base()) - { return __x.base() - __y.base(); } - - template<typename _Iterator> inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator> operator+(typename move_iterator<_Iterator>::difference_type __n, const move_iterator<_Iterator>& __x) diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis.cc index ed01258..35284d0 100644 --- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis.cc +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis.cc @@ -1,3 +1,4 @@ +// { dg-options "-std=gnu++98" } // { dg-do compile } // Copyright (C) 2007-2016 Free Software Foundation, Inc. diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++11.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++11.cc new file mode 100644 index 0000000..f0b620f --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++11.cc @@ -0,0 +1,165 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2016 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/>. + +#include <iterator> + +namespace std { + + // C++11 24.4.4, iterator operations: + template <class InputIterator, class Distance> + void + advance(InputIterator& i, Distance n); + + template <class InputIterator> + typename iterator_traits<InputIterator>::difference_type + distance(InputIterator first, InputIterator last); + + template<class ForwardIterator> + ForwardIterator + next(ForwardIterator x, + typename iterator_traits<ForwardIterator>::difference_type); + + template<class BidirectionalIterator> + BidirectionalIterator + prev(BidirectionalIterator x, + typename iterator_traits<BidirectionalIterator>::difference_type); + + // C++11 24.5, Iterator adaptors: + template <class Iterator> class reverse_iterator; + + template <class Iterator1, class Iterator2> + bool operator==(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator<(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator!=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator>(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator>=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator<=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + auto + operator-(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y) + -> decltype(x.base() - y.base()); + + template <class Iterator> + reverse_iterator<Iterator> + operator+(typename reverse_iterator<Iterator>::difference_type n, + const reverse_iterator<Iterator>& x); + + template <class Container> class back_insert_iterator; + + template <class Container> + back_insert_iterator<Container> back_inserter(Container& x); + + template <class Container> class front_insert_iterator; + + template <class Container> + front_insert_iterator<Container> front_inserter(Container& x); + + template <class Container> class insert_iterator; + + template <class Container, class Iterator> + insert_iterator<Container> inserter(Container& x, Iterator i); + + template <class Iterator> class move_iterator; + + template <class Iterator1, class Iterator2> + bool operator==(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator!=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator<(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator<=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator>(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + bool operator>=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + auto operator-(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y) + -> decltype(x.base() - y.base()); + + template <class Iterator> + move_iterator<Iterator> + operator+(typename move_iterator<Iterator>::difference_type, + const move_iterator<Iterator>&); + + template <class Iterator> + move_iterator<Iterator> make_move_iterator(const Iterator&); + + // 24.6, stream iterators: + template <class T, class charT, class traits, class Distance> + class istream_iterator; + + template <class T, class charT, class traits, class Distance> + bool operator==(const istream_iterator<T,charT,traits,Distance>& x, + const istream_iterator<T,charT,traits,Distance>& y); + + template <class T, class charT, class traits, class Distance> + bool operator!=(const istream_iterator<T,charT,traits,Distance>& x, + const istream_iterator<T,charT,traits,Distance>& y); + + template <class T, class charT, class traits> + class ostream_iterator; + + template<class charT, class traits> + class istreambuf_iterator; + + template <class charT, class traits> + bool + operator==(const istreambuf_iterator<charT,traits>&, + const istreambuf_iterator<charT,traits>&); + + template <class charT, class traits> + bool operator!=(const istreambuf_iterator<charT,traits>&, + const istreambuf_iterator<charT,traits>&); + + template <class charT, class traits> + class ostreambuf_iterator; +} diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++14.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++14.cc new file mode 100644 index 0000000..7f6063f --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++14.cc @@ -0,0 +1,28 @@ +// { dg-options "-std=gnu++14" } +// { dg-do compile } + +// Copyright (C) 2016 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/>. + +#include "./synopsis_c++11.cc" + +namespace std { + + // C++14 24.5, iterator adaptors: + template <class Iterator> + reverse_iterator<Iterator> make_reverse_iterator(const Iterator&); +} diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc new file mode 100644 index 0000000..c2adc40 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc @@ -0,0 +1,181 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +// Copyright (C) 2016 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/>. + +#include <iterator> + +namespace std { + + // C++17 24.4.3, iterator operations: + template <class InputIterator, class Distance> + constexpr void + advance(InputIterator& i, Distance n); + + template <class InputIterator> + constexpr typename iterator_traits<InputIterator>::difference_type + distance(InputIterator first, InputIterator last); + + template <class ForwardIterator> + constexpr ForwardIterator + next(ForwardIterator x, + typename iterator_traits<ForwardIterator>::difference_type); + + template <class BidirectionalIterator> + constexpr BidirectionalIterator + prev(BidirectionalIterator x, + typename iterator_traits<BidirectionalIterator>::difference_type); + + // C++17 24.5, iterator adaptors: + template <class Iterator> class reverse_iterator; + + template <class Iterator1, class Iterator2> + constexpr + bool operator==(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator<(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator!=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator>(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator>=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator<=(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr auto + operator-(const reverse_iterator<Iterator1>& x, + const reverse_iterator<Iterator2>& y) + -> decltype(x.base() - y.base()); + + template <class Iterator> + constexpr reverse_iterator<Iterator> + operator+(typename reverse_iterator<Iterator>::difference_type n, + const reverse_iterator<Iterator>& x); + + template <class Iterator> + constexpr reverse_iterator<Iterator> make_reverse_iterator(const Iterator&); + + template <class Container> class back_insert_iterator; + + template <class Container> + back_insert_iterator<Container> back_inserter(Container& x); + + template <class Container> class front_insert_iterator; + + template <class Container> + front_insert_iterator<Container> front_inserter(Container& x); + + template <class Container> class insert_iterator; + + template <class Container, class Iterator> + insert_iterator<Container> inserter(Container& x, Iterator i); + + template <class Iterator> class move_iterator; + + template <class Iterator1, class Iterator2> + constexpr + bool operator==(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator!=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator<(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator<=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator>(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + bool operator>=(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y); + + template <class Iterator1, class Iterator2> + constexpr + auto operator-(const move_iterator<Iterator1>& x, + const move_iterator<Iterator2>& y) + -> decltype(x.base() - y.base()); + + template <class Iterator> + constexpr move_iterator<Iterator> + operator+(typename move_iterator<Iterator>::difference_type, + const move_iterator<Iterator>&); + + template <class Iterator> + constexpr move_iterator<Iterator> make_move_iterator(const Iterator&); + + // 24.6, stream iterators: + template <class T, class charT, class traits, class Distance> + class istream_iterator; + + template <class T, class charT, class traits, class Distance> + bool operator==(const istream_iterator<T,charT,traits,Distance>& x, + const istream_iterator<T,charT,traits,Distance>& y); + + template <class T, class charT, class traits, class Distance> + bool operator!=(const istream_iterator<T,charT,traits,Distance>& x, + const istream_iterator<T,charT,traits,Distance>& y); + + template <class T, class charT, class traits> + class ostream_iterator; + + template<class charT, class traits> + class istreambuf_iterator; + + template <class charT, class traits> + bool + operator==(const istreambuf_iterator<charT,traits>&, + const istreambuf_iterator<charT,traits>&); + + template <class charT, class traits> + bool operator!=(const istreambuf_iterator<charT,traits>&, + const istreambuf_iterator<charT,traits>&); + + template <class charT, class traits> + class ostreambuf_iterator; +} diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc index 655313a..e546e19 100644 --- a/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc +++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc @@ -32,7 +32,7 @@ void test01() it <= it; it > it; it >= it; - it - it; + // it - it; // See PR libstdc++/71771 1 + it; it + 1; } diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/71771.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/71771.cc new file mode 100644 index 0000000..41b5086 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/71771.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2016 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-do compile { target c++11 } } + +#include <iterator> +#include <testsuite_iterators.h> + +// PR libstdc++/71771 + +template<typename Iter> +auto +diff2(std::reverse_iterator<Iter> it1, std::reverse_iterator<Iter> it2) +-> decltype(it1 - it2) +{ return it1 - it2; } + +template<typename Iter> +void +diff2(Iter, Iter) +{ } + +void +test01() +{ + int i[2]; + __gnu_test::test_container<int, __gnu_test::bidirectional_iterator_wrapper> + c(i); + using reverse_iterator + = std::reverse_iterator<__gnu_test::bidirectional_iterator_wrapper<int>>; + diff2(reverse_iterator(c.end()), reverse_iterator(c.begin())); +} diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc index 05aa340..1360029 100644 --- a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc @@ -31,7 +31,9 @@ void test01() it <= it; it > it; it >= it; - it - it; +#if __cplusplus < 201103L + it - it; // See PR libstdc++/71771 +#endif 1 + it; it + 1; }