__exception_guard is a no-op in -fno-exceptions mode to produce better code-gen. This means that we don't provide the strong exception guarantees. However, Clang doesn't generate cleanup code with exceptions disabled, so even if we wanted to provide the strong exception guarantees we couldn't. This is also only relevant for constructs with a stack of -fexceptions > -fno-exceptions > -fexceptions code, since the exception can't be caught where exceptions are disabled. While -fexceptions > -fno-exceptions is quite common (e.g. libc++.dylib > -fno-exceptions), having another layer with exceptions enabled seems a lot less common, especially one that tries to catch an exception through -fno-exceptions code.
Fixes https://github.com/llvm/llvm-project/issues/56783
Reviewed By: ldionne, Mordante, huixie90, #libc
Spies: EricWF, alexfh, hans, joanahalili, libcxx-commits
Differential Revision: https://reviews.llvm.org/D133661
__utility/cmp.h
__utility/convert_to_integral.h
__utility/declval.h
+ __utility/exception_guard.h
__utility/exchange.h
__utility/forward.h
__utility/forward_like.h
__utility/rel_ops.h
__utility/swap.h
__utility/to_underlying.h
- __utility/transaction.h
__utility/unreachable.h
__variant/monostate.h
__verbose_abort
#include <__type_traits/negation.h>
#include <__type_traits/remove_cv.h>
#include <__type_traits/remove_cvref.h>
+#include <__utility/exception_guard.h>
#include <__utility/forward.h>
#include <__utility/in_place.h>
#include <__utility/move.h>
#include <__utility/swap.h>
-#include <__utility/transaction.h>
#include <cstdlib> // for std::abort
#include <initializer_list>
"be reverted to the previous state in case an exception is thrown during the assignment.");
_T2 __tmp(std::move(__oldval));
std::destroy_at(std::addressof(__oldval));
- __transaction __trans([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); });
+ __exception_guard __trans([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); });
std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...);
__trans.__complete();
}
if constexpr (is_nothrow_move_constructible_v<_Err>) {
_Err __tmp(std::move(__with_err.__union_.__unex_));
std::destroy_at(std::addressof(__with_err.__union_.__unex_));
- __transaction __trans([&] {
+ __exception_guard __trans([&] {
std::construct_at(std::addressof(__with_err.__union_.__unex_), std::move(__tmp));
});
std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__with_val.__union_.__val_));
"that it can be reverted to the previous state in case an exception is thrown during swap.");
_Tp __tmp(std::move(__with_val.__union_.__val_));
std::destroy_at(std::addressof(__with_val.__union_.__val_));
- __transaction __trans([&] { std::construct_at(std::addressof(__with_val.__union_.__val_), std::move(__tmp)); });
+ __exception_guard __trans([&] {
+ std::construct_at(std::addressof(__with_val.__union_.__val_), std::move(__tmp));
+ });
std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_));
__trans.__complete();
std::destroy_at(std::addressof(__with_err.__union_.__unex_));
#include <__type_traits/negation.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_extent.h>
+#include <__utility/exception_guard.h>
#include <__utility/move.h>
#include <__utility/pair.h>
-#include <__utility/transaction.h>
#include <new>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
_Tp& __array = *__loc;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __transaction __guard([&]() { std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i); });
+ __exception_guard __guard([&]() {
+ std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
+ });
+
for (; __i != extent_v<_Tp>; ++__i) {
std::__allocator_construct_at(__elem_alloc, std::addressof(__array[__i]));
}
_Tp& __array = *__loc;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __transaction __guard([&]() { std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i); });
+ __exception_guard __guard([&]() {
+ std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
+ });
for (; __i != extent_v<_Tp>; ++__i) {
std::__allocator_construct_at(__elem_alloc, std::addressof(__array[__i]), __arg[__i]);
}
_BidirIter __begin = __it;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __transaction __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ __exception_guard __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
for (; __n != 0; --__n, ++__it) {
std::__allocator_construct_at(__value_alloc, std::addressof(*__it), __value);
}
_BidirIter __begin = __it;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __transaction __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ __exception_guard __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
for (; __n != 0; --__n, ++__it) {
std::__allocator_construct_at(__value_alloc, std::addressof(*__it));
}
template <class _Alloc, class _Iter1, class _Sent1, class _Iter2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
__uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
-#ifndef _LIBCPP_NO_EXCEPTIONS
auto __destruct_first = __first2;
- try {
-#endif
+ auto __guard =
+ std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2));
while (__first1 != __last1) {
allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), *__first1);
++__first1;
++__first2;
}
-#ifndef _LIBCPP_NO_EXCEPTIONS
- } catch (...) {
- _AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)();
- throw;
- }
-#endif
+ __guard.__complete();
return __first2;
}
_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
static_assert(__is_cpp17_move_insertable<_Alloc>::value,
"The specified type does not meet the requirements of Cpp17MoveInsertable");
-#ifndef _LIBCPP_NO_EXCEPTIONS
auto __destruct_first = __first2;
- try {
-#endif
+ auto __guard =
+ std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2));
while (__first1 != __last1) {
#ifndef _LIBCPP_NO_EXCEPTIONS
allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), std::move_if_noexcept(*__first1));
++__first1;
++__first2;
}
-#ifndef _LIBCPP_NO_EXCEPTIONS
- } catch (...) {
- _AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2)();
- throw;
- }
-#endif
+ __guard.__complete();
return __first2;
}
#include <__assert>
#include <__config>
#include <__memory_resource/memory_resource.h>
-#include <__utility/transaction.h>
+#include <__utility/exception_guard.h>
#include <cstddef>
#include <limits>
#include <new>
template <class _Type, class... _CtorArgs>
[[nodiscard]] _Type* new_object(_CtorArgs&&... __ctor_args) {
_Type* __ptr = allocate_object<_Type>();
- __transaction __guard([&] { deallocate_object(__ptr); });
+ __exception_guard __guard([&] { deallocate_object(__ptr); });
construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...);
__guard.__complete();
return __ptr;
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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_TRANSACTION_H
+#define _LIBCPP___UTILITY_TRANSACTION_H
+
+#include <__assert>
+#include <__config>
+#include <__type_traits/is_nothrow_move_constructible.h>
+#include <__utility/exchange.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __exception_guard is a helper class for writing code with the strong exception guarantee.
+//
+// When writing code that can throw an exception, one can store rollback instructions in an
+// exception guard so that if an exception is thrown at any point during the lifetime of the
+// exception guard, it will be rolled back automatically. When the exception guard is done, one
+// must mark it as being complete so it isn't rolled back when the exception guard is destroyed.
+//
+// Exception guards are not default constructible, they can't be copied or assigned to, but
+// they can be moved around for convenience.
+//
+// __exception_guard is a no-op in -fno-exceptions mode to produce better code-gen. This means
+// that we don't provide the strong exception guarantees. However, Clang doesn't generate cleanup
+// code with exceptions disabled, so even if we wanted to provide the strong exception guarantees
+// we couldn't. This is also only relevant for constructs with a stack of
+// -fexceptions > -fno-exceptions > -fexceptions code, since the exception can't be caught where
+// exceptions are disabled. While -fexceptions > -fno-exceptions is quite common
+// (e.g. libc++.dylib > -fno-exceptions), having another layer with exceptions enabled seems a lot
+// less common, especially one that tries to catch an exception through -fno-exceptions code.
+//
+// __exception_guard can help greatly simplify code that would normally be cluttered by
+// `#if _LIBCPP_NO_EXCEPTIONS`. For example:
+//
+// template <class Iterator, class Size, class OutputIterator>
+// Iterator uninitialized_copy_n(Iterator iter, Size n, OutputIterator out) {
+// typedef typename iterator_traits<Iterator>::value_type value_type;
+// __exception_guard guard([start=out, &out] {
+// std::destroy(start, out);
+// });
+//
+// for (; n > 0; ++iter, ++out, --n) {
+// ::new ((void*)std::addressof(*out)) value_type(*iter);
+// }
+// guard.__complete();
+// return out;
+// }
+//
+
+#ifndef _LIBCPP_NO_EXCEPTIONS
+template <class _Rollback>
+struct __exception_guard {
+ __exception_guard() = delete;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __exception_guard(_Rollback __rollback)
+ : __rollback_(std::move(__rollback)), __completed_(false) {}
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __exception_guard(__exception_guard&& __other)
+ _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
+ : __rollback_(std::move(__other.__rollback_)), __completed_(__other.__completed_) {
+ __other.__completed_ = true;
+ }
+
+ __exception_guard(__exception_guard const&) = delete;
+ __exception_guard& operator=(__exception_guard const&) = delete;
+ __exception_guard& operator=(__exception_guard&&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __complete() _NOEXCEPT { __completed_ = true; }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__exception_guard() {
+ if (!__completed_)
+ __rollback_();
+ }
+
+private:
+ _Rollback __rollback_;
+ bool __completed_;
+};
+#else // _LIBCPP_NO_EXCEPTIONS
+template <class _Rollback>
+struct __exception_guard {
+ __exception_guard() = delete;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG explicit __exception_guard(_Rollback) {}
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG __exception_guard(__exception_guard&& __other)
+ _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
+ : __completed_(__other.__completed_) {
+ __other.__completed_ = true;
+ }
+
+ __exception_guard(__exception_guard const&) = delete;
+ __exception_guard& operator=(__exception_guard const&) = delete;
+ __exception_guard& operator=(__exception_guard&&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG void __complete() _NOEXCEPT {
+ __completed_ = true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard() {
+ _LIBCPP_ASSERT(__completed_, "__exception_guard not completed with exceptions disabled");
+ }
+
+private:
+ bool __completed_ = false;
+};
+#endif // _LIBCPP_NO_EXCEPTIONS
+
+_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__exception_guard);
+
+template <class _Rollback>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __exception_guard<_Rollback> __make_exception_guard(_Rollback __rollback) {
+ return __exception_guard<_Rollback>(std::move(__rollback));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_TRANSACTION_H
+++ /dev/null
-//===----------------------------------------------------------------------===//
-//
-// 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_TRANSACTION_H
-#define _LIBCPP___UTILITY_TRANSACTION_H
-
-#include <__config>
-#include <__type_traits/is_nothrow_move_constructible.h>
-#include <__utility/exchange.h>
-#include <__utility/move.h>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
-#endif
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-// __transaction is a helper class for writing code with the strong exception guarantee.
-//
-// When writing code that can throw an exception, one can store rollback instructions in a
-// transaction so that if an exception is thrown at any point during the lifetime of the
-// transaction, it will be rolled back automatically. When the transaction is done, one
-// must mark it as being complete so it isn't rolled back when the transaction is destroyed.
-//
-// Transactions are not default constructible, they can't be copied or assigned to, but
-// they can be moved around for convenience.
-//
-// __transaction can help greatly simplify code that would normally be cluttered by
-// `#if _LIBCPP_NO_EXCEPTIONS`. For example:
-//
-// template <class Iterator, class Size, class OutputIterator>
-// Iterator uninitialized_copy_n(Iterator iter, Size n, OutputIterator out) {
-// typedef typename iterator_traits<Iterator>::value_type value_type;
-// __transaction transaction([start=out, &out] {
-// std::destroy(start, out);
-// });
-//
-// for (; n > 0; ++iter, ++out, --n) {
-// ::new ((void*)std::addressof(*out)) value_type(*iter);
-// }
-// transaction.__complete();
-// return out;
-// }
-//
-template <class _Rollback>
-struct __transaction {
- __transaction() = delete;
-
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __transaction(_Rollback __rollback)
- : __rollback_(_VSTD::move(__rollback))
- , __completed_(false)
- { }
-
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX20 __transaction(__transaction&& __other)
- _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
- : __rollback_(_VSTD::move(__other.__rollback_))
- , __completed_(__other.__completed_)
- {
- __other.__completed_ = true;
- }
-
- __transaction(__transaction const&) = delete;
- __transaction& operator=(__transaction const&) = delete;
- __transaction& operator=(__transaction&&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX20 void __complete() _NOEXCEPT {
- __completed_ = true;
- }
-
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__transaction() {
- if (!__completed_)
- __rollback_();
- }
-
-private:
- _Rollback __rollback_;
- bool __completed_;
-};
-_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__transaction);
-
-template <class _Rollback>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __transaction<_Rollback> __make_transaction(_Rollback __rollback) {
- return __transaction<_Rollback>(std::move(__rollback));
-}
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP___UTILITY_TRANSACTION_H
module cmp { private header "__utility/cmp.h" }
module convert_to_integral { private header "__utility/convert_to_integral.h" }
module declval { private header "__utility/declval.h" }
+ module exception_guard { private header "__utility/exception_guard.h" }
module exchange { private header "__utility/exchange.h" }
module forward { private header "__utility/forward.h" }
module forward_like { private header "__utility/forward_like.h" }
module rel_ops { private header "__utility/rel_ops.h" }
module swap { private header "__utility/swap.h" }
module to_underlying { private header "__utility/to_underlying.h" }
- module transaction { private header "__utility/transaction.h" }
module unreachable { private header "__utility/unreachable.h" }
}
}
#include <__utility/auto_cast.h>
#include <__utility/cmp.h>
#include <__utility/declval.h>
+#include <__utility/exception_guard.h>
#include <__utility/exchange.h>
#include <__utility/forward.h>
#include <__utility/forward_like.h>
#include <__utility/rel_ops.h>
#include <__utility/swap.h>
#include <__utility/to_underlying.h>
-#include <__utility/transaction.h>
#include <__utility/unreachable.h>
#include <version>
#include <__split_buffer>
#include <__type_traits/is_allocator.h>
#include <__type_traits/noexcept_move_assign_container.h>
+#include <__utility/exception_guard.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
-#include <__utility/transaction.h>
#include <climits>
#include <cstdlib>
#include <cstring>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(size_type __n)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__n > 0)
{
vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__n > 0)
{
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__n > 0)
{
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
vector<_Tp, _Allocator>::vector(const vector& __x)
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
else
{
typedef move_iterator<iterator> _Ip;
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
assign(_Ip(__x.begin()), _Ip(__x.end()));
__guard.__complete();
}
inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__il.size() > 0)
{
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__il.size() > 0)
{
__size_(0),
__cap_alloc_(0, __default_init_tag())
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
- auto __guard = std::__make_transaction(__destroy_vector(*this));
+ auto __guard = std::__make_exception_guard(__destroy_vector(*this));
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
#include <__utility/cmp.h> // expected-error@*:* {{use of private header from outside its module: '__utility/cmp.h'}}
#include <__utility/convert_to_integral.h> // expected-error@*:* {{use of private header from outside its module: '__utility/convert_to_integral.h'}}
#include <__utility/declval.h> // expected-error@*:* {{use of private header from outside its module: '__utility/declval.h'}}
+#include <__utility/exception_guard.h> // expected-error@*:* {{use of private header from outside its module: '__utility/exception_guard.h'}}
#include <__utility/exchange.h> // expected-error@*:* {{use of private header from outside its module: '__utility/exchange.h'}}
#include <__utility/forward.h> // expected-error@*:* {{use of private header from outside its module: '__utility/forward.h'}}
#include <__utility/forward_like.h> // expected-error@*:* {{use of private header from outside its module: '__utility/forward_like.h'}}
#include <__utility/rel_ops.h> // expected-error@*:* {{use of private header from outside its module: '__utility/rel_ops.h'}}
#include <__utility/swap.h> // expected-error@*:* {{use of private header from outside its module: '__utility/swap.h'}}
#include <__utility/to_underlying.h> // expected-error@*:* {{use of private header from outside its module: '__utility/to_underlying.h'}}
-#include <__utility/transaction.h> // expected-error@*:* {{use of private header from outside its module: '__utility/transaction.h'}}
#include <__utility/unreachable.h> // expected-error@*:* {{use of private header from outside its module: '__utility/unreachable.h'}}
#include <__variant/monostate.h> // expected-error@*:* {{use of private header from outside its module: '__variant/monostate.h'}}
// GENERATED-MARKER
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// REQUIRES: has-unix-headers
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}
+// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions -D_LIBCPP_ENABLE_ASSERTIONS
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header
+
+#include <__utility/exception_guard.h>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::__make_exception_guard([] {}), "__exception_guard not completed with exceptions disabled");
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions -D_LIBCPP_ENABLE_ASSERTIONS
+
+#include <utility>
+
+int main(int, char**) {
+ auto guard = std::__make_exception_guard([] {});
+ auto guard2 = std::move(guard);
+ guard2.__complete();
+}
// UNSUPPORTED: c++03
-#include <utility> // for __transaction
+// UNSUPPORTED: no-exceptions
+
#include <cassert>
#include <type_traits>
#include <utility>
bool rolled_back = false;
{
auto rollback = [&] { rolled_back = true; };
- std::__transaction<decltype(rollback)> t(rollback);
+ std::__exception_guard<decltype(rollback)> g(rollback);
}
assert(rolled_back);
}
bool rolled_back = false;
{
auto rollback = [&] { rolled_back = true; };
- std::__transaction<decltype(rollback)> t(rollback);
- t.__complete();
+ std::__exception_guard<decltype(rollback)> g(rollback);
+ g.__complete();
}
assert(!rolled_back);
}
int rollbacks = 0;
{
auto rollback = [&] { ++rollbacks; };
- std::__transaction<decltype(rollback)> t(rollback);
- auto other = std::move(t);
+ std::__exception_guard<decltype(rollback)> g(rollback);
+ auto other = std::move(g);
}
assert(rollbacks == 1);
}
int rollbacks = 0;
{
auto rollback = [&] { ++rollbacks; };
- std::__transaction<decltype(rollback)> t(rollback);
- auto other = std::move(t);
+ std::__exception_guard<decltype(rollback)> g(rollback);
+ auto other = std::move(g);
other.__complete();
}
assert(rollbacks == 0);
// Basic properties of the type
{
struct Rollback { void operator()() const { } };
- using Transaction = std::__transaction<Rollback>;
+ using Transaction = std::__exception_guard<Rollback>;
static_assert(!std::is_default_constructible<Transaction>::value, "");
ThrowOnMove(ThrowOnMove&&) noexcept(false) { }
void operator()() const { }
};
- using ThrowOnMoveTransaction = std::__transaction<ThrowOnMove>;
+ using ThrowOnMoveTransaction = std::__exception_guard<ThrowOnMove>;
ASSERT_NOEXCEPT(std::declval<Transaction>().__complete());
static_assert( std::is_nothrow_move_constructible<Transaction>::value, "");
bool rolled_back = false;
auto rollback = [&] { rolled_back = true; };
try {
- std::__transaction<decltype(rollback)> t(rollback);
+ std::__exception_guard<decltype(rollback)> g(rollback);
throw 0;
} catch (...) { }
assert(rolled_back);
bool rolled_back = false;
auto rollback = [&] { rolled_back = true; };
try {
- std::__transaction<decltype(rollback)> t(rollback);
- t.__complete();
+ std::__exception_guard<decltype(rollback)> g(rollback);
+ g.__complete();
throw 0;
} catch (...) { }
assert(!rolled_back);
}
- // Make sure __transaction does not rollback if the transaction is marked as
+ // Make sure __exception_guard does not rollback if the transaction is marked as
// completed within a destructor.
{
struct S {
~S() {
auto rollback = [this]{ x_ = true; };
- std::__transaction<decltype(rollback)> t(rollback);
- t.__complete();
+ std::__exception_guard<decltype(rollback)> g(rollback);
+ g.__complete();
}
bool& x_;