mclow.lists created this revision.

WG21 has decided that the ABI-breaking `lock_guard` proposal that we (@EricWF) 
implemented (and hid behind an ABI-break macro) is not the way to go. Instead, 
we're introducing a new class, `scoped_lock`, which is variadic, and leaving 
`lock_guard` as non-variadic.

So, delete Eric's work, nuke the ABI macro, and implement the non-ABI breaking 
stuff.

While I'm in the neighborhood, implement the mutex-ey parts of P0433: 
"Deduction guides for the standard library". This bit has the guides for 
`lock_guard`, `scoped_lock`, `unique_lock`, and `shared_lock`.

Note: If you're using the variadic version of `lock_guard`, then this is a 
breaking change.  Good news is that you just switch to using `scoped_lock`, and 
everything works the same.


https://reviews.llvm.org/D31163

Files:
  include/__config
  include/__mutex_base
  include/mutex
  include/shared_mutex
  
test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/adopt_lock.pass.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/assign.fail.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/copy.fail.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.fail.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp
  test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/types.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp
  
test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp

Index: test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
@@ -15,11 +15,16 @@
 
 // explicit unique_lock(mutex_type& m);
 
+// template<class _Mutex> unique_lock(unique_lock<_Mutex>)
+//     -> unique_lock<_Mutex>;  // C++17
+
 #include <mutex>
 #include <thread>
 #include <cstdlib>
 #include <cassert>
 
+#include "test_macros.h"
+
 std::mutex m;
 
 typedef std::chrono::system_clock Clock;
@@ -47,4 +52,8 @@
     std::this_thread::sleep_for(ms(250));
     m.unlock();
     t.join();
+
+#if TEST_STD_VER > 14
+	std::unique_lock ul(m);	// deduction guide
+#endif
 }
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp
@@ -18,6 +18,9 @@
 
 // explicit shared_lock(mutex_type& m);
 
+// template<class _Mutex> shared_lock(shared_lock<_Mutex>)
+//     -> shared_lock<_Mutex>;  // C++17
+
 #include <shared_mutex>
 #include <thread>
 #include <vector>
@@ -92,4 +95,8 @@
             t.join();
         q.join();
     }
+
+#if TEST_STD_VER > 14
+	std::shared_lock sl(m);	// deduction guide
+#endif
 }
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/types.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/types.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/types.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class Mutex...>
+// class scoped_lock
+// {
+// public:
+//     typedef Mutex mutex_type;  // only if sizeof...(Mutex) == 1
+//     ...
+// };
+
+#include <mutex>
+#include <type_traits>
+#include "test_macros.h"
+
+struct NAT {};
+
+template <class LG>
+auto test_typedef(int) -> typename LG::mutex_type;
+
+template <class LG>
+auto test_typedef(...) -> NAT;
+
+template <class LG>
+constexpr bool has_mutex_type() {
+    return !std::is_same<decltype(test_typedef<LG>(0)), NAT>::value;
+}
+
+int main()
+{
+    {
+        using T = std::scoped_lock<>;
+        static_assert(!has_mutex_type<T>(), "");
+    }
+    {
+        using M1 = std::mutex;
+        using T = std::scoped_lock<M1>;
+        static_assert(std::is_same<T::mutex_type, M1>::value, "");
+    }
+    {
+        using M1 = std::recursive_mutex;
+        using T = std::scoped_lock<M1>;
+        static_assert(std::is_same<T::mutex_type, M1>::value, "");
+    }
+    {
+        using M1 = std::mutex;
+        using M2 = std::recursive_mutex;
+        using T = std::scoped_lock<M1, M2>;
+        static_assert(!has_mutex_type<T>(), "");
+    }
+    {
+        using M1 = std::mutex;
+        using M2 = std::recursive_mutex;
+        using T = std::scoped_lock<M1, M1, M2>;
+        static_assert(!has_mutex_type<T>(), "");
+    }
+    {
+        using M1 = std::mutex;
+        using T = std::scoped_lock<M1, M1>;
+        static_assert(!has_mutex_type<T>(), "");
+    }
+    {
+        using M1 = std::recursive_mutex;
+        using T = std::scoped_lock<M1, M1, M1>;
+        static_assert(!has_mutex_type<T>(), "");
+    }
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class ...Mutex> class scoped_lock;
+
+// explicit scoped_lock(mutex_type& m);
+
+#include <mutex>
+#include <cassert>
+#include "test_macros.h"
+
+struct TestMutex {
+    bool locked = false;
+    TestMutex() = default;
+    ~TestMutex() { assert(!locked); }
+
+    void lock() { assert(!locked); locked = true; }
+    bool try_lock() { if (locked) return false; locked = true; return true; }
+    void unlock() { assert(locked); locked = false; }
+
+    TestMutex(TestMutex const&) = delete;
+    TestMutex& operator=(TestMutex const&) = delete;
+};
+
+#if !defined(TEST_HAS_NO_EXCEPTIONS)
+struct TestMutexThrows {
+    bool locked = false;
+    bool throws_on_lock = false;
+
+    TestMutexThrows() = default;
+    ~TestMutexThrows() { assert(!locked); }
+
+    void lock() {
+        assert(!locked);
+        if (throws_on_lock) {
+            throw 42;
+        }
+        locked = true;
+    }
+
+    bool try_lock() {
+        if (locked) return false;
+        lock();
+        return true;
+    }
+
+    void unlock() { assert(locked); locked = false; }
+
+    TestMutexThrows(TestMutexThrows const&) = delete;
+    TestMutexThrows& operator=(TestMutexThrows const&) = delete;
+};
+#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
+
+int main()
+{
+    {
+        using LG = std::scoped_lock<>;
+        LG lg;
+    }
+    {
+        using LG = std::scoped_lock<TestMutex>;
+        TestMutex m1;
+        {
+            LG lg(m1);
+            assert(m1.locked);
+        }
+        assert(!m1.locked);
+    }
+    {
+        using LG = std::scoped_lock<TestMutex, TestMutex>;
+        TestMutex m1, m2;
+        {
+            LG lg(m1, m2);
+            assert(m1.locked && m2.locked);
+        }
+        assert(!m1.locked && !m2.locked);
+    }
+    {
+        using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
+        TestMutex m1, m2, m3;
+        {
+            LG lg(m1, m2, m3);
+            assert(m1.locked && m2.locked && m3.locked);
+        }
+        assert(!m1.locked && !m2.locked && !m3.locked);
+    }
+#if !defined(TEST_HAS_NO_EXCEPTIONS)
+    {
+        using MT = TestMutexThrows;
+        using LG = std::scoped_lock<MT>;
+        MT m1;
+        m1.throws_on_lock = true;
+        try {
+            LG lg(m1);
+            assert(false);
+        } catch (int) {}
+        assert(!m1.locked);
+    }
+    {
+        using MT = TestMutexThrows;
+        using LG = std::scoped_lock<MT, MT>;
+        MT m1, m2;
+        m1.throws_on_lock = true;
+        try {
+            LG lg(m1, m2);
+            assert(false);
+        } catch (int) {}
+        assert(!m1.locked && !m2.locked);
+    }
+    {
+        using MT = TestMutexThrows;
+        using LG = std::scoped_lock<MT, MT, MT>;
+        MT m1, m2, m3;
+        m2.throws_on_lock = true;
+        try {
+            LG lg(m1, m2, m3);
+            assert(false);
+        } catch (int) {}
+        assert(!m1.locked && !m2.locked && !m3.locked);
+    }
+#endif
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.fail.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class ...Mutex> class scoped_lock;
+
+// explicit scoped_lock(Mutex&...);
+
+#include <mutex>
+#include "test_macros.h"
+
+template <class LG>
+void test_conversion(LG) {}
+
+int main()
+{
+    using M = std::mutex;
+    M m0, m1, m2;
+    M n0, n1, n2;
+    {
+        using LG = std::scoped_lock<>;
+        LG lg = {}; // expected-error{{chosen constructor is explicit in copy-initialization}}
+        test_conversion<LG>({}); // expected-error{{no matching function for call}}
+        ((void)lg);
+    }
+    {
+        using LG = std::scoped_lock<M>;
+        LG lg = {m0}; // expected-error{{chosen constructor is explicit in copy-initialization}}
+        test_conversion<LG>({n0}); // expected-error{{no matching function for call}}
+        ((void)lg);
+    }
+    {
+        using LG = std::scoped_lock<M, M>;
+        LG lg = {m0, m1}; // expected-error{{chosen constructor is explicit in copy-initialization}}
+        test_conversion<LG>({n0, n1}); // expected-error{{no matching function for call}}
+        ((void)lg);
+    }
+    {
+        using LG = std::scoped_lock<M, M, M>;
+        LG lg = {m0, m1, m2}; // expected-error{{chosen constructor is explicit in copy-initialization}}
+        test_conversion<LG>({n0, n1, n2}); // expected-error{{no matching function for call}}
+    }
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/copy.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/copy.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/copy.fail.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class ...Mutex> class scoped_lock;
+
+// scoped_lock(scoped_lock const&) = delete;
+
+#include <mutex>
+#include "test_macros.h"
+
+int main()
+{
+    using M = std::mutex;
+    M m0, m1, m2;
+    {
+        using LG = std::scoped_lock<>;
+        const LG Orig;
+        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
+    }
+    {
+        using LG = std::scoped_lock<M>;
+        const LG Orig(m0);
+        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
+    }
+    {
+        using LG = std::scoped_lock<M, M>;
+        const LG Orig(m0, m1);
+        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
+    }
+    {
+        using LG = std::scoped_lock<M, M, M>;
+        const LG Orig(m0, m1, m2);
+        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
+    }
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/assign.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/assign.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/assign.fail.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class ...Mutex> class scoped_lock;
+
+// scoped_lock& operator=(scoped_lock const&) = delete;
+
+#include <mutex>
+#include "test_macros.h"
+
+int main()
+{
+    using M = std::mutex;
+    M m0, m1, m2;
+    M om0, om1, om2;
+    {
+        using LG = std::scoped_lock<>;
+        LG lg1, lg2;
+        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
+    }
+    {
+        using LG = std::scoped_lock<M>;
+        LG lg1(m0);
+        LG lg2(om0);
+        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
+    }
+    {
+        using LG = std::scoped_lock<M, M>;
+        LG lg1(m0, m1);
+        LG lg2(om0, om1);
+        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
+    }
+    {
+        using LG = std::scoped_lock<M, M, M>;
+        LG lg1(m0, m1, m2);
+        LG lg2(om0, om1, om2);
+        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
+    }
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/adopt_lock.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/adopt_lock.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/adopt_lock.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <mutex>
+
+// template <class ...Mutex> class scoped_lock;
+
+// scoped_lock(Mutex&..., adopt_lock_t);
+
+#include <mutex>
+#include <cassert>
+#include "test_macros.h"
+
+struct TestMutex {
+    bool locked = false;
+    TestMutex() = default;
+
+    void lock() { assert(!locked); locked = true; }
+    bool try_lock() { if (locked) return false; locked = true; return true; }
+    void unlock() { assert(locked); locked = false; }
+
+    TestMutex(TestMutex const&) = delete;
+    TestMutex& operator=(TestMutex const&) = delete;
+};
+
+int main()
+{
+    {
+        using LG = std::scoped_lock<>;
+        LG lg(std::adopt_lock);
+    }
+    {
+        TestMutex m1;
+        using LG = std::scoped_lock<TestMutex>;
+        m1.lock();
+        {
+            LG lg(m1, std::adopt_lock);
+            assert(m1.locked);
+        }
+        assert(!m1.locked);
+    }
+    {
+        TestMutex m1, m2;
+        using LG = std::scoped_lock<TestMutex, TestMutex>;
+        m1.lock(); m2.lock();
+        {
+            LG lg(m1, m2, std::adopt_lock);
+            assert(m1.locked && m2.locked);
+        }
+        assert(!m1.locked && !m2.locked);
+    }
+    {
+        TestMutex m1, m2, m3;
+        using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
+        m1.lock(); m2.lock(); m3.lock();
+        {
+            LG lg(m1, m2, m3, std::adopt_lock);
+            assert(m1.locked && m2.locked && m3.locked);
+        }
+        assert(!m1.locked && !m2.locked && !m3.locked);
+    }
+
+}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
@@ -1,79 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class Mutex>
-// class lock_guard
-// {
-// public:
-//     typedef Mutex mutex_type;
-//     ...
-// };
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-#include <type_traits>
-
-struct NAT {};
-
-template <class LG>
-auto test_typedef(int) -> typename LG::mutex_type;
-
-template <class LG>
-auto test_typedef(...) -> NAT;
-
-template <class LG>
-constexpr bool has_mutex_type() {
-    return !std::is_same<decltype(test_typedef<LG>(0)), NAT>::value;
-}
-
-int main()
-{
-    {
-        using T = std::lock_guard<>;
-        static_assert(!has_mutex_type<T>(), "");
-    }
-    {
-        using M1 = std::mutex;
-        using T = std::lock_guard<M1>;
-        static_assert(std::is_same<T::mutex_type, M1>::value, "");
-    }
-    {
-        using M1 = std::recursive_mutex;
-        using T = std::lock_guard<M1>;
-        static_assert(std::is_same<T::mutex_type, M1>::value, "");
-    }
-    {
-        using M1 = std::mutex;
-        using M2 = std::recursive_mutex;
-        using T = std::lock_guard<M1, M2>;
-        static_assert(!has_mutex_type<T>(), "");
-    }
-    {
-        using M1 = std::mutex;
-        using M2 = std::recursive_mutex;
-        using T = std::lock_guard<M1, M1, M2>;
-        static_assert(!has_mutex_type<T>(), "");
-    }
-    {
-        using M1 = std::mutex;
-        using T = std::lock_guard<M1, M1>;
-        static_assert(!has_mutex_type<T>(), "");
-    }
-    {
-        using M1 = std::recursive_mutex;
-        using T = std::lock_guard<M1, M1, M1>;
-        static_assert(!has_mutex_type<T>(), "");
-    }
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
@@ -1,21 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// Test that the variadic lock guard implementation compiles in all standard
-// dialects, including C++03, even though it is forward declared using
-// variadic templates.
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include "mutex.pass.cpp" // Use the existing non-variadic test
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
@@ -1,116 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// explicit lock_guard(mutex_type& m);
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-#include <cassert>
-
-#include "test_macros.h"
-
-struct TestMutex {
-    bool locked = false;
-    TestMutex() = default;
-    ~TestMutex() { assert(!locked); }
-
-    void lock() { assert(!locked); locked = true; }
-    bool try_lock() { if (locked) return false; locked = true; return true; }
-    void unlock() { assert(locked); locked = false; }
-
-    TestMutex(TestMutex const&) = delete;
-    TestMutex& operator=(TestMutex const&) = delete;
-};
-
-#if !defined(TEST_HAS_NO_EXCEPTIONS)
-struct TestMutexThrows {
-    bool locked = false;
-    bool throws_on_lock = false;
-
-    TestMutexThrows() = default;
-    ~TestMutexThrows() { assert(!locked); }
-
-    void lock() {
-        assert(!locked);
-        if (throws_on_lock) {
-            throw 42;
-        }
-        locked = true;
-    }
-
-    bool try_lock() {
-        if (locked) return false;
-        lock();
-        return true;
-    }
-
-    void unlock() { assert(locked); locked = false; }
-
-    TestMutexThrows(TestMutexThrows const&) = delete;
-    TestMutexThrows& operator=(TestMutexThrows const&) = delete;
-};
-#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
-
-int main()
-{
-    {
-        using LG = std::lock_guard<>;
-        LG lg;
-    }
-    {
-        using LG = std::lock_guard<TestMutex, TestMutex>;
-        TestMutex m1, m2;
-        {
-            LG lg(m1, m2);
-            assert(m1.locked && m2.locked);
-        }
-        assert(!m1.locked && !m2.locked);
-    }
-    {
-        using LG = std::lock_guard<TestMutex, TestMutex, TestMutex>;
-        TestMutex m1, m2, m3;
-        {
-            LG lg(m1, m2, m3);
-            assert(m1.locked && m2.locked && m3.locked);
-        }
-        assert(!m1.locked && !m2.locked && !m3.locked);
-    }
-#if !defined(TEST_HAS_NO_EXCEPTIONS)
-    {
-        using MT = TestMutexThrows;
-        using LG = std::lock_guard<MT, MT>;
-        MT m1, m2;
-        m1.throws_on_lock = true;
-        try {
-            LG lg(m1, m2);
-            assert(false);
-        } catch (int) {}
-        assert(!m1.locked && !m2.locked);
-    }
-    {
-        using MT = TestMutexThrows;
-        using LG = std::lock_guard<MT, MT, MT>;
-        MT m1, m2, m3;
-        m2.throws_on_lock = true;
-        try {
-            LG lg(m1, m2, m3);
-            assert(false);
-        } catch (int) {}
-        assert(!m1.locked && !m2.locked && !m3.locked);
-    }
-#endif
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
@@ -1,48 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// explicit lock_guard(Mutex&...);
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-
-template <class LG>
-void test_conversion(LG) {}
-
-int main()
-{
-    using M = std::mutex;
-    M m0, m1, m2;
-    M n0, n1, n2;
-    {
-        using LG = std::lock_guard<>;
-        LG lg = {}; // expected-error{{chosen constructor is explicit in copy-initialization}}
-        test_conversion<LG>({}); // expected-error{{no matching function for call}}
-        ((void)lg);
-    }
-    {
-        using LG = std::lock_guard<M, M>;
-        LG lg = {m0, m1}; // expected-error{{chosen constructor is explicit in copy-initialization}}
-        test_conversion<LG>({n0, n1}); // expected-error{{no matching function for call}}
-        ((void)lg);
-    }
-    {
-        using LG = std::lock_guard<M, M, M>;
-        LG lg = {m0, m1, m2}; // expected-error{{chosen constructor is explicit in copy-initialization}}
-        test_conversion<LG>({n0, n1, n2}); // expected-error{{no matching function for call}}
-    }
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
@@ -1,42 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// lock_guard(lock_guard const&) = delete;
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-
-int main()
-{
-    using M = std::mutex;
-    M m0, m1, m2;
-    {
-        using LG = std::lock_guard<>;
-        const LG Orig;
-        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
-    }
-    {
-        using LG = std::lock_guard<M, M>;
-        const LG Orig(m0, m1);
-        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
-    }
-    {
-        using LG = std::lock_guard<M, M, M>;
-        const LG Orig(m0, m1, m2);
-        LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}}
-    }
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
@@ -1,45 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// lock_guard& operator=(lock_guard const&) = delete;
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-
-int main()
-{
-    using M = std::mutex;
-    M m0, m1, m2;
-    M om0, om1, om2;
-    {
-        using LG = std::lock_guard<>;
-        LG lg1, lg2;
-        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
-    }
-    {
-        using LG = std::lock_guard<M, M>;
-        LG lg1(m0, m1);
-        LG lg2(om0, om1);
-        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
-    }
-    {
-        using LG = std::lock_guard<M, M, M>;
-        LG lg1(m0, m1, m2);
-        LG lg2(om0, om1, om2);
-        lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}}
-    }
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
@@ -1,63 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-// UNSUPPORTED: c++98, c++03
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// lock_guard(Mutex&..., adopt_lock_t);
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-#include <cassert>
-
-struct TestMutex {
-    bool locked = false;
-    TestMutex() = default;
-
-    void lock() { assert(!locked); locked = true; }
-    bool try_lock() { if (locked) return false; locked = true; return true; }
-    void unlock() { assert(locked); locked = false; }
-
-    TestMutex(TestMutex const&) = delete;
-    TestMutex& operator=(TestMutex const&) = delete;
-};
-
-int main()
-{
-    {
-        using LG = std::lock_guard<>;
-        LG lg(std::adopt_lock);
-    }
-    {
-        TestMutex m1, m2;
-        using LG = std::lock_guard<TestMutex, TestMutex>;
-        m1.lock(); m2.lock();
-        {
-            LG lg(m1, m2, std::adopt_lock);
-            assert(m1.locked && m2.locked);
-        }
-        assert(!m1.locked && !m2.locked);
-    }
-    {
-        TestMutex m1, m2, m3;
-        using LG = std::lock_guard<TestMutex, TestMutex, TestMutex>;
-        m1.lock(); m2.lock(); m3.lock();
-        {
-            LG lg(m1, m2, m3, std::adopt_lock);
-            assert(m1.locked && m2.locked && m3.locked);
-        }
-        assert(!m1.locked && !m2.locked && !m3.locked);
-    }
-
-}
Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.pass.cpp
===================================================================
--- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.pass.cpp
+++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.pass.cpp
@@ -15,11 +15,16 @@
 
 // explicit lock_guard(mutex_type& m);
 
+// template<class _Mutex> lock_guard(lock_guard<_Mutex>)
+//     -> lock_guard<_Mutex>;  // C++17
+
 #include <mutex>
 #include <thread>
 #include <cstdlib>
 #include <cassert>
 
+#include "test_macros.h"
+
 std::mutex m;
 
 typedef std::chrono::system_clock Clock;
@@ -47,4 +52,8 @@
     std::this_thread::sleep_for(ms(250));
     m.unlock();
     t.join();
+	
+#if TEST_STD_VER > 14
+	std::lock_guard lg(m);	// deduction guide
+#endif
 }
Index: test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
===================================================================
--- test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
+++ test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
@@ -1,37 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-
-// TODO(EricWF) Investigate why typeid(...).name() returns a different string
-// on GCC 4.9 but not newer GCCs.
-// XFAIL: gcc-4.9
-// XFAIL: windows
-
-// THIS TESTS C++03 EXTENSIONS.
-
-// <mutex>
-
-// template <class ...Mutex> class lock_guard;
-
-// Test that the the variadic lock guard implementation mangles the same in
-// C++11 and C++03. This is important since the mangling of `lock_guard` depends
-// on it being declared as a variadic template, even in C++03.
-
-// MODULES_DEFINES: _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
-#include <mutex>
-#include <string>
-#include <typeinfo>
-#include <cassert>
-
-int main() {
-    const std::string expect = "NSt3__110lock_guardIJNS_5mutexEEEE";
-    assert(typeid(std::lock_guard<std::mutex>).name() == expect);
-}
Index: include/shared_mutex
===================================================================
--- include/shared_mutex
+++ include/shared_mutex
@@ -116,6 +116,9 @@
     mutex_type* mutex() const noexcept;
 };
 
+template<class M> shared_lock(shared_lock<M>)
+    -> shared_lock<M>;  // C++17
+
 template <class Mutex>
     void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
 
@@ -175,7 +178,7 @@
 #if _LIBCPP_STD_VER > 14
 class _LIBCPP_TYPE_VIS shared_mutex
 {
-	__shared_mutex_base __base;
+    __shared_mutex_base __base;
 public:
     shared_mutex() : __base() {}
     _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
@@ -201,7 +204,7 @@
 
 class _LIBCPP_TYPE_VIS shared_timed_mutex
 {
-	__shared_mutex_base __base;
+    __shared_mutex_base __base;
 public:
     shared_timed_mutex();
     _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
@@ -488,6 +491,11 @@
     __owns_ = false;
 }
 
+#if _LIBCPP_STD_VER > 14
+template<class _Mutex> shared_lock(shared_lock<_Mutex>)
+  -> shared_lock<_Mutex>;
+#endif
+
 template <class _Mutex>
 inline _LIBCPP_INLINE_VISIBILITY
 void
Index: include/mutex
===================================================================
--- include/mutex
+++ include/mutex
@@ -109,19 +109,27 @@
     lock_guard& operator=(lock_guard const&) = delete;
 };
 
-template <class... MutexTypes> // Variadic lock_guard only provided in ABI V2.
-class lock_guard
+template<class M> lock_guard(lock_guard<M>) 
+    -> lock_guard<M>; // C++17
+
+template <class... MutexTypes>
+class scoped_lock // C++17
 {
 public:
-    explicit lock_guard(MutexTypes&... m);
-    lock_guard(MutexTypes&... m, adopt_lock_t);
-    ~lock_guard();
-    lock_guard(lock_guard const&) = delete;
-    lock_guard& operator=(lock_guard const&) = delete;
+    using mutex_type = Mutex;  // If MutexTypes... consists of the single type Mutex
+
+    explicit scoped_lock(MutexTypes&... m);
+    scoped_lock(MutexTypes&... m, adopt_lock_t);
+    ~scoped_lock();
+    scoped_lock(scoped_lock const&) = delete;
+    scoped_lock& operator=(scoped_lock const&) = delete;
 private:
     tuple<MutexTypes&...> pm; // exposition only
 };
 
+template<class... M> scoped_lock(scoped_lock<M...>) 
+    -> scoped_lock<M...>; // C++17
+
 template <class Mutex>
 class unique_lock
 {
@@ -165,6 +173,9 @@
 template <class Mutex>
   void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
 
+template<class M> unique_lock(unique_lock<M>)
+    -> unique_lock<M>; // C++17
+
 template <class L1, class L2, class... L3>
   int try_lock(L1&, L2&, L3&...);
 template <class L1, class L2, class... L3>
@@ -614,31 +625,53 @@
 
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
+#if _LIBCPP_STD_VER > 14
+template <class ..._Mutexes>
+class _LIBCPP_TEMPLATE_VIS scoped_lock;
 
-#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) \
-    && !defined(_LIBCPP_CXX03_LANG)
 template <>
-class _LIBCPP_TEMPLATE_VIS lock_guard<> {
+class _LIBCPP_TEMPLATE_VIS scoped_lock<> {
 public:
-    explicit lock_guard() {}
-    ~lock_guard() = default;
+    explicit scoped_lock() {}
+    ~scoped_lock() = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    explicit lock_guard(adopt_lock_t) {}
+    explicit scoped_lock(adopt_lock_t) {}
 
-    lock_guard(lock_guard const&) = delete;
-    lock_guard& operator=(lock_guard const&) = delete;
+    scoped_lock(scoped_lock const&) = delete;
+    scoped_lock& operator=(scoped_lock const&) = delete;
 };
 
+template <class _Mutex>
+class _LIBCPP_TEMPLATE_VIS scoped_lock<_Mutex> {
+public:
+    typedef _Mutex  mutex_type;
+private:
+    mutex_type& __m_;
+public:
+    explicit scoped_lock(mutex_type & __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
+        : __m_(__m) {__m_.lock();}
+
+    ~scoped_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit scoped_lock(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
+        : __m_(__m) {}
+    
+
+    scoped_lock(scoped_lock const&) = delete;
+    scoped_lock& operator=(scoped_lock const&) = delete;
+};
+
 template <class ..._MArgs>
-class _LIBCPP_TEMPLATE_VIS lock_guard
+class _LIBCPP_TEMPLATE_VIS scoped_lock
 {
-    static_assert(sizeof...(_MArgs) >= 2, "At least 2 lock types required");
+    static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
     typedef tuple<_MArgs&...> _MutexTuple;
 
 public:
     _LIBCPP_INLINE_VISIBILITY
-    explicit lock_guard(_MArgs&... __margs)
+    explicit scoped_lock(_MArgs&... __margs)
       : __t_(__margs...)
     {
         _VSTD::lock(__margs...);
@@ -645,19 +678,19 @@
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    lock_guard(_MArgs&... __margs, adopt_lock_t)
+    scoped_lock(_MArgs&... __margs, adopt_lock_t)
         : __t_(__margs...)
     {
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    ~lock_guard() {
+    ~scoped_lock() {
         typedef typename __make_tuple_indices<sizeof...(_MArgs)>::type _Indices;
         __unlock_unpack(_Indices{}, __t_);
     }
 
-    lock_guard(lock_guard const&) = delete;
-    lock_guard& operator=(lock_guard const&) = delete;
+    scoped_lock(scoped_lock const&) = delete;
+    scoped_lock& operator=(scoped_lock const&) = delete;
 
 private:
     template <size_t ..._Indx>
@@ -669,8 +702,11 @@
     _MutexTuple __t_;
 };
 
-#endif // _LIBCPP_ABI_VARIADIC_LOCK_GUARD
+template<class... _Mutexes> scoped_lock(scoped_lock<_Mutexes...>)
+  -> scoped_lock<_Mutexes...>;
 
+#endif // _LIBCPP_STD_VER > 14
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_MUTEX
Index: include/__mutex_base
===================================================================
--- include/__mutex_base
+++ include/__mutex_base
@@ -80,21 +80,9 @@
 
 #endif
 
-
-// Forward declare lock_guard as a variadic template even in C++03 to keep
-// the mangling consistent between dialects.
-#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD)
-template <class ..._Mutexes>
-class _LIBCPP_TEMPLATE_VIS lock_guard;
-#endif
-
 template <class _Mutex>
 class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
-#if !defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD)
 lock_guard
-#else
-lock_guard<_Mutex>
-#endif
 {
 public:
     typedef _Mutex mutex_type;
@@ -117,6 +105,11 @@
     lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
 };
 
+#if _LIBCPP_STD_VER > 14
+template<class _Mutex> lock_guard(lock_guard<_Mutex>)
+    -> lock_guard<_Mutex>;
+#endif
+
 template <class _Mutex>
 class _LIBCPP_TEMPLATE_VIS unique_lock
 {
@@ -215,6 +208,11 @@
     mutex_type* mutex() const _NOEXCEPT {return __m_;}
 };
 
+#if _LIBCPP_STD_VER > 14
+template<class _Mutex> unique_lock(unique_lock<_Mutex>)
+    -> unique_lock<_Mutex>;
+#endif
+
 template <class _Mutex>
 void
 unique_lock<_Mutex>::lock()
Index: include/__config
===================================================================
--- include/__config
+++ include/__config
@@ -49,7 +49,6 @@
 #define _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
 #define _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB
 #define _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE
-#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
 // Don't use a nullptr_t simulation type in C++03 instead using C++11 nullptr
 // provided under the alternate keyword __nullptr, which changes the mangling
 // of nullptr_t. This option is ABI incompatible with GCC in C++03 mode.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to