From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 108785 invoked by alias); 15 Nov 2015 21:12:59 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 108761 invoked by uid 89); 15 Nov 2015 21:12:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.6 required=5.0 tests=AWL,BAYES_20,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mail-wm0-f47.google.com Received: from mail-wm0-f47.google.com (HELO mail-wm0-f47.google.com) (74.125.82.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sun, 15 Nov 2015 21:12:54 +0000 Received: by wmvv187 with SMTP id v187so149504011wmv.1; Sun, 15 Nov 2015 13:12:51 -0800 (PST) X-Received: by 10.194.249.69 with SMTP id ys5mr37251810wjc.97.1447621971744; Sun, 15 Nov 2015 13:12:51 -0800 (PST) Received: from [192.168.0.23] (arf62-1-82-237-250-248.fbx.proxad.net. [82.237.250.248]) by smtp.googlemail.com with ESMTPSA id da10sm8077789wjb.22.2015.11.15.13.12.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 15 Nov 2015 13:12:50 -0800 (PST) Subject: Re: vector lightweight debug mode References: <55F71189.8080006@gmail.com> <20150914195038.GQ2631@redhat.com> <55F9C4F6.6030706@gmail.com> <20150916202953.GE2631@redhat.com> <55FD0F35.4010106@gmail.com> <561574BE.1060005@gmail.com> <20151007200917.GU12094@redhat.com> <561C0D3A.7010504@gmail.com> Cc: "libstdc++@gcc.gnu.org" , gcc-patches To: Jonathan Wakely From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= X-Enigmail-Draft-Status: N1110 Message-ID: <5648F551.5030404@gmail.com> Date: Sun, 15 Nov 2015 21:12:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 In-Reply-To: <561C0D3A.7010504@gmail.com> Content-Type: multipart/mixed; boundary="------------080809070202030300070803" X-SW-Source: 2015-11/txt/msg01886.txt.bz2 This is a multi-part message in MIME format. --------------080809070202030300070803 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 8bit Content-length: 4508 On 12/10/2015 21:42, François Dumont wrote: > On 07/10/2015 22:09, Jonathan Wakely wrote: >> On 07/10/15 21:38 +0200, François Dumont wrote: >>> Hi >>> >>> I completed vector assertion mode. Here is the result of the new >>> test you will find in the attached patch. >>> >>> With debug mode: >>> /home/fdt/dev/gcc/build_git/x86_64-unknown-linux-gnu/libstdc++-v3/include/debug/safe_iterator.h:375: >>> >>> Error: attempt to advance a dereferenceable (start-of-sequence) >>> iterator 2 >>> steps, which falls outside its valid range. >>> >>> Objects involved in the operation: >>> iterator @ 0x0x7fff1c346760 { >>> type = >>> __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator>> std::__cxx1998::vector > >, >>> std::__debug::vector > > (mutable iterator); >>> state = dereferenceable (start-of-sequence); >>> references sequence with type 'std::__debug::vector>> std::allocator >' @ 0x0x7fff1c3469a0 >>> } >>> XFAIL: 23_containers/vector/debug/insert8_neg.cc execution test >>> >>> >>> With assertion mode: >>> /home/fdt/dev/gcc/build_git/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/stl_vector.h:1124: >>> >>> Error: invalid insert position outside container [begin, end) range. >>> >>> Objects involved in the operation: >>> sequence "this" @ 0x0x7fff60b1f870 { >>> type = std::vector >; >>> } >>> iterator "__position" @ 0x0x7fff60b1f860 { >>> type = __gnu_cxx::__normal_iterator>> std::allocator > >; >>> } >>> XFAIL: 23_containers/vector/debug/insert8_neg.cc execution test >> I still don't like the formatted output for the lightweight mode, it >> adds a dependency on I/O support in libc, which is a problem for >> embedded systems. > I thought you just meant I/O dependency in terms of included headers. > The __glibcxx_assert also has some I/O as in case of failure it calls: > > inline void > __replacement_assert(const char* __file, int __line, > const char* __function, const char* __condition) > { > __builtin_printf("%s:%d: %s: Assertion '%s' failed.\n", __file, __line, > __function, __condition); > __builtin_abort(); > } > > but it is much more limited than the _GLIBCXX_DEBUG_VERIFY counterpart > which is calling fprintf to send to stderr. > > So ok let's limit this mode to glibcxx_assert. > >> The idea was to just add really cheap checks and abort :-( >> >> Have you compared codegen with and without assertion mode? How much >> more code is added to member functions like operator[] that must be >> inlined for good performance? Is it likely to affect inlining >> decisions? >> >> I suspect it will have a much bigger impact than if we just use >> __builtin_abort() as I made it do originally. > I think that impact on compiled code depends more on the assert > condition than on the code executed when this assertion happens to be > false. But I haven't check it and will try. > > In the attached patch I eventually: > - Move assertion macros in debug/assertions.h, it sounds like the right > place for those. > - Complete implementation of assertion checks by using __valid_range > function. All checks I can think of are now in place. I still need to > compare with google branch. > > Note that for the latter, condition is still evaluated in O(1). > __valid_range detects iterator issues without looping through them. > __valid_range, by considering iterator category, also make those macros > usable in any container. > > François > Here is a last version I think. I completed the debug light mode by adding some check on iterator ranges. Even if check are light I made some changes to make sure that internally vector is not using methods instrumented with those checks. This is to make sure checks are not done several times. Doing so also simplify normal mode especially when using insert range, there is no need to check if parameters are integers or not. I also introduce some __builtin_expect to make sure compiler will prefer the best path. I didn't manage to check result on generated code. I am pretty sure there will be an impact, you can't run more code without impact. But that is a known drawback of debug mode, light or not, we just need to minimize it. Mostly by making sure that checks are done only once. It would be great to have it for gcc 6.0. I am working on the same for other containers. François --------------080809070202030300070803 Content-Type: text/x-patch; name="vector_debug.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="vector_debug.patch" Content-length: 22001 diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 305d446..66b813d 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -63,6 +63,8 @@ #include #endif +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_CONTAINER @@ -320,7 +322,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector(const vector& __x) : _Base(__x.size(), _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())) - { this->_M_impl._M_finish = + { + this->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin(), __x.end(), this->_M_impl._M_start, _M_get_Tp_allocator()); @@ -340,7 +343,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Copy constructor with alternative allocator vector(const vector& __x, const allocator_type& __a) : _Base(__x.size(), __a) - { this->_M_impl._M_finish = + { + this->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin(), __x.end(), this->_M_impl._M_start, _M_get_Tp_allocator()); @@ -403,13 +407,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) - { _M_initialize_dispatch(__first, __last, __false_type()); } + { + __glibcxx_requires_valid_range(__first, __last); + _M_initialize_dispatch(__first, __last, __false_type()); + } #else template vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { + __glibcxx_requires_valid_range(__first, __last); + // Check whether it's an integral type. If so, it's not an iterator. typedef typename std::__is_integer<_InputIterator>::__type _Integral; _M_initialize_dispatch(__first, __last, _Integral()); @@ -470,7 +479,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector& operator=(initializer_list __l) { - this->assign(__l.begin(), __l.end()); + this->_M_assign_aux(__l.begin(), __l.end(), + random_access_iterator_tag()); return *this; } #endif @@ -506,12 +516,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typename = std::_RequireInputIter<_InputIterator>> void assign(_InputIterator __first, _InputIterator __last) - { _M_assign_dispatch(__first, __last, __false_type()); } + { + __glibcxx_requires_valid_range(__first, __last); + _M_assign_dispatch(__first, __last, __false_type()); + } #else template void assign(_InputIterator __first, _InputIterator __last) { + __glibcxx_requires_valid_range(__first, __last); + // Check whether it's an integral type. If so, it's not an iterator. typedef typename std::__is_integer<_InputIterator>::__type _Integral; _M_assign_dispatch(__first, __last, _Integral()); @@ -532,7 +547,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void assign(initializer_list __l) - { this->assign(__l.begin(), __l.end()); } + { + this->_M_assign_aux(__l.begin(), __l.end(), + random_access_iterator_tag()); + } #endif /// Get a copy of the memory allocation object. @@ -694,7 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER resize(size_type __new_size, const value_type& __x) { if (__new_size > size()) - insert(end(), __new_size - size(), __x); + _M_fill_insert(end(), __new_size - size(), __x); else if (__new_size < size()) _M_erase_at_end(this->_M_impl._M_start + __new_size); } @@ -714,7 +732,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER resize(size_type __new_size, value_type __x = value_type()) { if (__new_size > size()) - insert(end(), __new_size - size(), __x); + _M_fill_insert(end(), __new_size - size(), __x); else if (__new_size < size()) _M_erase_at_end(this->_M_impl._M_start + __new_size); } @@ -778,7 +796,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ reference operator[](size_type __n) _GLIBCXX_NOEXCEPT - { return *(this->_M_impl._M_start + __n); } + { + __glibcxx_requires_subscript(__n); + return *(this->_M_impl._M_start + __n); + } /** * @brief Subscript access to the data contained in the %vector. @@ -793,7 +814,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ const_reference operator[](size_type __n) const _GLIBCXX_NOEXCEPT - { return *(this->_M_impl._M_start + __n); } + { + __glibcxx_requires_subscript(__n); + return *(this->_M_impl._M_start + __n); + } protected: /// Safety check used only from at(). @@ -850,7 +874,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ reference front() _GLIBCXX_NOEXCEPT - { return *begin(); } + { + __glibcxx_requires_nonempty(); + return *begin(); + } /** * Returns a read-only (constant) reference to the data at the first @@ -858,7 +885,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ const_reference front() const _GLIBCXX_NOEXCEPT - { return *begin(); } + { + __glibcxx_requires_nonempty(); + return *begin(); + } /** * Returns a read/write reference to the data at the last @@ -866,7 +896,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ reference back() _GLIBCXX_NOEXCEPT - { return *(end() - 1); } + { + __glibcxx_requires_nonempty(); + return *(end() - 1); + } /** * Returns a read-only (constant) reference to the data at the @@ -874,7 +907,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ const_reference back() const _GLIBCXX_NOEXCEPT - { return *(end() - 1); } + { + __glibcxx_requires_nonempty(); + return *(end() - 1); + } // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 464. Suggestion for new member functions in standard containers. @@ -949,6 +985,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void pop_back() _GLIBCXX_NOEXCEPT { + __glibcxx_requires_nonempty(); --this->_M_impl._M_finish; _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); } @@ -968,7 +1005,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ template iterator - emplace(const_iterator __position, _Args&&... __args); + emplace(const_iterator __position, _Args&&... __args) + { + __glibcxx_requires_valid_insert_position(__position); + return _M_emplace(__position, std::forward<_Args>(__args)...); + } /** * @brief Inserts given value into %vector before specified iterator. @@ -982,7 +1023,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * used the user should consider using std::list. */ iterator - insert(const_iterator __position, const value_type& __x); + insert(const_iterator __position, const value_type& __x) #else /** * @brief Inserts given value into %vector before specified iterator. @@ -996,8 +1037,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * used the user should consider using std::list. */ iterator - insert(iterator __position, const value_type& __x); + insert(iterator __position, const value_type& __x) #endif + { + __glibcxx_requires_valid_insert_position(__position); + return _M_insert(__position, __x); + } #if __cplusplus >= 201103L /** @@ -1013,7 +1058,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ iterator insert(const_iterator __position, value_type&& __x) - { return emplace(__position, std::move(__x)); } + { + __glibcxx_requires_valid_insert_position(__position); + return _M_emplace(__position, std::move(__x)); + } /** * @brief Inserts an initializer_list into the %vector. @@ -1030,7 +1078,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ iterator insert(const_iterator __position, initializer_list __l) - { return this->insert(__position, __l.begin(), __l.end()); } + { + __glibcxx_requires_valid_insert_position(__position); + auto __offset = __position - cbegin(); + _M_range_insert(begin() + __offset, __l.begin(), __l.end(), + std::random_access_iterator_tag()); + return begin() + __offset; + } #endif #if __cplusplus >= 201103L @@ -1051,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator insert(const_iterator __position, size_type __n, const value_type& __x) { + __glibcxx_requires_valid_insert_position(__position); difference_type __offset = __position - cbegin(); _M_fill_insert(begin() + __offset, __n, __x); return begin() + __offset; @@ -1071,7 +1126,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void insert(iterator __position, size_type __n, const value_type& __x) - { _M_fill_insert(__position, __n, __x); } + { + __glibcxx_requires_valid_insert_position(__position); + _M_fill_insert(__position, __n, __x); + } #endif #if __cplusplus >= 201103L @@ -1096,6 +1154,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(const_iterator __position, _InputIterator __first, _InputIterator __last) { + __glibcxx_requires_valid_insert_position(__position); + __glibcxx_requires_valid_range(__first, __last); + difference_type __offset = __position - cbegin(); _M_insert_dispatch(begin() + __offset, __first, __last, __false_type()); @@ -1121,6 +1182,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(iterator __position, _InputIterator __first, _InputIterator __last) { + __glibcxx_requires_valid_insert_position(__position); + // Check whether it's an integral type. If so, it's not an iterator. typedef typename std::__is_integer<_InputIterator>::__type _Integral; _M_insert_dispatch(__position, __first, __last, _Integral()); @@ -1145,10 +1208,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator #if __cplusplus >= 201103L erase(const_iterator __position) - { return _M_erase(begin() + (__position - cbegin())); } + { + __glibcxx_requires_valid_erase_position(__position); + return _M_erase(begin() + (__position - cbegin())); + } #else erase(iterator __position) - { return _M_erase(__position); } + { + __glibcxx_requires_valid_erase_position(__position); + return _M_erase(__position); + } #endif /** @@ -1173,13 +1242,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L erase(const_iterator __first, const_iterator __last) { + __glibcxx_requires_valid_range(__first, __last); const auto __beg = begin(); const auto __cbeg = cbegin(); return _M_erase(__beg + (__first - __cbeg), __beg + (__last - __cbeg)); } #else erase(iterator __first, iterator __last) - { return _M_erase(__first, __last); } + { + __glibcxx_requires_valid_range(__first, __last); + return _M_erase(__first, __last); + } #endif /** @@ -1194,6 +1267,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void swap(vector& __x) _GLIBCXX_NOEXCEPT { +#if __cplusplus >= 201103L + __glibcxx_assert(_Alloc_traits::propagate_on_container_swap::value + || _M_get_Tp_allocator() == __x._M_get_Tp_allocator()); +#endif this->_M_impl._M_swap_data(__x._M_impl); _Alloc_traits::_S_on_swap(_M_get_Tp_allocator(), __x._M_get_Tp_allocator()); @@ -1353,6 +1430,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Internal insert functions follow. +#if __cplusplus >= 201103L + template + iterator + _M_emplace(const_iterator __position, _Args&&... __args); + + iterator + _M_insert(const_iterator __position, value_type&& __x) + { return _M_emplace(__position, std::move(__x)); } + + iterator + _M_insert(const_iterator __position, const value_type& __x); +#else + iterator + _M_insert(iterator __position, const value_type& __x); +#endif // Called by the range insert to implement [23.1.1]/9 @@ -1370,9 +1462,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_insert_dispatch(iterator __pos, _InputIterator __first, _InputIterator __last, __false_type) { - typedef typename std::iterator_traits<_InputIterator>:: - iterator_category _IterCategory; - _M_range_insert(__pos, __first, __last, _IterCategory()); + _M_range_insert(__pos, __first, __last, + std::__iterator_category(__first)); } // Called by the second insert_dispatch above diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 34118a4..39a5133 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -106,9 +106,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: #if __cplusplus >= 201103L - insert(const_iterator __position, const value_type& __x) + _M_insert(const_iterator __position, const value_type& __x) #else - insert(iterator __position, const value_type& __x) + _M_insert(iterator __position, const value_type& __x) #endif { const size_type __n = __position - begin(); @@ -256,7 +256,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (__first == __last) _M_erase_at_end(__cur); else - insert(end(), __first, __last); + _M_range_insert(end(), __first, __last, + std::__iterator_category(__first)); } template @@ -299,7 +300,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: - emplace(const_iterator __position, _Args&&... __args) + _M_emplace(const_iterator __position, _Args&&... __args) { const size_type __n = __position - begin(); if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage @@ -605,7 +606,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { for (; __first != __last; ++__first) { - __pos = insert(__pos, *__first); + __pos = _M_insert(__pos, *__first); ++__pos; } } diff --git a/libstdc++-v3/include/debug/assertions.h b/libstdc++-v3/include/debug/assertions.h index 9b9a48c..f40dc61 100644 --- a/libstdc++-v3/include/debug/assertions.h +++ b/libstdc++-v3/include/debug/assertions.h @@ -33,10 +33,39 @@ # define _GLIBCXX_DEBUG_ASSERT(_Condition) # define _GLIBCXX_DEBUG_PEDASSERT(_Condition) -# define _GLIBCXX_DEBUG_ONLY(_Statement) ; +# define _GLIBCXX_DEBUG_ONLY(_Statement) +#endif + +#ifndef _GLIBCXX_ASSERTIONS +# define __glibcxx_requires_non_empty_range(_First,_Last) +# define __glibcxx_requires_valid_range(_First,_Last) +# define __glibcxx_requires_valid_insert_position(_Position) +# define __glibcxx_requires_valid_erase_position(_Position) +# define __glibcxx_requires_nonempty() +# define __glibcxx_requires_subscript(_N) #else +# include + +# define __glibcxx_requires_valid_insert_position(_Position) \ + __glibcxx_check_insert2(_Position) +# define __glibcxx_requires_valid_erase_position(_Position) \ + __glibcxx_check_erase2(_Position) +# define __glibcxx_requires_subscript(_N) \ + __glibcxx_assert(__builtin_expect(_N < this->size(), true)) +# define __glibcxx_requires_non_empty_range(_First,_Last) \ + __glibcxx_check_non_empty_range(_First,_Last) +# define __glibcxx_requires_valid_range(_First,_Last) \ + __glibcxx_assert(__gnu_debug::__valid_range(_First, _Last)) +# define __glibcxx_requires_nonempty() \ + __glibcxx_assert(__builtin_expect(!this->empty(), true)) + +# include + +#endif + +#ifdef _GLIBCXX_DEBUG # define _GLIBCXX_DEBUG_ASSERT(_Condition) __glibcxx_assert(_Condition) # ifdef _GLIBCXX_DEBUG_PEDANTIC @@ -46,7 +75,6 @@ # endif # define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement - #endif #endif // _GLIBCXX_DEBUG_ASSERTIONS diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h index b5935fe..f233bc1 100644 --- a/libstdc++-v3/include/debug/debug.h +++ b/libstdc++-v3/include/debug/debug.h @@ -74,33 +74,16 @@ namespace __gnu_debug # define __glibcxx_requires_heap_pred(_First,_Last,_Pred) # define __glibcxx_requires_string(_String) # define __glibcxx_requires_string_len(_String,_Len) -# define __glibcxx_requires_subscript(_N) # define __glibcxx_requires_irreflexive(_First,_Last) # define __glibcxx_requires_irreflexive2(_First,_Last) # define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred) # define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred) -#ifdef _GLIBCXX_ASSERTIONS -// Verify that [_First, _Last) forms a non-empty iterator range. -# define __glibcxx_requires_non_empty_range(_First,_Last) \ - __glibcxx_assert(_First != _Last) -// Verify that the container is nonempty -# define __glibcxx_requires_nonempty() \ - __glibcxx_assert(! this->empty()) #else -# define __glibcxx_requires_non_empty_range(_First,_Last) -# define __glibcxx_requires_nonempty() -#endif - -#else - -# include # define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg) # define __glibcxx_requires_valid_range(_First,_Last) \ __glibcxx_check_valid_range(_First,_Last) -# define __glibcxx_requires_non_empty_range(_First,_Last) \ - __glibcxx_check_non_empty_range(_First,_Last) # define __glibcxx_requires_sorted(_First,_Last) \ __glibcxx_check_sorted(_First,_Last) # define __glibcxx_requires_sorted_pred(_First,_Last,_Pred) \ @@ -121,11 +104,9 @@ namespace __gnu_debug __glibcxx_check_heap(_First,_Last) # define __glibcxx_requires_heap_pred(_First,_Last,_Pred) \ __glibcxx_check_heap_pred(_First,_Last,_Pred) -# define __glibcxx_requires_nonempty() __glibcxx_check_nonempty() # define __glibcxx_requires_string(_String) __glibcxx_check_string(_String) # define __glibcxx_requires_string_len(_String,_Len) \ __glibcxx_check_string_len(_String,_Len) -# define __glibcxx_requires_subscript(_N) __glibcxx_check_subscript(_N) # define __glibcxx_requires_irreflexive(_First,_Last) \ __glibcxx_check_irreflexive(_First,_Last) # define __glibcxx_requires_irreflexive2(_First,_Last) \ diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h index a2db00d..b628b06 100644 --- a/libstdc++-v3/include/debug/helper_functions.h +++ b/libstdc++-v3/include/debug/helper_functions.h @@ -138,6 +138,7 @@ namespace __gnu_debug return __dist.first >= 0; } + // Can't tell so assume it is fine. return true; } diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h index c636663..f1ad40f 100644 --- a/libstdc++-v3/include/debug/macros.h +++ b/libstdc++-v3/include/debug/macros.h @@ -86,6 +86,17 @@ _GLIBCXX_DEBUG_VERIFY(_Position._M_attached_to(this), \ ._M_sequence(*this, "this") \ ._M_iterator(_Position, #_Position)) +/** The same as previous macro but when _Position is not a debug iterator. */ +#if __cplusplus >= 201103L +# define __glibcxx_check_insert2(_Position) \ + __glibcxx_assert(__gnu_debug::__valid_range(this->cbegin(), _Position) \ + && __gnu_debug::__valid_range(_Position, this->cend())) +#else +# define __glibcxx_check_insert2(_Position) \ + __glibcxx_assert(__gnu_debug::__valid_range(this->begin(), _Position) \ + && __gnu_debug::__valid_range(_Position, this->end())) +#endif + /** Verify that we can insert into *this after the iterator _Position. * Insertion into a container after a specific position requires that * the iterator be nonsingular, either dereferenceable or before-begin, @@ -152,6 +163,19 @@ _GLIBCXX_DEBUG_VERIFY(_Position._M_attached_to(this), \ ._M_sequence(*this, "this") \ ._M_iterator(_Position, #_Position)) +/** Same as above but for normal (non-debug) containers. */ +#if __cplusplus >= 201103L +# define __glibcxx_check_erase2(_Position) \ + __glibcxx_assert(__gnu_debug::__valid_range(this->cbegin(), _Position) && \ + __gnu_debug::__valid_range(_Position, this->cend()) && \ + _Position != this->cend()) +#else +# define __glibcxx_check_erase2(_Position) \ + __glibcxx_assert(__gnu_debug::__valid_range(this->begin(), _Position) && \ + __gnu_debug::__valid_range(_Position, this->end()) && \ + _Position != this->end()) +#endif + /** Verify that we can erase the element after the iterator * _Position. We can erase the element if the _Position iterator is * before a dereferenceable one and references this sequence. diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/insert8_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/insert8_neg.cc new file mode 100644 index 0000000..5d915c2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/insert8_neg.cc @@ -0,0 +1,41 @@ +// -*- C++ -*- + +// Copyright (C) 2015 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 +// . + +// { dg-options "-D_GLIBCXX_ASSERTIONS" } +// { dg-do run { xfail *-*-* } } + +#include + +#include + +void +test01() +{ + std::vector v1, v2; + + v1.push_back(0); + + v1.insert(v1.begin() + 2, v2.begin(), v2.end()); +} + +int +main() +{ + test01(); +} --------------080809070202030300070803--