• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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