diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fa87445..bbdad00 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2012-01-14 Jonathan Wakely + + PR libstdc++/51823 + * include/bits/stl_iterator.h (reverse_iterator): Implement DR 198, + disabling the auxiliary member for the library's own iterator types. + * testsuite/24_iterators/reverse_iterator/51823.cc: New. + * testsuite/24_iterators/reverse_iterator/51823-2.cc: New. + 2012-01-13 François Dumont * include/bits/hashtable_policy.h (_Hash_node_base): New, use it as diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 624ae64..eae1ce2 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -75,6 +75,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ + template + struct __cache_rev_iter_deref + { + static const bool __value = true; + }; + template + const bool __cache_rev_iter_deref<_Iterator>::__value; + + template + struct __cache_rev_iter_deref<_Tp*> + { + static const bool __value = false; + }; + template + const bool __cache_rev_iter_deref<_Tp*>::__value; + + template::__value> + class __reverse_iter_deref_cache + { + mutable _Iterator _M_deref_tmp; + + protected: + typename iterator_traits<_Iterator>::reference + _M_deref(_Iterator __it) const + { + _M_deref_tmp = __it; + return *--_M_deref_tmp; + } + }; + + template + class __reverse_iter_deref_cache<_Iterator, false> + { + protected: + typename iterator_traits<_Iterator>::reference + _M_deref(_Iterator __it) const + { + _Iterator __deref_tmp = __it; + return *--__deref_tmp; + } + }; + // 24.4.1 Reverse iterators /** * Bidirectional and random access iterators have corresponding reverse @@ -100,7 +143,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename iterator_traits<_Iterator>::value_type, typename iterator_traits<_Iterator>::difference_type, typename iterator_traits<_Iterator>::pointer, - typename iterator_traits<_Iterator>::reference> + typename iterator_traits<_Iterator>::reference>, + private __reverse_iter_deref_cache<_Iterator> { protected: _Iterator current; @@ -148,6 +192,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION base() const { return current; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 198 Avoid returning a reference that persists beyond the + // lifetime of its associated iterator. /** * @return TODO * @@ -155,10 +202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ reference operator*() const - { - _Iterator __tmp = current; - return *--__tmp; - } + { return this->_M_deref(current); } /** * @return TODO @@ -901,7 +945,101 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + // __normal_iterator does not need to cache the result of dereferencing + template + struct __cache_rev_iter_deref<__gnu_cxx::__normal_iterator<_Iter, _Cont> > + : __cache_rev_iter_deref<_Iter> + { }; + + // deque iterator + template struct _Deque_iterator; + + template + struct __cache_rev_iter_deref<_Deque_iterator<_Tp, _Ref, _Ptr> > + { static const bool __value = false; }; + + template + const bool + __cache_rev_iter_deref<_Deque_iterator<_Tp, _Ref, _Ptr> >::__value; + + // list iterators + template struct _List_iterator; + + template + struct __cache_rev_iter_deref<_List_iterator<_Tp> > + { static const bool __value = false; }; + + template + const bool __cache_rev_iter_deref<_List_iterator<_Tp> >::__value; + + template struct _List_const_iterator; + + template + struct __cache_rev_iter_deref<_List_const_iterator<_Tp> > + { static const bool __value = false; }; + + template + const bool __cache_rev_iter_deref<_List_const_iterator<_Tp> >::__value; + + // associative container iterators + template struct _Rb_tree_iterator; + + template + struct __cache_rev_iter_deref<_Rb_tree_iterator<_Tp> > + { static const bool __value = false; }; + + template + const bool __cache_rev_iter_deref<_Rb_tree_iterator<_Tp> >::__value; + + template struct _Rb_tree_const_iterator; + + template + struct __cache_rev_iter_deref<_Rb_tree_const_iterator<_Tp> > + { static const bool __value = false; }; + + template + const bool __cache_rev_iter_deref<_Rb_tree_const_iterator<_Tp> >::__value; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + #ifdef __GXX_EXPERIMENTAL_CXX0X__ +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace __detail +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + // unordered container iterators + template struct _Node_iterator; + template struct _Node_const_iterator; +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace __detail + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template + struct __cache_rev_iter_deref<__detail::_Node_iterator<_Value, _B1, _B2>> + { static const bool __value = false; }; + + template + const bool + __cache_rev_iter_deref<__detail::_Node_iterator<_Value, + _B1, _B2>>::__value; + + + template + struct __cache_rev_iter_deref<__detail::_Node_const_iterator<_Value, + _B1, _B2>> + { static const bool __value = false; }; + + template + const bool + __cache_rev_iter_deref<__detail::_Node_const_iterator<_Value, + _B1, _B2>>::__value; +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std namespace std _GLIBCXX_VISIBILITY(default) { @@ -1127,6 +1265,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_move_if_noexcept_iterator(_Iterator __i) { return _ReturnType(__i); } + template + struct __cache_rev_iter_deref> + : __cache_rev_iter_deref<_Iterator> + { }; + // @} group iterators _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823-2.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823-2.cc new file mode 100644 index 0000000..7d5efe2 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823-2.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2012 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 +// . + +// 24.5.1 Reverse iterators + +// DR 198. +// Validity of pointers and references unspecified after iterator destruction. + +// libstdc++/51823 + +// { do-do compile } +// { do-options "-std=gnu++11" } + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +constexpr bool test() +{ + return sizeof(T) == sizeof(std::reverse_iterator); +} + +static_assert( test(), "pointer" ); +static_assert( test(), "pointer const" ); + +static_assert( test(), "string" ); +static_assert( test(), "string const" ); + +static_assert( test::iterator>(), "array" ); +static_assert( test::const_iterator>(), "array const" ); + +static_assert( test::iterator>(), "list" ); +static_assert( test::const_iterator>(), "list const" ); + +static_assert( test::iterator>(), "deque" ); +static_assert( test::const_iterator>(), "deque const" ); + +static_assert( test::iterator>(), "vector" ); +static_assert( test::const_iterator>(), "vector const" ); + +static_assert( test::iterator>(), "map" ); +static_assert( test::const_iterator>(), "map const" ); + +static_assert( test::iterator>(), "set" ); +static_assert( test::const_iterator>(), "set const" ); + +static_assert( test::iterator>(), + "unordered_map" ); +static_assert( test::const_iterator>(), + "unordered_map const" ); + +static_assert( test::iterator>(), + "unordered_set" ); +static_assert( test::const_iterator>(), + "unordered_set const" ); + diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823.cc new file mode 100644 index 0000000..a8c733f --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/51823.cc @@ -0,0 +1,108 @@ +// Copyright (C) 2012 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 +// . + +// 24.5.1 Reverse iterators + +// DR 198. +// Validity of pointers and references unspecified after iterator destruction. + +// libstdc++/51823 + +#include +#include +#include + +struct datum +{ + unsigned use_count; +}; + +std::vector data(6); +unsigned iterator_id = 0; + +struct iterator +{ + typedef datum value_type; + typedef datum& reference; + typedef datum* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator() : id(-1) { } + iterator(unsigned id) : id(id) { data[id].use_count++; } + iterator(const iterator& i) : id(i.id) { data[id].use_count++; } + + ~iterator() { if (id < data.size()) data[id].use_count--; } + + iterator& operator=(iterator i) { swap(i); } + + reference operator*() const { return data[id]; } + pointer operator->() const { return &data[id]; } + + iterator& operator++() + { + data[id].use_count--; + ++id; + data[id].use_count++; + return *this; + } + + iterator& operator--() + { + data[id].use_count--; + --id; + data[id].use_count++; + return *this; + } + + iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } + iterator operator--(int) { iterator tmp = *this; --*this; return tmp; } + +private: + void swap(iterator& i) { std::swap(id, i.id); } + + unsigned id; +}; + +void test01() +{ + bool test __attribute__((unused)) = true; + + typedef std::reverse_iterator reverse_iterator; + + iterator it1(2); + reverse_iterator rit1(it1); + VERIFY( (*rit1).use_count != 0 ); + VERIFY( rit1->use_count != 0 ); + ++rit1; + VERIFY( (*rit1).use_count != 0 ); + VERIFY( rit1->use_count != 0 ); + + iterator it2(3); + reverse_iterator rit2(it2); + VERIFY( (*rit2).use_count != 0 ); + VERIFY( rit2->use_count != 0 ); + --rit2; + VERIFY( (*rit2).use_count != 0 ); + VERIFY( rit2->use_count != 0 ); +} + +int main() +{ + test01(); + return 0; +}