16015dd11SMarshall Clow //===----------------------------------------------------------------------===//
26015dd11SMarshall Clow //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66015dd11SMarshall Clow //
76015dd11SMarshall Clow //===----------------------------------------------------------------------===//
86015dd11SMarshall Clow //
9*a7f9895cSLouis Dionne // UNSUPPORTED: no-threads
1031cbe0f2SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
116015dd11SMarshall Clow 
126015dd11SMarshall Clow // <mutex>
136015dd11SMarshall Clow 
146015dd11SMarshall Clow // template <class ...Mutex> class scoped_lock;
156015dd11SMarshall Clow 
166015dd11SMarshall Clow // explicit scoped_lock(mutex_type& m);
176015dd11SMarshall Clow 
186015dd11SMarshall Clow #include <mutex>
196015dd11SMarshall Clow #include <cassert>
206015dd11SMarshall Clow #include "test_macros.h"
216015dd11SMarshall Clow 
226015dd11SMarshall Clow struct TestMutex {
236015dd11SMarshall Clow     bool locked = false;
246015dd11SMarshall Clow     TestMutex() = default;
~TestMutexTestMutex256015dd11SMarshall Clow     ~TestMutex() { assert(!locked); }
266015dd11SMarshall Clow 
lockTestMutex276015dd11SMarshall Clow     void lock() { assert(!locked); locked = true; }
try_lockTestMutex286015dd11SMarshall Clow     bool try_lock() { if (locked) return false; locked = true; return true; }
unlockTestMutex296015dd11SMarshall Clow     void unlock() { assert(locked); locked = false; }
306015dd11SMarshall Clow 
316015dd11SMarshall Clow     TestMutex(TestMutex const&) = delete;
326015dd11SMarshall Clow     TestMutex& operator=(TestMutex const&) = delete;
336015dd11SMarshall Clow };
346015dd11SMarshall Clow 
356015dd11SMarshall Clow #if !defined(TEST_HAS_NO_EXCEPTIONS)
366015dd11SMarshall Clow struct TestMutexThrows {
376015dd11SMarshall Clow     bool locked = false;
386015dd11SMarshall Clow     bool throws_on_lock = false;
396015dd11SMarshall Clow 
406015dd11SMarshall Clow     TestMutexThrows() = default;
~TestMutexThrowsTestMutexThrows416015dd11SMarshall Clow     ~TestMutexThrows() { assert(!locked); }
426015dd11SMarshall Clow 
lockTestMutexThrows436015dd11SMarshall Clow     void lock() {
446015dd11SMarshall Clow         assert(!locked);
456015dd11SMarshall Clow         if (throws_on_lock) {
466015dd11SMarshall Clow             throw 42;
476015dd11SMarshall Clow         }
486015dd11SMarshall Clow         locked = true;
496015dd11SMarshall Clow     }
506015dd11SMarshall Clow 
try_lockTestMutexThrows516015dd11SMarshall Clow     bool try_lock() {
526015dd11SMarshall Clow         if (locked) return false;
536015dd11SMarshall Clow         lock();
546015dd11SMarshall Clow         return true;
556015dd11SMarshall Clow     }
566015dd11SMarshall Clow 
unlockTestMutexThrows576015dd11SMarshall Clow     void unlock() { assert(locked); locked = false; }
586015dd11SMarshall Clow 
596015dd11SMarshall Clow     TestMutexThrows(TestMutexThrows const&) = delete;
606015dd11SMarshall Clow     TestMutexThrows& operator=(TestMutexThrows const&) = delete;
616015dd11SMarshall Clow };
626015dd11SMarshall Clow #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
636015dd11SMarshall Clow 
main(int,char **)642df59c50SJF Bastien int main(int, char**)
656015dd11SMarshall Clow {
666015dd11SMarshall Clow     {
676015dd11SMarshall Clow         using LG = std::scoped_lock<>;
686015dd11SMarshall Clow         LG lg;
696015dd11SMarshall Clow     }
706015dd11SMarshall Clow     {
716015dd11SMarshall Clow         using LG = std::scoped_lock<TestMutex>;
726015dd11SMarshall Clow         TestMutex m1;
736015dd11SMarshall Clow         {
746015dd11SMarshall Clow             LG lg(m1);
756015dd11SMarshall Clow             assert(m1.locked);
766015dd11SMarshall Clow         }
776015dd11SMarshall Clow         assert(!m1.locked);
786015dd11SMarshall Clow     }
796015dd11SMarshall Clow     {
806015dd11SMarshall Clow         using LG = std::scoped_lock<TestMutex, TestMutex>;
816015dd11SMarshall Clow         TestMutex m1, m2;
826015dd11SMarshall Clow         {
836015dd11SMarshall Clow             LG lg(m1, m2);
846015dd11SMarshall Clow             assert(m1.locked && m2.locked);
856015dd11SMarshall Clow         }
866015dd11SMarshall Clow         assert(!m1.locked && !m2.locked);
876015dd11SMarshall Clow     }
886015dd11SMarshall Clow     {
896015dd11SMarshall Clow         using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
906015dd11SMarshall Clow         TestMutex m1, m2, m3;
916015dd11SMarshall Clow         {
926015dd11SMarshall Clow             LG lg(m1, m2, m3);
936015dd11SMarshall Clow             assert(m1.locked && m2.locked && m3.locked);
946015dd11SMarshall Clow         }
956015dd11SMarshall Clow         assert(!m1.locked && !m2.locked && !m3.locked);
966015dd11SMarshall Clow     }
976015dd11SMarshall Clow #if !defined(TEST_HAS_NO_EXCEPTIONS)
986015dd11SMarshall Clow     {
996015dd11SMarshall Clow         using MT = TestMutexThrows;
1006015dd11SMarshall Clow         using LG = std::scoped_lock<MT>;
1016015dd11SMarshall Clow         MT m1;
1026015dd11SMarshall Clow         m1.throws_on_lock = true;
1036015dd11SMarshall Clow         try {
1046015dd11SMarshall Clow             LG lg(m1);
1056015dd11SMarshall Clow             assert(false);
1066015dd11SMarshall Clow         } catch (int) {}
1076015dd11SMarshall Clow         assert(!m1.locked);
1086015dd11SMarshall Clow     }
1096015dd11SMarshall Clow     {
1106015dd11SMarshall Clow         using MT = TestMutexThrows;
1116015dd11SMarshall Clow         using LG = std::scoped_lock<MT, MT>;
1126015dd11SMarshall Clow         MT m1, m2;
1136015dd11SMarshall Clow         m1.throws_on_lock = true;
1146015dd11SMarshall Clow         try {
1156015dd11SMarshall Clow             LG lg(m1, m2);
1166015dd11SMarshall Clow             assert(false);
1176015dd11SMarshall Clow         } catch (int) {}
1186015dd11SMarshall Clow         assert(!m1.locked && !m2.locked);
1196015dd11SMarshall Clow     }
1206015dd11SMarshall Clow     {
1216015dd11SMarshall Clow         using MT = TestMutexThrows;
1226015dd11SMarshall Clow         using LG = std::scoped_lock<MT, MT, MT>;
1236015dd11SMarshall Clow         MT m1, m2, m3;
1246015dd11SMarshall Clow         m2.throws_on_lock = true;
1256015dd11SMarshall Clow         try {
1266015dd11SMarshall Clow             LG lg(m1, m2, m3);
1276015dd11SMarshall Clow             assert(false);
1286015dd11SMarshall Clow         } catch (int) {}
1296015dd11SMarshall Clow         assert(!m1.locked && !m2.locked && !m3.locked);
1306015dd11SMarshall Clow     }
1316015dd11SMarshall Clow #endif
1326015dd11SMarshall Clow 
13301666904SLouis Dionne #if TEST_STD_VER >= 17
1346015dd11SMarshall Clow     {
1356015dd11SMarshall Clow     TestMutex m1, m2, m3;
1366015dd11SMarshall Clow         {
1376015dd11SMarshall Clow         std::scoped_lock sl{};
1386015dd11SMarshall Clow         static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" );
1396015dd11SMarshall Clow         }
1406015dd11SMarshall Clow         {
1416015dd11SMarshall Clow         std::scoped_lock sl{m1};
1426015dd11SMarshall Clow         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" );
1436015dd11SMarshall Clow         }
1446015dd11SMarshall Clow         {
1456015dd11SMarshall Clow         std::scoped_lock sl{m1, m2};
1466015dd11SMarshall Clow         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" );
1476015dd11SMarshall Clow         }
1486015dd11SMarshall Clow         {
1496015dd11SMarshall Clow         std::scoped_lock sl{m1, m2, m3};
1506015dd11SMarshall Clow         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" );
1516015dd11SMarshall Clow         }
1526015dd11SMarshall Clow     }
1536015dd11SMarshall Clow #endif
1542df59c50SJF Bastien 
1552df59c50SJF Bastien   return 0;
1566015dd11SMarshall Clow }
157