diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem --- a/libcxx/include/filesystem +++ b/libcxx/include/filesystem @@ -792,7 +792,7 @@ template static typename enable_if<__is_cpp17_forward_iterator<_Iter>::value>::type __append_range(__path_string& __dest, _Iter __b, _Iter __e) { - __dest.__append_forward_unsafe(__b, __e); + __dest.append(__b, __e); } template diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -1938,23 +1938,6 @@ return __x; } -template -struct __libcpp_is_trivial_iterator - : public _LIBCPP_BOOL_CONSTANT(is_pointer<_Iter>::value) {}; - -template -struct __libcpp_is_trivial_iterator > - : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {}; - -template -struct __libcpp_is_trivial_iterator > - : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {}; - -template -struct __libcpp_is_trivial_iterator<__wrap_iter<_Iter> > - : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {}; - - template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Tp* diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -632,29 +632,16 @@ _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __basic_string_common) -#ifdef _LIBCPP_NO_EXCEPTIONS template -struct __libcpp_string_gets_noexcept_iterator_impl : public true_type {}; -#elif defined(_LIBCPP_HAS_NO_NOEXCEPT) -template -struct __libcpp_string_gets_noexcept_iterator_impl : public false_type {}; -#else -template ::value> -struct __libcpp_string_gets_noexcept_iterator_impl : public _LIBCPP_BOOL_CONSTANT(( - noexcept(++(declval<_Iter&>())) && - is_nothrow_assignable<_Iter&, _Iter>::value && - noexcept(declval<_Iter>() == declval<_Iter>()) && - noexcept(*declval<_Iter>()) -)) {}; - -template -struct __libcpp_string_gets_noexcept_iterator_impl<_Iter, false> : public false_type {}; -#endif +struct __string_is_trivial_iterator : public false_type {}; +template +struct __string_is_trivial_iterator<_Tp*> + : public is_arithmetic<_Tp> {}; template -struct __libcpp_string_gets_noexcept_iterator - : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value || __libcpp_string_gets_noexcept_iterator_impl<_Iter>::value) {}; +struct __string_is_trivial_iterator<__wrap_iter<_Iter> > + : public __string_is_trivial_iterator<_Iter> {}; template struct __can_be_converted_to_string_view : public _BoolConstant< @@ -1048,20 +1035,16 @@ _LIBCPP_INLINE_VISIBILITY void __append_default_init(size_type __n); - template - _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS - basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator); template _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_exactly_cpp17_input_iterator<_InputIterator>::value - || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value, + __is_exactly_cpp17_input_iterator<_InputIterator>::value, basic_string& > _LIBCPP_INLINE_VISIBILITY append(_InputIterator __first, _InputIterator __last) { - const basic_string __temp (__first, __last, __alloc()); + const basic_string __temp(__first, __last, __alloc()); append(__temp.data(), __temp.size()); return *this; } @@ -1069,14 +1052,11 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_cpp17_forward_iterator<_ForwardIterator>::value - && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value, + __is_cpp17_forward_iterator<_ForwardIterator>::value, basic_string& > _LIBCPP_INLINE_VISIBILITY - append(_ForwardIterator __first, _ForwardIterator __last) { - return __append_forward_unsafe(__first, __last); - } + append(_ForwardIterator __first, _ForwardIterator __last); #ifndef _LIBCPP_CXX03_LANG _LIBCPP_INLINE_VISIBILITY @@ -1124,8 +1104,7 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_exactly_cpp17_input_iterator<_InputIterator>::value - || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value, + __is_exactly_cpp17_input_iterator<_InputIterator>::value, basic_string& > assign(_InputIterator __first, _InputIterator __last); @@ -1133,8 +1112,7 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_cpp17_forward_iterator<_ForwardIterator>::value - && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value, + __is_cpp17_forward_iterator<_ForwardIterator>::value, basic_string& > assign(_ForwardIterator __first, _ForwardIterator __last); @@ -1175,8 +1153,7 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_exactly_cpp17_input_iterator<_InputIterator>::value - || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value, + __is_exactly_cpp17_input_iterator<_InputIterator>::value, iterator > insert(const_iterator __pos, _InputIterator __first, _InputIterator __last); @@ -1184,8 +1161,7 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _EnableIf < - __is_cpp17_forward_iterator<_ForwardIterator>::value - && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value, + __is_cpp17_forward_iterator<_ForwardIterator>::value, iterator > insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last); @@ -1721,6 +1697,12 @@ _LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators(); _LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type); + template + bool __addr_in_range(_Tp&& __t) const { + const volatile void *__p = _VSTD::addressof(__t); + return data() <= __p && __p <= data() + size(); + } + friend basic_string operator+<>(const basic_string&, const basic_string&); friend basic_string operator+<>(const value_type*, const basic_string&); friend basic_string operator+<>(value_type, const basic_string&); @@ -2470,8 +2452,7 @@ template _EnableIf < - __is_exactly_cpp17_input_iterator <_InputIterator>::value - || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value, + __is_exactly_cpp17_input_iterator<_InputIterator>::value, basic_string<_CharT, _Traits, _Allocator>& > basic_string<_CharT, _Traits, _Allocator>::assign(_InputIterator __first, _InputIterator __last) @@ -2485,26 +2466,36 @@ template _EnableIf < - __is_cpp17_forward_iterator<_ForwardIterator>::value - && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value, + __is_cpp17_forward_iterator<_ForwardIterator>::value, basic_string<_CharT, _Traits, _Allocator>& > basic_string<_CharT, _Traits, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last) { - size_type __n = static_cast(_VSTD::distance(__first, __last)); size_type __cap = capacity(); - if (__cap < __n) + size_type __n = __string_is_trivial_iterator<_ForwardIterator>::value ? + static_cast(_VSTD::distance(__first, __last)) : 0; + + if (__string_is_trivial_iterator<_ForwardIterator>::value && + (__cap >= __n || !__addr_in_range(*__first))) { - size_type __sz = size(); - __grow_by(__cap, __n - __cap, __sz, 0, __sz); + if (__cap < __n) + { + size_type __sz = size(); + __grow_by(__cap, __n - __cap, __sz, 0, __sz); + } + else + __invalidate_iterators_past(__n); + pointer __p = __get_pointer(); + for (; __first != __last; ++__first, ++__p) + traits_type::assign(*__p, *__first); + traits_type::assign(*__p, value_type()); + __set_size(__n); } else - __invalidate_iterators_past(__n); - pointer __p = __get_pointer(); - for (; __first != __last; ++__first, ++__p) - traits_type::assign(*__p, *__first); - traits_type::assign(*__p, value_type()); - __set_size(__n); + { + const basic_string __temp(__first, __last, __alloc()); + assign(__temp.data(), __temp.size()); + } return *this; } @@ -2651,39 +2642,23 @@ traits_type::assign(*++__p, value_type()); } -template -bool __ptr_in_range (const _Tp* __p, const _Tp* __first, const _Tp* __last) -{ - return __first <= __p && __p < __last; -} - -template -bool __ptr_in_range (const _Tp1*, const _Tp2*, const _Tp2*) -{ - return false; -} - template template -basic_string<_CharT, _Traits, _Allocator>& -basic_string<_CharT, _Traits, _Allocator>::__append_forward_unsafe( +_EnableIf +< + __is_cpp17_forward_iterator<_ForwardIterator>::value, + basic_string<_CharT, _Traits, _Allocator>& +> +basic_string<_CharT, _Traits, _Allocator>::append( _ForwardIterator __first, _ForwardIterator __last) { - static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value, - "function requires a ForwardIterator"); size_type __sz = size(); size_type __cap = capacity(); size_type __n = static_cast(_VSTD::distance(__first, __last)); if (__n) { - typedef typename iterator_traits<_ForwardIterator>::reference _CharRef; - _CharRef __tmp_ref = *__first; - if (__ptr_in_range(_VSTD::addressof(__tmp_ref), data(), data() + size())) - { - const basic_string __temp (__first, __last, __alloc()); - append(__temp.data(), __temp.size()); - } - else + if (__string_is_trivial_iterator<_ForwardIterator>::value && + !__addr_in_range(*__first)) { if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); @@ -2693,6 +2668,11 @@ traits_type::assign(*__p, value_type()); __set_size(__sz + __n); } + else + { + const basic_string __temp(__first, __last, __alloc()); + append(__temp.data(), __temp.size()); + } } return *this; } @@ -2808,8 +2788,7 @@ template _EnableIf < - __is_exactly_cpp17_input_iterator<_InputIterator>::value - || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value, + __is_exactly_cpp17_input_iterator<_InputIterator>::value, typename basic_string<_CharT, _Traits, _Allocator>::iterator > basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last) @@ -2827,8 +2806,7 @@ template _EnableIf < - __is_cpp17_forward_iterator<_ForwardIterator>::value - && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value, + __is_cpp17_forward_iterator<_ForwardIterator>::value, typename basic_string<_CharT, _Traits, _Allocator>::iterator > basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last) @@ -2842,34 +2820,35 @@ size_type __n = static_cast(_VSTD::distance(__first, __last)); if (__n) { - typedef typename iterator_traits<_ForwardIterator>::reference _CharRef; - _CharRef __tmp_char = *__first; - if (__ptr_in_range(_VSTD::addressof(__tmp_char), data(), data() + size())) - { - const basic_string __temp(__first, __last, __alloc()); - return insert(__pos, __temp.data(), __temp.data() + __temp.size()); - } - - size_type __sz = size(); - size_type __cap = capacity(); - value_type* __p; - if (__cap - __sz >= __n) + if (__string_is_trivial_iterator<_ForwardIterator>::value && + !__addr_in_range(*__first)) { - __p = _VSTD::__to_address(__get_pointer()); - size_type __n_move = __sz - __ip; - if (__n_move != 0) - traits_type::move(__p + __ip + __n, __p + __ip, __n_move); + size_type __sz = size(); + size_type __cap = capacity(); + value_type* __p; + if (__cap - __sz >= __n) + { + __p = _VSTD::__to_address(__get_pointer()); + size_type __n_move = __sz - __ip; + if (__n_move != 0) + traits_type::move(__p + __ip + __n, __p + __ip, __n_move); + } + else + { + __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); + __p = _VSTD::__to_address(__get_long_pointer()); + } + __sz += __n; + __set_size(__sz); + traits_type::assign(__p[__sz], value_type()); + for (__p += __ip; __first != __last; ++__p, ++__first) + traits_type::assign(*__p, *__first); } else { - __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); - __p = _VSTD::__to_address(__get_long_pointer()); + const basic_string __temp(__first, __last, __alloc()); + return insert(__pos, __temp.data(), __temp.data() + __temp.size()); } - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); - for (__p += __ip; __first != __last; ++__p, ++__first) - traits_type::assign(*__p, *__first); } return begin() + __ip; } diff --git a/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp b/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp +++ /dev/null @@ -1,195 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// - -// - -// __libcpp_is_trivial_iterator - -// __libcpp_is_trivial_iterator determines if an iterator is a "trivial" one, -// that can be used w/o worrying about its operations throwing exceptions. -// Pointers are trivial iterators. Libc++ has three "iterator wrappers": -// reverse_iterator, move_iterator, and __wrap_iter. If the underlying iterator -// is trivial, then those are as well. -// - -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "test_iterators.h" - -#if TEST_STD_VER >= 11 -#define DELETE_FUNCTION = delete -#else -#define DELETE_FUNCTION -#endif - -class T; // incomplete - -class my_input_iterator_tag : public std::input_iterator_tag {}; - -template -class my_input_iterator -{ - It it_; - - template friend class my_input_iterator; -public: - typedef my_input_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef It pointer; - typedef typename std::iterator_traits::reference reference; - - It base() const {return it_;} - - my_input_iterator() : it_() {} - explicit my_input_iterator(It it) : it_(it) {} - template - my_input_iterator(const my_input_iterator& u) :it_(u.it_) {} - - reference operator*() const {return *it_;} - pointer operator->() const {return it_;} - - my_input_iterator& operator++() {++it_; return *this;} - my_input_iterator operator++(int) - {my_input_iterator tmp(*this); ++(*this); return tmp;} - - friend bool operator==(const my_input_iterator& x, const my_input_iterator& y) - {return x.it_ == y.it_;} - friend bool operator!=(const my_input_iterator& x, const my_input_iterator& y) - {return !(x == y);} - - template - void operator,(T const &) DELETE_FUNCTION; -}; - -template -inline -bool -operator==(const my_input_iterator& x, const my_input_iterator& y) -{ - return x.base() == y.base(); -} - -template -inline -bool -operator!=(const my_input_iterator& x, const my_input_iterator& y) -{ - return !(x == y); -} - - -int main(int, char**) -{ -// basic tests - static_assert(( std::__libcpp_is_trivial_iterator::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::value), ""); - - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator >::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator >::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator >::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator > ::value), ""); - - static_assert(( std::__libcpp_is_trivial_iterator > > ::value), ""); - -// iterators in the libc++ test suite - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - static_assert((!std::__libcpp_is_trivial_iterator >::value), ""); - - -// Iterator classification - static_assert(( std::__is_cpp17_input_iterator ::value), "" ); - static_assert(( std::__is_cpp17_forward_iterator ::value), "" ); - static_assert(( std::__is_cpp17_bidirectional_iterator::value), "" ); - static_assert(( std::__is_cpp17_random_access_iterator::value), "" ); - static_assert(( std::__is_cpp17_contiguous_iterator ::value), "" ); - static_assert((!std::__is_exactly_cpp17_input_iterator::value), "" ); - - static_assert(( std::__is_cpp17_input_iterator >::value), "" ); - static_assert((!std::__is_cpp17_forward_iterator >::value), "" ); - static_assert((!std::__is_cpp17_bidirectional_iterator >::value), "" ); - static_assert((!std::__is_cpp17_random_access_iterator >::value), "" ); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), "" ); - static_assert(( std::__is_exactly_cpp17_input_iterator >::value), "" ); - - static_assert(( std::__is_cpp17_input_iterator >::value), "" ); - static_assert(( std::__is_cpp17_forward_iterator >::value), "" ); - static_assert((!std::__is_cpp17_bidirectional_iterator >::value), "" ); - static_assert((!std::__is_cpp17_random_access_iterator >::value), "" ); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), "" ); - static_assert((!std::__is_exactly_cpp17_input_iterator >::value), "" ); - - static_assert(( std::__is_cpp17_input_iterator >::value), "" ); - static_assert(( std::__is_cpp17_forward_iterator >::value), "" ); - static_assert(( std::__is_cpp17_bidirectional_iterator >::value), "" ); - static_assert((!std::__is_cpp17_random_access_iterator >::value), "" ); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), "" ); - static_assert((!std::__is_exactly_cpp17_input_iterator >::value), "" ); - - static_assert(( std::__is_cpp17_input_iterator >::value), "" ); - static_assert(( std::__is_cpp17_forward_iterator >::value), "" ); - static_assert(( std::__is_cpp17_bidirectional_iterator >::value), "" ); - static_assert(( std::__is_cpp17_random_access_iterator >::value), "" ); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), "" ); - static_assert((!std::__is_exactly_cpp17_input_iterator >::value), "" ); - - static_assert(( std::__is_cpp17_input_iterator >::value), "" ); - static_assert((!std::__is_cpp17_forward_iterator >::value), "" ); - static_assert((!std::__is_cpp17_bidirectional_iterator >::value), "" ); - static_assert((!std::__is_cpp17_random_access_iterator >::value), "" ); - static_assert((!std::__is_cpp17_contiguous_iterator >::value), "" ); - static_assert(( std::__is_exactly_cpp17_input_iterator >::value), "" ); - -// -// iterators from libc++'s containers -// - -// vector - static_assert(( std::__libcpp_is_trivial_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::const_reverse_iterator>::value), ""); - -// string - static_assert(( std::__libcpp_is_trivial_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::const_reverse_iterator>::value), ""); - -#if TEST_STD_VER >= 11 -// Initializer list (which has no reverse iterators) - static_assert(( std::__libcpp_is_trivial_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_is_trivial_iterator::const_iterator> ::value), ""); -#endif - - - return 0; -} diff --git a/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp b/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// - -// __libcpp_is_trivial_iterator - -// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used -// w/o worrying about whether or not certain operations can throw. -// This gives us a "fast path for string operations" -// - -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "test_iterators.h" - -#ifndef TEST_HAS_NO_EXCEPTIONS -static const bool expected = false; -#else -// Under -fno-exceptions all noexcept expressions are trivially true, so -// any check for a noexcept returning false must actually check for it being -// true. -static const bool expected = true; -#endif - -int main(int, char**) -{ -// basic tests - static_assert(( std::__libcpp_string_gets_noexcept_iterator::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > > ::value), ""); - -// iterators in the libc++ test suite - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); - -#if TEST_STD_VER >= 11 - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); -#else - static_assert(std::__libcpp_string_gets_noexcept_iterator >::value == expected, ""); -#endif - -// -// iterators from libc++'s containers -// - -// string - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_reverse_iterator>::value), ""); - -// vector - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_reverse_iterator>::value), ""); - -#if TEST_STD_VER >= 11 -// Initializer list (which has no reverse iterators) - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); -#endif - - return 0; -} diff --git a/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp b/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// - -// - -// __libcpp_is_trivial_iterator - -// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used -// w/o worrying about whether or not certain operations can throw. -// This gives us a "fast path for string operations". -// -// When exceptions are disabled, all iterators should get this "fast path" -// - -// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions - -#include -#include -#include -#include -#include - -#include "test_macros.h" -#include "test_iterators.h" - -int main(int, char**) -{ -// basic tests - static_assert(( std::__libcpp_string_gets_noexcept_iterator::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator > > ::value), ""); - -// iterators in the libc++ test suite - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - - static_assert(( std::__libcpp_string_gets_noexcept_iterator >::value), ""); - -// -// iterators from libc++'s containers -// - -// string - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_reverse_iterator>::value), ""); - -// vector - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::reverse_iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_reverse_iterator>::value), ""); - -#if TEST_STD_VER >= 11 -// Initializer list (which has no reverse iterators) - static_assert(( std::__libcpp_string_gets_noexcept_iterator::iterator> ::value), ""); - static_assert(( std::__libcpp_string_gets_noexcept_iterator::const_iterator> ::value), ""); -#endif - - return 0; -} diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +struct Incomplete; +template struct Holder { T t; }; + +template +struct Charlike { + char ch_; + Charlike(char ch) : ch_(ch) {} + operator char() const { return ch_; } +}; + +int main(int, char**) +{ + std::string s; + Charlike > a[] = {'m', 'a', 'h', 'i'}; + s.append(a, a+4); + s.assign(a, a+4); + s.insert(s.begin(), a, a+4); + s.replace(s.begin(), s.begin()+4, a, a+4); + assert(s == "mahimahi"); + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp @@ -18,6 +18,8 @@ #include "test_iterators.h" #include "min_allocator.h" +struct Widget { operator char() const { throw 42; } }; + template void test(S s, It first, It last, S expected) @@ -32,14 +34,21 @@ void test_exceptions(S s, It first, It last) { - S aCopy = s; + S original = s; + typename S::iterator begin = s.begin(); + typename S::iterator end = s.end(); + try { s.append(first, last); assert(false); - } - catch (...) {} + } catch (...) {} + + // Part of "no effects" is that iterators and pointers + // into the string must not have been invalidated. LIBCPP_ASSERT(s.__invariants()); - assert(s == aCopy); + assert(s == original); + assert(s.begin() == begin); + assert(s.end() == end); } #endif @@ -176,6 +185,9 @@ test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter()); test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter()); test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter()); + + Widget w[100]; + test_exceptions(S(), w, w+100); } #endif @@ -204,6 +216,23 @@ assert(s == "ABCD"); } + { // regression-test appending to self in sneaky ways + std::string s_short = "hello"; + std::string s_long = "Lorem ipsum dolor sit amet, consectetur/"; + std::string s_othertype = "hello"; + const unsigned char *first = reinterpret_cast(s_othertype.data()); + std::string s_sneaky = "hello"; + + test(s_short, s_short.data() + s_short.size(), s_short.data() + s_short.size() + 1, + std::string("hello\0", 6)); + test(s_long, s_long.data() + s_long.size(), s_long.data() + s_long.size() + 1, + std::string("Lorem ipsum dolor sit amet, consectetur/\0", 41)); + test(s_othertype, first + 2, first + 5, std::string("hellollo")); + + s_sneaky.reserve(12); + test(s_sneaky, s_sneaky.data(), s_sneaky.data() + 6, std::string("hellohello\0", 11)); + } + { // test with a move iterator that returns char&& typedef forward_iterator It; typedef std::move_iterator MoveIt; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp @@ -18,6 +18,8 @@ #include "test_iterators.h" #include "min_allocator.h" +struct Widget { operator char() const { throw 42; } }; + template void test(S s, It first, It last, S expected) @@ -32,14 +34,21 @@ void test_exceptions(S s, It first, It last) { - S aCopy = s; + S original = s; + typename S::iterator begin = s.begin(); + typename S::iterator end = s.end(); + try { s.assign(first, last); assert(false); - } - catch (...) {} + } catch (...) {} + + // Part of "no effects" is that iterators and pointers + // into the string must not have been invalidated. LIBCPP_ASSERT(s.__invariants()); - assert(s == aCopy); + assert(s == original); + assert(s.begin() == begin); + assert(s.end() == end); } #endif @@ -176,6 +185,9 @@ test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter()); test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter()); test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter()); + + Widget w[100]; + test_exceptions(S(), w, w+100); } #endif @@ -205,5 +217,12 @@ assert(s == "ABCD"); } - return 0; + { // regression-test assigning to self in sneaky ways + std::string sneaky = "hello"; + sneaky.resize(sneaky.capacity(), 'x'); + std::string expected = sneaky + std::string(1, '\0'); + test(sneaky, sneaky.data(), sneaky.data() + sneaky.size() + 1, expected); + } + + return 0; } diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp @@ -18,6 +18,8 @@ #include "test_iterators.h" #include "min_allocator.h" +struct Widget { operator char() const { throw 42; } }; + template void test(S s, typename S::difference_type pos, It first, It last, S expected) @@ -35,14 +37,22 @@ test_exceptions(S s, typename S::difference_type pos, It first, It last) { typename S::const_iterator p = s.cbegin() + pos; - S aCopy = s; + + S original = s; + typename S::iterator begin = s.begin(); + typename S::iterator end = s.end(); + try { s.insert(p, first, last); assert(false); - } - catch (...) {} + } catch (...) {} + + // Part of "no effects" is that iterators and pointers + // into the string must not have been invalidated. LIBCPP_ASSERT(s.__invariants()); - assert(s == aCopy); + assert(s == original); + assert(s.begin() == begin); + assert(s.end() == end); } #endif @@ -153,6 +163,9 @@ test_exceptions(S(), 0, TIter(s, s+10, 4, TIter::TAIncrement), TIter()); test_exceptions(S(), 0, TIter(s, s+10, 5, TIter::TADereference), TIter()); test_exceptions(S(), 0, TIter(s, s+10, 6, TIter::TAComparison), TIter()); + + Widget w[100]; + test_exceptions(S(), 0, w, w+100); } #endif @@ -181,6 +194,19 @@ assert(s == "ABCD"); } + { // regression-test inserting into self in sneaky ways + std::string s_short = "hello"; + std::string s_long = "Lorem ipsum dolor sit amet, consectetur/"; + std::string s_othertype = "hello"; + const unsigned char *first = reinterpret_cast(s_othertype.data()); + + test(s_short, 0, s_short.data() + s_short.size(), s_short.data() + s_short.size() + 1, + std::string("\0hello", 6)); + test(s_long, 0, s_long.data() + s_long.size(), s_long.data() + s_long.size() + 1, + std::string("\0Lorem ipsum dolor sit amet, consectetur/", 41)); + test(s_othertype, 1, first + 2, first + 5, std::string("hlloello")); + } + { // test with a move iterator that returns char&& typedef input_iterator It; typedef std::move_iterator MoveIt; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp @@ -20,6 +20,8 @@ #include "min_allocator.h" #include "test_iterators.h" +struct Widget { operator char() const { throw 42; } }; + template void test(S s, typename S::size_type pos1, typename S::size_type n1, It f, It l, S expected) @@ -42,14 +44,22 @@ { typename S::const_iterator first = s.begin() + pos1; typename S::const_iterator last = s.begin() + pos1 + n1; - S aCopy = s; + + S original = s; + typename S::iterator begin = s.begin(); + typename S::iterator end = s.end(); + try { s.replace(first, last, f, l); assert(false); - } - catch (...) {} + } catch (...) {} + + // Part of "no effects" is that iterators and pointers + // into the string must not have been invalidated. LIBCPP_ASSERT(s.__invariants()); - assert(s == aCopy); + assert(s == original); + assert(s.begin() == begin); + assert(s.end() == end); } #endif @@ -1005,6 +1015,9 @@ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 4, TIter::TAIncrement), TIter()); test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 5, TIter::TADereference), TIter()); test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 6, TIter::TAComparison), TIter()); + + Widget w[100]; + test_exceptions(S(), w, w+100); } #endif