@@ -638,6 +638,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
638
638
#include < __utility/forward.h>
639
639
#include < __utility/is_pointer_in_range.h>
640
640
#include < __utility/move.h>
641
+ #include < __utility/scope_guard.h>
641
642
#include < __utility/swap.h>
642
643
#include < __utility/unreachable.h>
643
644
#include < climits>
@@ -929,6 +930,15 @@ private:
929
930
930
931
_LIBCPP_COMPRESSED_PAIR (__rep, __rep_, allocator_type, __alloc_);
931
932
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
+
932
942
// Construct a string with the given allocator and enough storage to hold `__size` characters, but
933
943
// don't initialize the characters. The contents of the string, including the null terminator, must be
934
944
// initialized separately.
@@ -2171,6 +2181,7 @@ private:
2171
2181
__alloc_ = __str.__alloc_ ;
2172
2182
} else {
2173
2183
__annotate_delete ();
2184
+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
2174
2185
allocator_type __a = __str.__alloc_ ;
2175
2186
auto __allocation = std::__allocate_at_least (__a, __str.__get_long_cap ());
2176
2187
__begin_lifetime (__allocation.ptr , __allocation.count );
@@ -2180,7 +2191,6 @@ private:
2180
2191
__set_long_pointer (__allocation.ptr );
2181
2192
__set_long_cap (__allocation.count );
2182
2193
__set_long_size (__str.size ());
2183
- __annotate_new (__get_long_size ());
2184
2194
}
2185
2195
}
2186
2196
}
@@ -2508,6 +2518,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
2508
2518
size_type __cap =
2509
2519
__old_cap < __ms / 2 - __alignment ? __recommend (std::max (__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1 ;
2510
2520
__annotate_delete ();
2521
+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
2511
2522
auto __allocation = std::__allocate_at_least (__alloc_, __cap + 1 );
2512
2523
pointer __p = __allocation.ptr ;
2513
2524
__begin_lifetime (__p, __allocation.count );
@@ -2526,7 +2537,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
2526
2537
__old_sz = __n_copy + __n_add + __sec_cp_sz;
2527
2538
__set_long_size (__old_sz);
2528
2539
traits_type::assign (__p[__old_sz], value_type ());
2529
- __annotate_new (__old_sz);
2530
2540
}
2531
2541
2532
2542
// __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
2550
2560
pointer __old_p = __get_pointer ();
2551
2561
size_type __cap =
2552
2562
__old_cap < __ms / 2 - __alignment ? __recommend (std::max (__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1 ;
2553
- __annotate_delete ();
2554
2563
auto __allocation = std::__allocate_at_least (__alloc_, __cap + 1 );
2555
2564
pointer __p = __allocation.ptr ;
2556
2565
__begin_lifetime (__p, __allocation.count );
@@ -2575,11 +2584,12 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
2575
2584
size_type __n_copy,
2576
2585
size_type __n_del,
2577
2586
size_type __n_add) {
2587
+ __annotate_delete ();
2588
+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
2578
2589
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
2579
2590
__grow_by (__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
2580
2591
_LIBCPP_SUPPRESS_DEPRECATED_POP
2581
2592
__set_long_size (__old_sz - __n_del + __n_add);
2582
- __annotate_new (__old_sz - __n_del + __n_add);
2583
2593
}
2584
2594
2585
2595
// assign
@@ -3364,6 +3374,7 @@ template <class _CharT, class _Traits, class _Allocator>
3364
3374
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3365
3375
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3366
3376
__annotate_delete ();
3377
+ auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
3367
3378
size_type __cap = capacity ();
3368
3379
size_type __sz = size ();
3369
3380
@@ -3395,7 +3406,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
3395
3406
// due to swapping the elements.
3396
3407
if (__allocation.count - 1 > capacity ()) {
3397
3408
__alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3398
- __annotate_new (__sz); // Undoes the __annotate_delete()
3399
3409
return ;
3400
3410
}
3401
3411
__new_data = __allocation.ptr ;
@@ -3420,7 +3430,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
3420
3430
__set_long_pointer (__new_data);
3421
3431
} else
3422
3432
__set_short_size (__sz);
3423
- __annotate_new (__sz);
3424
3433
}
3425
3434
3426
3435
template <class _CharT , class _Traits , class _Allocator >
0 commit comments