aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog5
-rw-r--r--libstdc++-v3/include/bits/iterator_concepts.h35
-rw-r--r--libstdc++-v3/include/bits/vector.tcc138
-rw-r--r--libstdc++-v3/include/debug/helper_functions.h32
-rw-r--r--libstdc++-v3/include/std/format33
-rw-r--r--libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc42
-rw-r--r--libstdc++-v3/testsuite/std/format/string.cc5
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()