Implement the proposed resolution from LWG 1052, which also resolves DR 2118 by avoiding taking the address in the first place.
PR libstdc++/86734 * include/bits/stl_iterator.h (reverse_iterator::operator->): Call _S_to_pointer (LWG 1052, LWG 2118). (reverse_iterator::_S_to_pointer): Define overloaded helper functions. * testsuite/24_iterators/reverse_iterator/dr1052.cc: New test. * testsuite/24_iterators/reverse_iterator/dr2188.cc: New test. Tested powerpc64le-linux, committed to trunk.
commit 7e221535ac8ad07732c1ce019dd2c8c889a95dce Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Jul 30 15:14:11 2018 +0100 PR libstdc++/86734 make reverse_iterator::operator-> more robust Implement the proposed resolution from LWG 1052, which also resolves DR 2118 by avoiding taking the address in the first place. PR libstdc++/86734 * include/bits/stl_iterator.h (reverse_iterator::operator->): Call _S_to_pointer (LWG 1052, LWG 2118). (reverse_iterator::_S_to_pointer): Define overloaded helper functions. * testsuite/24_iterators/reverse_iterator/dr1052.cc: New test. * testsuite/24_iterators/reverse_iterator/dr2188.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 0d5f20bc2c6..8562f879c16 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -122,6 +122,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ // _GLIBCXX_RESOLVE_LIB_DEFECTS // 235 No specification of default ctor for reverse_iterator + // 1012. reverse_iterator default ctor should value initialize _GLIBCXX17_CONSTEXPR reverse_iterator() : current() { } @@ -182,7 +183,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ _GLIBCXX17_CONSTEXPR pointer operator->() const - { return &(operator*()); } + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 1052. operator-> should also support smart pointers + _Iterator __tmp = current; + --__tmp; + return _S_to_pointer(__tmp); + } /** * @return @c *this @@ -286,6 +293,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX17_CONSTEXPR reference operator[](difference_type __n) const { return *(*this + __n); } + + private: + template<typename _Tp> + static _GLIBCXX17_CONSTEXPR _Tp* + _S_to_pointer(_Tp* __p) + { return __p; } + + template<typename _Tp> + static _GLIBCXX17_CONSTEXPR pointer + _S_to_pointer(_Tp __t) + { return __t.operator->(); } }; //@{ diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr1052.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr1052.cc new file mode 100644 index 00000000000..2704010a083 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr1052.cc @@ -0,0 +1,82 @@ +// Copyright (C) 2018 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 run { target c++11 } } + +// PR libstdc++/86734 +// LWG 1052. reverse_iterator::operator-> should also support smart pointers +// LWG 2775. reverse_iterator is does not compile for fancy pointers + +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + // Example 1 from LWG 1052 + + struct X { int m; }; + + static X x; + + struct IterX { + typedef std::bidirectional_iterator_tag iterator_category; + typedef X& reference; + struct pointer + { + pointer(X& v) : value(v) {} + X& value; + X* operator->() const {return &value;} + }; + typedef std::ptrdiff_t difference_type; + typedef X value_type; + // additional iterator requirements not important for this issue + + reference operator*() const { return x; } + pointer operator->() const { return pointer(x); } + IterX& operator--() {return *this;} + + }; + + std::reverse_iterator<IterX> ix; + VERIFY( &ix->m == &(*ix).m ); +} + +void +test02() +{ + // Example 2 from LWG 1052 + + struct P { + P() : first(10), second(20.0) { } + int first; + double second; + }; + P op; + std::reverse_iterator<P*> ri(&op + 1); + VERIFY( ri->first == 10 ); +} + +// N.B. Example 3 from LWG 1052 isn't expected to work, +// because a caching iterator like IterX is not a forward iterator. + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr2188.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr2188.cc new file mode 100644 index 00000000000..047334ddf24 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/dr2188.cc @@ -0,0 +1,47 @@ +// Copyright (C) 2018 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 run { target c++11 } } + +// PR libstdc++/86734 + +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + // LWG DR 2188 + // Reverse iterator does not fully support targets that overload operator& + struct X { + int val; + int* operator&() { return &val; } + const int* operator&() const { return &val; } + }; + + X x[2] = { {1}, {2} }; + std::reverse_iterator<X*> rev(x+2); + VERIFY( rev->val == 2 ); + ++rev; + VERIFY( rev->val == 1 ); +} + +int +main() +{ + test01(); +}