diff options
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/iterator_concepts.h | 35 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/vector.tcc | 138 | ||||
-rw-r--r-- | libstdc++-v3/include/debug/helper_functions.h | 32 | ||||
-rw-r--r-- | libstdc++-v3/include/std/format | 33 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc | 42 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/format/string.cc | 5 |
7 files changed, 195 insertions, 95 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index afeacbc..561c584 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2023-06-23 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/vector.tcc (_M_realloc_insert): Replace try-block + with RAII types. + 2023-06-20 Jonathan Wakely <jwakely@redhat.com> * include/std/array (to_array(T(&)[N])): Remove redundant diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 1555c37..6802582 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -771,19 +771,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && invocable<_Fn, iter_reference_t<_Is>...> using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Is>...>; + namespace __detail + { + template<typename _Iter, typename _Proj> + struct __projected + { + struct __type + { + using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>; + indirect_result_t<_Proj&, _Iter> operator*() const; // not defined + }; + }; + + template<weakly_incrementable _Iter, typename _Proj> + struct __projected<_Iter, _Proj> + { + struct __type + { + using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>; + using difference_type = iter_difference_t<_Iter>; + indirect_result_t<_Proj&, _Iter> operator*() const; // not defined + }; + }; + } // namespace __detail + /// [projected], projected template<indirectly_readable _Iter, indirectly_regular_unary_invocable<_Iter> _Proj> - struct projected - { - using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>; - - indirect_result_t<_Proj&, _Iter> operator*() const; // not defined - }; - - template<weakly_incrementable _Iter, typename _Proj> - struct incrementable_traits<projected<_Iter, _Proj>> - { using difference_type = iter_difference_t<_Iter>; }; + using projected = __detail::__projected<_Iter, _Proj>::__type; // [alg.req], common algorithm requirements diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index acd11e2..cda52fb 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -458,73 +458,109 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_realloc_insert(iterator __position, const _Tp& __x) #endif { - const size_type __len = - _M_check_len(size_type(1), "vector::_M_realloc_insert"); + const size_type __len = _M_check_len(1u, "vector::_M_realloc_insert"); pointer __old_start = this->_M_impl._M_start; pointer __old_finish = this->_M_impl._M_finish; const size_type __elems_before = __position - begin(); pointer __new_start(this->_M_allocate(__len)); pointer __new_finish(__new_start); - __try + + // RAII guard for allocated storage. + struct _Guard + { + pointer _M_storage; // Storage to deallocate + size_type _M_len; + _Tp_alloc_type& _M_alloc; + + _GLIBCXX20_CONSTEXPR + _Guard(pointer __s, size_type __l, _Tp_alloc_type& __a) + : _M_storage(__s), _M_len(__l), _M_alloc(__a) + { } + + _GLIBCXX20_CONSTEXPR + ~_Guard() { - // The order of the three operations is dictated by the C++11 - // case, where the moves could alter a new element belonging - // to the existing vector. This is an issue only for callers - // taking the element by lvalue ref (see last bullet of C++11 - // [res.on.arguments]). - _Alloc_traits::construct(this->_M_impl, - __new_start + __elems_before, + if (_M_storage) + __gnu_cxx::__alloc_traits<_Tp_alloc_type>:: + deallocate(_M_alloc, _M_storage, _M_len); + } + + private: + _Guard(const _Guard&); + }; + _Guard __guard(__new_start, __len, _M_impl); + + // The order of the three operations is dictated by the C++11 + // case, where the moves could alter a new element belonging + // to the existing vector. This is an issue only for callers + // taking the element by lvalue ref (see last bullet of C++11 + // [res.on.arguments]). + + // If this throws, the existing elements are unchanged. #if __cplusplus >= 201103L - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + std::__to_address(__new_start + __elems_before), + std::forward<_Args>(__args)...); #else - __x); + _Alloc_traits::construct(this->_M_impl, + __new_start + __elems_before, + __x); #endif - __new_finish = pointer(); #if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) - { - __new_finish = _S_relocate(__old_start, __position.base(), - __new_start, _M_get_Tp_allocator()); + if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) + { + // Relocation cannot throw. + __new_finish = _S_relocate(__old_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + ++__new_finish; + __new_finish = _S_relocate(__position.base(), __old_finish, + __new_finish, _M_get_Tp_allocator()); + } + else +#endif + { + // RAII type to destroy initialized elements. + struct _Guard_elts + { + pointer _M_first, _M_last; // Elements to destroy + _Tp_alloc_type& _M_alloc; - ++__new_finish; + _GLIBCXX20_CONSTEXPR + _Guard_elts(pointer __elt, _Tp_alloc_type& __a) + : _M_first(__elt), _M_last(__elt + 1), _M_alloc(__a) + { } - __new_finish = _S_relocate(__position.base(), __old_finish, - __new_finish, _M_get_Tp_allocator()); - } - else -#endif - { - __new_finish - = std::__uninitialized_move_if_noexcept_a - (__old_start, __position.base(), - __new_start, _M_get_Tp_allocator()); + _GLIBCXX20_CONSTEXPR + ~_Guard_elts() + { std::_Destroy(_M_first, _M_last, _M_alloc); } - ++__new_finish; + private: + _Guard_elts(const _Guard_elts&); + }; - __new_finish - = std::__uninitialized_move_if_noexcept_a - (__position.base(), __old_finish, - __new_finish, _M_get_Tp_allocator()); - } - } - __catch(...) - { - if (!__new_finish) - _Alloc_traits::destroy(this->_M_impl, - __new_start + __elems_before); - else - std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator()); - _M_deallocate(__new_start, __len); - __throw_exception_again; + // Guard the new element so it will be destroyed if anything throws. + _Guard_elts __guard_elts(__new_start + __elems_before, _M_impl); + + __new_finish = std::__uninitialized_move_if_noexcept_a( + __old_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + + ++__new_finish; + // Guard everything before the new element too. + __guard_elts._M_first = __new_start; + + __new_finish = std::__uninitialized_move_if_noexcept_a( + __position.base(), __old_finish, + __new_finish, _M_get_Tp_allocator()); + + // New storage has been fully initialized, destroy the old elements. + __guard_elts._M_first = __old_start; + __guard_elts._M_last = __old_finish; } -#if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (!_S_use_relocate()) -#endif - std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator()); - _GLIBCXX_ASAN_ANNOTATE_REINIT; - _M_deallocate(__old_start, - this->_M_impl._M_end_of_storage - __old_start); + __guard._M_storage = __old_start; + __guard._M_len = this->_M_impl._M_end_of_storage - __old_start; + this->_M_impl._M_start = __new_start; this->_M_impl._M_finish = __new_finish; this->_M_impl._M_end_of_storage = __new_start + __len; diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h index dccf8e9..052b36b 100644 --- a/libstdc++-v3/include/debug/helper_functions.h +++ b/libstdc++-v3/include/debug/helper_functions.h @@ -111,12 +111,19 @@ namespace __gnu_debug _GLIBCXX_CONSTEXPR inline typename _Distance_traits<_Iterator>::__type __get_distance(_Iterator __lhs, _Iterator __rhs) - { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); } + { + return __gnu_debug::__get_distance(__lhs, __rhs, + std::__iterator_category(__lhs)); + } // An arbitrary iterator pointer is not singular. inline bool __check_singular_aux(const void*) { return false; } + // Defined in <debug/safe_base.h> + bool + __check_singular_aux(const class _Safe_iterator_base*); + // We may have an iterator that derives from _Safe_iterator_base but isn't // a _Safe_iterator. template<typename _Iterator> @@ -125,7 +132,7 @@ namespace __gnu_debug __check_singular(_Iterator const& __x) { return ! std::__is_constant_evaluated() - && __check_singular_aux(std::__addressof(__x)); + && __gnu_debug::__check_singular_aux(std::__addressof(__x)); } /** Non-NULL pointers are nonsingular. */ @@ -163,7 +170,8 @@ namespace __gnu_debug std::input_iterator_tag) { return __first == __last - || (!__check_singular(__first) && !__check_singular(__last)); + || (!__gnu_debug::__check_singular(__first) + && !__gnu_debug::__check_singular(__last)); } template<typename _InputIterator> @@ -172,8 +180,8 @@ namespace __gnu_debug __valid_range_aux(_InputIterator __first, _InputIterator __last, std::random_access_iterator_tag) { - return - __valid_range_aux(__first, __last, std::input_iterator_tag()) + return __gnu_debug::__valid_range_aux(__first, __last, + std::input_iterator_tag()) && __first <= __last; } @@ -186,8 +194,8 @@ namespace __gnu_debug __valid_range_aux(_InputIterator __first, _InputIterator __last, std::__false_type) { - return __valid_range_aux(__first, __last, - std::__iterator_category(__first)); + return __gnu_debug::__valid_range_aux(__first, __last, + std::__iterator_category(__first)); } template<typename _InputIterator> @@ -197,10 +205,11 @@ namespace __gnu_debug typename _Distance_traits<_InputIterator>::__type& __dist, std::__false_type) { - if (!__valid_range_aux(__first, __last, std::input_iterator_tag())) + if (!__gnu_debug::__valid_range_aux(__first, __last, + std::input_iterator_tag())) return false; - __dist = __get_distance(__first, __last); + __dist = __gnu_debug::__get_distance(__first, __last); switch (__dist.second) { case __dp_none: @@ -231,7 +240,8 @@ namespace __gnu_debug typename _Distance_traits<_InputIterator>::__type& __dist) { typedef typename std::__is_integer<_InputIterator>::__type _Integral; - return __valid_range_aux(__first, __last, __dist, _Integral()); + return __gnu_debug::__valid_range_aux(__first, __last, __dist, + _Integral()); } template<typename _Iterator, typename _Sequence, typename _Category> @@ -254,7 +264,7 @@ namespace __gnu_debug __valid_range(_InputIterator __first, _InputIterator __last) { typedef typename std::__is_integer<_InputIterator>::__type _Integral; - return __valid_range_aux(__first, __last, _Integral()); + return __gnu_debug::__valid_range_aux(__first, __last, _Integral()); } template<typename _Iterator, typename _Sequence, typename _Category> diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 96a1e62..9d5981e 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -269,39 +269,26 @@ namespace __format if (__first == __last) __builtin_unreachable(); - // TODO: use this loop unconditionally? - // Most integers used for arg-id, width or precision will be small. - if (is_constant_evaluated()) - { - auto __next = __first; - unsigned short __val = 0; - while (__next != __last && '0' <= *__next && *__next <= '9') - { - __val = (__val * 10) + (*__next - '0'); // TODO check overflow? - ++__next; - } - if (__next == __first) - return {0, nullptr}; - return {__val, __next}; - } - - unsigned short __val = 0; if constexpr (is_same_v<_CharT, char>) { - auto [ptr, ec] = std::from_chars(__first, __last, __val); - if (ec == errc{}) - return {__val, ptr}; - return {0, nullptr}; + const auto __start = __first; + unsigned short __val = 0; + // N.B. std::from_chars is not constexpr in C++20. + if (__detail::__from_chars_alnum<true>(__first, __last, __val, 10) + && __first != __start) [[likely]] + return {__val, __first}; } else { + unsigned short __val = 0; constexpr int __n = 32; char __buf[__n]{}; - for (int __i = 0; __i < __n && __first != __last; ++__i) + for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i) __buf[__i] = __first[__i]; auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n); return {__v, __first + (__ptr - __buf)}; } + return {0, nullptr}; } template<typename _CharT> @@ -2118,7 +2105,7 @@ namespace __format typename basic_format_context<_Out, _CharT>::iterator format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const { - auto __u = reinterpret_cast<__UINT64_TYPE__>(__v); + auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); char __buf[2 + sizeof(__v) * 2]; auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), __u, 16); diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc new file mode 100644 index 0000000..4c2a095 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc @@ -0,0 +1,42 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } + +// P2538R1 ADL-proof std::projected +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2538r1.html + +#include <iterator> + +template<typename T> + concept has_diff_type = requires { typename T::difference_type; }; + +static_assert( has_diff_type<std::projected<int*, void(*)(int)>> ); + +struct Indy { + using value_type = int; + int operator*() const { return 0; } +}; +static_assert( ! std::weakly_incrementable<Indy> ); +static_assert( ! has_diff_type<std::projected<Indy, void(*)(int)>> ); + + +// Examples from the paper: + +template<class T> struct Holder { T t; }; +struct Incomplete; + +void test_concepts() +{ + using T = Holder<Incomplete>*; + static_assert(std::equality_comparable<T>); + (void) std::indirectly_comparable<T*, T*, std::equal_to<>>; + (void) std::sortable<T*>; +} + +#include <algorithm> + +void test_count() +{ + Holder<Incomplete>* a = nullptr; + (void) std::count(&a, &a, nullptr); + (void) std::ranges::count(&a, &a, nullptr); // { dg-bogus "." } +} diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc index e421028..d28135e 100644 --- a/libstdc++-v3/testsuite/std/format/string.cc +++ b/libstdc++-v3/testsuite/std/format/string.cc @@ -121,6 +121,11 @@ test_format_spec() // Invalid presentation types for strings. VERIFY( ! is_format_string_for("{:S}", "str") ); VERIFY( ! is_format_string_for("{:d}", "str") ); + + // Maximum integer value supported for widths and precisions is USHRT_MAX. + VERIFY( is_format_string_for("{:65535}", 1) ); + VERIFY( ! is_format_string_for("{:65536}", 1) ); + VERIFY( ! is_format_string_for("{:9999999}", 1) ); } int main() |