diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index a4b97b1d7658c..36573715b537a 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -879,6 +879,7 @@ set(files __utility/priority_tag.h __utility/private_constructor_tag.h __utility/rel_ops.h + __utility/scope_guard.h __utility/small_buffer.h __utility/swap.h __utility/to_underlying.h diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h index 77dc2b4eb48ee..073b63cd8f0a6 100644 --- a/libcxx/include/__flat_map/flat_map.h +++ b/libcxx/include/__flat_map/flat_map.h @@ -60,6 +60,7 @@ #include <__type_traits/maybe_const.h> #include <__utility/exception_guard.h> #include <__utility/pair.h> +#include <__utility/scope_guard.h> #include <__vector/vector.h> #include #include diff --git a/libcxx/include/__utility/exception_guard.h b/libcxx/include/__utility/exception_guard.h index 00b835d3e2a2f..a03bd7e8f3522 100644 --- a/libcxx/include/__utility/exception_guard.h +++ b/libcxx/include/__utility/exception_guard.h @@ -137,12 +137,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __exception_guard<_Rollback> __make_exce return __exception_guard<_Rollback>(std::move(__rollback)); } -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __exception_guard_exceptions<_Rollback> -__make_scope_guard(_Rollback __rollback) { - return __exception_guard_exceptions<_Rollback>(std::move(__rollback)); -} - _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/__utility/scope_guard.h b/libcxx/include/__utility/scope_guard.h new file mode 100644 index 0000000000000..133e54212ed59 --- /dev/null +++ b/libcxx/include/__utility/scope_guard.h @@ -0,0 +1,60 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_SCOPE_GUARD_H +#define _LIBCPP___UTILITY_SCOPE_GUARD_H + +#include <__assert> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __scope_guard { + _Func __func_; + bool __moved_from_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __scope_guard(_Func __func) : __func_(std::move(__func)) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__scope_guard() { __func_(); } + + __scope_guard(const __scope_guard&) = delete; + +// C++17 has mandatory RVO, so we don't need the move constructor anymore to make __make_scope_guard work. +#if _LIBCPP_STD_VER <= 14 + __scope_guard(__scope_guard&& __other) : __func_(__other.__func_) { + _LIBCPP_ASSERT_INTERNAL(!__other.__moved_from_, "Cannot move twice from __scope_guard"); + __other.__moved_from_ = true; + } +#else + __scope_guard(__scope_guard&&) = delete; +#endif + + __scope_guard& operator=(const __scope_guard&) = delete; + __scope_guard& operator=(__scope_guard&&) = delete; +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __scope_guard<_Func> __make_scope_guard(_Func __func) { + return __scope_guard<_Func>(std::move(__func)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___UTILITY_SCOPE_GUARD_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 5465d603b2c4d..10b99ca5133dc 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -2003,6 +2003,7 @@ module std [system] { module priority_tag { header "__utility/priority_tag.h" } module private_constructor_tag { header "__utility/private_constructor_tag.h" } module rel_ops { header "__utility/rel_ops.h" } + module scope_guard { header "__utility/scope_guard.h" } module small_buffer { header "__utility/small_buffer.h" } module swap { header "__utility/swap.h" } module to_underlying { header "__utility/to_underlying.h" } diff --git a/libcxx/include/string b/libcxx/include/string index b1cedbe68f795..70b1196ed3b59 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -638,6 +638,7 @@ basic_string operator""s( const char32_t *str, size_t len ); #include <__utility/forward.h> #include <__utility/is_pointer_in_range.h> #include <__utility/move.h> +#include <__utility/scope_guard.h> #include <__utility/swap.h> #include <__utility/unreachable.h> #include @@ -929,6 +930,15 @@ private: _LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_); + // annotate the string with its size() at scope exit. The string has to be in a valid state at that point. + struct __annotate_new_size { + basic_string& __str_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotate_new_size(basic_string& __str) : __str_(__str) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() { __str_.__annotate_new(__str_.size()); } + }; + // Construct a string with the given allocator and enough storage to hold `__size` characters, but // don't initialize the characters. The contents of the string, including the null terminator, must be // initialized separately. @@ -2171,6 +2181,7 @@ private: __alloc_ = __str.__alloc_; } else { __annotate_delete(); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); allocator_type __a = __str.__alloc_; auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap()); __begin_lifetime(__allocation.ptr, __allocation.count); @@ -2180,7 +2191,6 @@ private: __set_long_pointer(__allocation.ptr); __set_long_cap(__allocation.count); __set_long_size(__str.size()); - __annotate_new(__get_long_size()); } } } @@ -2508,6 +2518,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__ size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; __annotate_delete(); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2526,7 +2537,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__ __old_sz = __n_copy + __n_add + __sec_cp_sz; __set_long_size(__old_sz); traits_type::assign(__p[__old_sz], value_type()); - __annotate_new(__old_sz); } // __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 pointer __old_p = __get_pointer(); size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; - __annotate_delete(); auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2575,11 +2584,12 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( size_type __n_copy, size_type __n_del, size_type __n_add) { + __annotate_delete(); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); _LIBCPP_SUPPRESS_DEPRECATED_PUSH __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add); _LIBCPP_SUPPRESS_DEPRECATED_POP __set_long_size(__old_sz - __n_del + __n_add); - __annotate_new(__old_sz - __n_del + __n_add); } // assign @@ -3364,6 +3374,7 @@ template inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) { __annotate_delete(); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); size_type __cap = capacity(); size_type __sz = size(); @@ -3395,7 +3406,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target // due to swapping the elements. if (__allocation.count - 1 > __target_capacity) { __alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count); - __annotate_new(__sz); // Undoes the __annotate_delete() return; } __new_data = __allocation.ptr; @@ -3420,7 +3430,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target __set_long_pointer(__new_data); } else __set_short_size(__sz); - __annotate_new(__sz); } template