1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03
10
11 // UNSUPPORTED: no-exceptions
12
13 #include <cassert>
14 #include <type_traits>
15 #include <utility>
16
17 #include "test_macros.h"
18
test()19 TEST_CONSTEXPR_CXX20 bool test() {
20 // Make sure the transaction is rolled back if it is not marked as complete when
21 // it goes out of scope.
22 {
23 bool rolled_back = false;
24 {
25 auto rollback = [&] { rolled_back = true; };
26 std::__exception_guard<decltype(rollback)> g(rollback);
27 }
28 assert(rolled_back);
29 }
30
31 // Make sure the transaction is not rolled back if it is marked as complete when
32 // it goes out of scope.
33 {
34 bool rolled_back = false;
35 {
36 auto rollback = [&] { rolled_back = true; };
37 std::__exception_guard<decltype(rollback)> g(rollback);
38 g.__complete();
39 }
40 assert(!rolled_back);
41 }
42
43 // Make sure that we will perform the right number of rollbacks when a transaction has
44 // been moved around
45 {
46 // When we don't complete it (exactly 1 rollback should happen)
47 {
48 int rollbacks = 0;
49 {
50 auto rollback = [&] { ++rollbacks; };
51 std::__exception_guard<decltype(rollback)> g(rollback);
52 auto other = std::move(g);
53 }
54 assert(rollbacks == 1);
55 }
56
57 // When we do complete it (no rollbacks should happen)
58 {
59 int rollbacks = 0;
60 {
61 auto rollback = [&] { ++rollbacks; };
62 std::__exception_guard<decltype(rollback)> g(rollback);
63 auto other = std::move(g);
64 other.__complete();
65 }
66 assert(rollbacks == 0);
67 }
68 }
69
70 // Basic properties of the type
71 {
72 struct Rollback { void operator()() const { } };
73 using Transaction = std::__exception_guard<Rollback>;
74
75 static_assert(!std::is_default_constructible<Transaction>::value, "");
76
77 static_assert(!std::is_copy_constructible<Transaction>::value, "");
78 static_assert( std::is_move_constructible<Transaction>::value, "");
79
80 static_assert(!std::is_copy_assignable<Transaction>::value, "");
81 static_assert(!std::is_move_assignable<Transaction>::value, "");
82
83 // Check noexcept-ness of a few operations
84 {
85 struct ThrowOnMove {
86 ThrowOnMove(ThrowOnMove&&) noexcept(false) { }
87 void operator()() const { }
88 };
89 using ThrowOnMoveTransaction = std::__exception_guard<ThrowOnMove>;
90
91 ASSERT_NOEXCEPT(std::declval<Transaction>().__complete());
92 static_assert( std::is_nothrow_move_constructible<Transaction>::value, "");
93 static_assert(!std::is_nothrow_move_constructible<ThrowOnMoveTransaction>::value, "");
94 }
95 }
96
97 return true;
98 }
99
test_exceptions()100 void test_exceptions() {
101 #ifndef TEST_HAS_NO_EXCEPTIONS
102 // Make sure the rollback is performed when an exception is thrown during the
103 // lifetime of the transaction.
104 {
105 bool rolled_back = false;
106 auto rollback = [&] { rolled_back = true; };
107 try {
108 std::__exception_guard<decltype(rollback)> g(rollback);
109 throw 0;
110 } catch (...) { }
111 assert(rolled_back);
112 }
113
114 // Make sure we don't roll back if an exception is thrown but the transaction
115 // has been marked as complete when that happens.
116 {
117 bool rolled_back = false;
118 auto rollback = [&] { rolled_back = true; };
119 try {
120 std::__exception_guard<decltype(rollback)> g(rollback);
121 g.__complete();
122 throw 0;
123 } catch (...) { }
124 assert(!rolled_back);
125 }
126
127 // Make sure __exception_guard does not rollback if the transaction is marked as
128 // completed within a destructor.
129 {
130 struct S {
131 explicit S(bool& x) : x_(x) { }
132
133 ~S() {
134 auto rollback = [this]{ x_ = true; };
135 std::__exception_guard<decltype(rollback)> g(rollback);
136 g.__complete();
137 }
138
139 bool& x_;
140 };
141
142 bool rolled_back = false;
143 try {
144 S s(rolled_back);
145 throw 0;
146 } catch (...) {
147 assert(!rolled_back);
148 }
149 }
150 #endif // TEST_HAS_NO_EXCEPTIONS
151 }
152
main(int,char **)153 int main(int, char**) {
154 test();
155 test_exceptions();
156 #if TEST_STD_VER > 17
157 static_assert(test(), "");
158 #endif
159 return 0;
160 }
161