1 //===----------------------------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // UNSUPPORTED: libcpp-has-no-threads
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
12
13 // <mutex>
14
15 // template <class ...Mutex> class scoped_lock;
16
17 // explicit scoped_lock(mutex_type& m);
18
19 #include <mutex>
20 #include <cassert>
21 #include "test_macros.h"
22
23 struct TestMutex {
24 bool locked = false;
25 TestMutex() = default;
~TestMutexTestMutex26 ~TestMutex() { assert(!locked); }
27
lockTestMutex28 void lock() { assert(!locked); locked = true; }
try_lockTestMutex29 bool try_lock() { if (locked) return false; locked = true; return true; }
unlockTestMutex30 void unlock() { assert(locked); locked = false; }
31
32 TestMutex(TestMutex const&) = delete;
33 TestMutex& operator=(TestMutex const&) = delete;
34 };
35
36 #if !defined(TEST_HAS_NO_EXCEPTIONS)
37 struct TestMutexThrows {
38 bool locked = false;
39 bool throws_on_lock = false;
40
41 TestMutexThrows() = default;
~TestMutexThrowsTestMutexThrows42 ~TestMutexThrows() { assert(!locked); }
43
lockTestMutexThrows44 void lock() {
45 assert(!locked);
46 if (throws_on_lock) {
47 throw 42;
48 }
49 locked = true;
50 }
51
try_lockTestMutexThrows52 bool try_lock() {
53 if (locked) return false;
54 lock();
55 return true;
56 }
57
unlockTestMutexThrows58 void unlock() { assert(locked); locked = false; }
59
60 TestMutexThrows(TestMutexThrows const&) = delete;
61 TestMutexThrows& operator=(TestMutexThrows const&) = delete;
62 };
63 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
64
main()65 int main()
66 {
67 {
68 using LG = std::scoped_lock<>;
69 LG lg;
70 }
71 {
72 using LG = std::scoped_lock<TestMutex>;
73 TestMutex m1;
74 {
75 LG lg(m1);
76 assert(m1.locked);
77 }
78 assert(!m1.locked);
79 }
80 {
81 using LG = std::scoped_lock<TestMutex, TestMutex>;
82 TestMutex m1, m2;
83 {
84 LG lg(m1, m2);
85 assert(m1.locked && m2.locked);
86 }
87 assert(!m1.locked && !m2.locked);
88 }
89 {
90 using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
91 TestMutex m1, m2, m3;
92 {
93 LG lg(m1, m2, m3);
94 assert(m1.locked && m2.locked && m3.locked);
95 }
96 assert(!m1.locked && !m2.locked && !m3.locked);
97 }
98 #if !defined(TEST_HAS_NO_EXCEPTIONS)
99 {
100 using MT = TestMutexThrows;
101 using LG = std::scoped_lock<MT>;
102 MT m1;
103 m1.throws_on_lock = true;
104 try {
105 LG lg(m1);
106 assert(false);
107 } catch (int) {}
108 assert(!m1.locked);
109 }
110 {
111 using MT = TestMutexThrows;
112 using LG = std::scoped_lock<MT, MT>;
113 MT m1, m2;
114 m1.throws_on_lock = true;
115 try {
116 LG lg(m1, m2);
117 assert(false);
118 } catch (int) {}
119 assert(!m1.locked && !m2.locked);
120 }
121 {
122 using MT = TestMutexThrows;
123 using LG = std::scoped_lock<MT, MT, MT>;
124 MT m1, m2, m3;
125 m2.throws_on_lock = true;
126 try {
127 LG lg(m1, m2, m3);
128 assert(false);
129 } catch (int) {}
130 assert(!m1.locked && !m2.locked && !m3.locked);
131 }
132 #endif
133
134 #ifdef __cpp_deduction_guides
135 {
136 TestMutex m1, m2, m3;
137 {
138 std::scoped_lock sl{};
139 static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" );
140 }
141 {
142 std::scoped_lock sl{m1};
143 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" );
144 }
145 {
146 std::scoped_lock sl{m1, m2};
147 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" );
148 }
149 {
150 std::scoped_lock sl{m1, m2, m3};
151 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" );
152 }
153 }
154 #endif
155 }
156