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: libcpp-has-no-threads
10 // UNSUPPORTED: c++03, c++11, c++14
11
12 // <mutex>
13
14 // template <class ...Mutex> class scoped_lock;
15
16 // explicit scoped_lock(mutex_type& m);
17
18 #include <mutex>
19 #include <cassert>
20 #include "test_macros.h"
21
22 struct TestMutex {
23 bool locked = false;
24 TestMutex() = default;
~TestMutexTestMutex25 ~TestMutex() { assert(!locked); }
26
lockTestMutex27 void lock() { assert(!locked); locked = true; }
try_lockTestMutex28 bool try_lock() { if (locked) return false; locked = true; return true; }
unlockTestMutex29 void unlock() { assert(locked); locked = false; }
30
31 TestMutex(TestMutex const&) = delete;
32 TestMutex& operator=(TestMutex const&) = delete;
33 };
34
35 #if !defined(TEST_HAS_NO_EXCEPTIONS)
36 struct TestMutexThrows {
37 bool locked = false;
38 bool throws_on_lock = false;
39
40 TestMutexThrows() = default;
~TestMutexThrowsTestMutexThrows41 ~TestMutexThrows() { assert(!locked); }
42
lockTestMutexThrows43 void lock() {
44 assert(!locked);
45 if (throws_on_lock) {
46 throw 42;
47 }
48 locked = true;
49 }
50
try_lockTestMutexThrows51 bool try_lock() {
52 if (locked) return false;
53 lock();
54 return true;
55 }
56
unlockTestMutexThrows57 void unlock() { assert(locked); locked = false; }
58
59 TestMutexThrows(TestMutexThrows const&) = delete;
60 TestMutexThrows& operator=(TestMutexThrows const&) = delete;
61 };
62 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
63
main(int,char **)64 int main(int, char**)
65 {
66 {
67 using LG = std::scoped_lock<>;
68 LG lg;
69 }
70 {
71 using LG = std::scoped_lock<TestMutex>;
72 TestMutex m1;
73 {
74 LG lg(m1);
75 assert(m1.locked);
76 }
77 assert(!m1.locked);
78 }
79 {
80 using LG = std::scoped_lock<TestMutex, TestMutex>;
81 TestMutex m1, m2;
82 {
83 LG lg(m1, m2);
84 assert(m1.locked && m2.locked);
85 }
86 assert(!m1.locked && !m2.locked);
87 }
88 {
89 using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
90 TestMutex m1, m2, m3;
91 {
92 LG lg(m1, m2, m3);
93 assert(m1.locked && m2.locked && m3.locked);
94 }
95 assert(!m1.locked && !m2.locked && !m3.locked);
96 }
97 #if !defined(TEST_HAS_NO_EXCEPTIONS)
98 {
99 using MT = TestMutexThrows;
100 using LG = std::scoped_lock<MT>;
101 MT m1;
102 m1.throws_on_lock = true;
103 try {
104 LG lg(m1);
105 assert(false);
106 } catch (int) {}
107 assert(!m1.locked);
108 }
109 {
110 using MT = TestMutexThrows;
111 using LG = std::scoped_lock<MT, MT>;
112 MT m1, m2;
113 m1.throws_on_lock = true;
114 try {
115 LG lg(m1, m2);
116 assert(false);
117 } catch (int) {}
118 assert(!m1.locked && !m2.locked);
119 }
120 {
121 using MT = TestMutexThrows;
122 using LG = std::scoped_lock<MT, MT, MT>;
123 MT m1, m2, m3;
124 m2.throws_on_lock = true;
125 try {
126 LG lg(m1, m2, m3);
127 assert(false);
128 } catch (int) {}
129 assert(!m1.locked && !m2.locked && !m3.locked);
130 }
131 #endif
132
133 #ifdef __cpp_deduction_guides
134 {
135 TestMutex m1, m2, m3;
136 {
137 std::scoped_lock sl{};
138 static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" );
139 }
140 {
141 std::scoped_lock sl{m1};
142 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" );
143 }
144 {
145 std::scoped_lock sl{m1, m2};
146 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" );
147 }
148 {
149 std::scoped_lock sl{m1, m2, m3};
150 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" );
151 }
152 }
153 #endif
154
155 return 0;
156 }
157