On 23/08/16 11:19 +0100, Jonathan Wakely wrote:
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.
For gcc-5 and gcc-6 I'm making this smaller change that retains the non-standard overload, but constrains it so it's SFINAE-friendly. Tested x86_64-linux, committed to gcc-5-branch and gcc-6-branch.
commit 115a595a7a47462333bf0127c45b903e0ce0aca2 Author: Jonathan Wakely <[email protected]> Date: Tue Aug 23 00:59:42 2016 +0100 libstdc++/71771 constrain reverse_iterator difference op * include/bits/stl_iterator.h (operator-(reverse_iterator<Iter>, reverse_iterator<Iter>): Constrain for C++11 and later. * 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 3401cd0..17e6ff0 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -324,9 +324,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !(__x < __y); } template<typename _Iterator> +#if __cplusplus < 201103L inline typename reverse_iterator<_Iterator>::difference_type operator-(const reverse_iterator<_Iterator>& __x, const reverse_iterator<_Iterator>& __y) +#else + inline auto + operator-(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + -> decltype(__x.base() - __y.base()) +#endif { return __y.base() - __x.base(); } template<typename _Iterator> 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..1a7c963 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/71771.cc @@ -0,0 +1,43 @@ +// 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); + diff2(std::rbegin(c), std::rend(c)); +}
