@@ -638,6 +638,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
638638#include < __utility/forward.h>
639639#include < __utility/is_pointer_in_range.h>
640640#include < __utility/move.h>
641+ #include < __utility/scope_guard.h>
641642#include < __utility/swap.h>
642643#include < __utility/unreachable.h>
643644#include < climits>
@@ -929,6 +930,15 @@ private:
929930
930931 _LIBCPP_COMPRESSED_PAIR (__rep, __rep_, allocator_type, __alloc_);
931932
933+ // annotate the string with its size() at scope exit. The string has to be in a valid state at that point.
934+ struct __annotate_new_size {
935+ basic_string& __str_;
936+
937+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotate_new_size (basic_string& __str) : __str_(__str) {}
938+
939+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator ()() { __str_.__annotate_new (__str_.size ()); }
940+ };
941+
932942 // Construct a string with the given allocator and enough storage to hold `__size` characters, but
933943 // don't initialize the characters. The contents of the string, including the null terminator, must be
934944 // initialized separately.
@@ -2171,6 +2181,7 @@ private:
21712181 __alloc_ = __str.__alloc_ ;
21722182 } else {
21732183 __annotate_delete ();
2184+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
21742185 allocator_type __a = __str.__alloc_ ;
21752186 auto __allocation = std::__allocate_at_least (__a, __str.__get_long_cap ());
21762187 __begin_lifetime (__allocation.ptr , __allocation.count );
@@ -2180,7 +2191,6 @@ private:
21802191 __set_long_pointer (__allocation.ptr );
21812192 __set_long_cap (__allocation.count );
21822193 __set_long_size (__str.size ());
2183- __annotate_new (__get_long_size ());
21842194 }
21852195 }
21862196 }
@@ -2508,6 +2518,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
25082518 size_type __cap =
25092519 __old_cap < __ms / 2 - __alignment ? __recommend (std::max (__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1 ;
25102520 __annotate_delete ();
2521+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
25112522 auto __allocation = std::__allocate_at_least (__alloc_, __cap + 1 );
25122523 pointer __p = __allocation.ptr ;
25132524 __begin_lifetime (__p, __allocation.count );
@@ -2526,7 +2537,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
25262537 __old_sz = __n_copy + __n_add + __sec_cp_sz;
25272538 __set_long_size (__old_sz);
25282539 traits_type::assign (__p[__old_sz], value_type ());
2529- __annotate_new (__old_sz);
25302540}
25312541
25322542// __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it
@@ -2550,7 +2560,6 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait
25502560 pointer __old_p = __get_pointer ();
25512561 size_type __cap =
25522562 __old_cap < __ms / 2 - __alignment ? __recommend (std::max (__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1 ;
2553- __annotate_delete ();
25542563 auto __allocation = std::__allocate_at_least (__alloc_, __cap + 1 );
25552564 pointer __p = __allocation.ptr ;
25562565 __begin_lifetime (__p, __allocation.count );
@@ -2575,11 +2584,12 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
25752584 size_type __n_copy,
25762585 size_type __n_del,
25772586 size_type __n_add) {
2587+ __annotate_delete ();
2588+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
25782589 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
25792590 __grow_by (__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
25802591 _LIBCPP_SUPPRESS_DEPRECATED_POP
25812592 __set_long_size (__old_sz - __n_del + __n_add);
2582- __annotate_new (__old_sz - __n_del + __n_add);
25832593}
25842594
25852595// assign
@@ -3364,6 +3374,7 @@ template <class _CharT, class _Traits, class _Allocator>
33643374inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
33653375basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
33663376 __annotate_delete ();
3377+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
33673378 size_type __cap = capacity ();
33683379 size_type __sz = size ();
33693380
@@ -3395,7 +3406,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
33953406 // due to swapping the elements.
33963407 if (__allocation.count - 1 > __target_capacity) {
33973408 __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3398- __annotate_new (__sz); // Undoes the __annotate_delete()
33993409 return ;
34003410 }
34013411 __new_data = __allocation.ptr ;
@@ -3420,7 +3430,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
34203430 __set_long_pointer (__new_data);
34213431 } else
34223432 __set_short_size (__sz);
3423- __annotate_new (__sz);
34243433}
34253434
34263435template <class _CharT , class _Traits , class _Allocator >
0 commit comments