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