[libcxx] r272634 - Implement variadic lock_guard.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 13 20:48:10 PDT 2016


Author: ericwf
Date: Mon Jun 13 22:48:09 2016
New Revision: 272634

URL: http://llvm.org/viewvc/llvm-project?rev=272634&view=rev
Log:
Implement variadic lock_guard.

Summary:
This patch implements the variadic `lock_guard` paper. 

Making `lock_guard` variadic is a ABI breaking change because the specialization `lock_guard<_Mutex>` mangles differently then when it was the primary template. This change only provides variadic `lock_guard` in ABI V2 or when `_LIBCPP_ABI_VARIADIC_LOCK_GUARD` is defined.

Note that in ABI V2 `lock_guard` must always be declared as a variadic template, even in C++03, in order to keep the ABI consistent. For this reason `lock_guard` is forward declared as a variadic template in all standard dialects and therefore depends on variadic templates being provided as an extension in C++03. All supported versions of Clang and GCC provide this extension.




Reviewers: mclow.lists

Subscribers: K-ballo, mclow.lists, cfe-commits

Differential Revision: http://reviews.llvm.org/D21260

Added:
    libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/
    libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/
    libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/__mutex_base
    libcxx/trunk/include/mutex
    libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp
    libcxx/trunk/www/cxx1z_status.html

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=272634&r1=272633&r2=272634&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Mon Jun 13 22:48:09 2016
@@ -43,6 +43,7 @@
 #define _LIBCPP_ABI_LIST_REMOVE_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
 #endif
 
 #define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y

Modified: libcxx/trunk/include/__mutex_base
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__mutex_base?rev=272634&r1=272633&r2=272634&view=diff
==============================================================================
--- libcxx/trunk/include/__mutex_base (original)
+++ libcxx/trunk/include/__mutex_base Mon Jun 13 22:48:09 2016
@@ -76,8 +76,21 @@ constexpr adopt_lock_t  adopt_lock  = ad
 
 #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_TYPE_VIS_ONLY lock_guard;
+#endif
+
 template <class _Mutex>
-class _LIBCPP_TYPE_VIS_ONLY _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard
+class _LIBCPP_TYPE_VIS_ONLY _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;
@@ -96,8 +109,8 @@ public:
     ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
 
 private:
-    lock_guard(lock_guard const&);// = delete;
-    lock_guard& operator=(lock_guard const&);// = delete;
+    lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
+    lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
 };
 
 template <class _Mutex>

Modified: libcxx/trunk/include/mutex
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/mutex?rev=272634&r1=272633&r2=272634&view=diff
==============================================================================
--- libcxx/trunk/include/mutex (original)
+++ libcxx/trunk/include/mutex Mon Jun 13 22:48:09 2016
@@ -109,6 +109,19 @@ public:
     lock_guard& operator=(lock_guard const&) = delete;
 };
 
+template <class... MutexTypes> // Variadic lock_guard only provided in ABI V2.
+class lock_guard
+{
+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;
+private:
+    tuple<MutexTypes&...> pm; // exposition only
+};
+
 template <class Mutex>
 class unique_lock
 {
@@ -427,6 +440,27 @@ lock(_L0& __l0, _L1& __l1, _L2& __l2, _L
     __lock_first(0, __l0, __l1, __l2, __l3...);
 }
 
+template <class _L0>
+inline _LIBCPP_INLINE_VISIBILITY
+void __unlock(_L0& __l0) {
+    __l0.unlock();
+}
+
+template <class _L0, class _L1>
+inline _LIBCPP_INLINE_VISIBILITY
+void __unlock(_L0& __l0, _L1& __l1) {
+    __l0.unlock();
+    __l1.unlock();
+}
+
+template <class _L0, class _L1, class _L2, class ..._L3>
+inline _LIBCPP_INLINE_VISIBILITY
+void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
+    __l0.unlock();
+    __l1.unlock();
+    _VSTD::__unlock(__l2, __l3...);
+}
+
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
 #endif // !_LIBCPP_HAS_NO_THREADS
@@ -577,6 +611,63 @@ call_once(once_flag& __flag, const _Call
 
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
+
+#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) \
+    && !defined(_LIBCPP_CXX03_LANG)
+template <>
+class _LIBCPP_TYPE_VIS_ONLY lock_guard<> {
+public:
+    explicit lock_guard() = default;
+    ~lock_guard() = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit lock_guard(adopt_lock_t) {}
+
+    lock_guard(lock_guard const&) = delete;
+    lock_guard& operator=(lock_guard const&) = delete;
+};
+
+template <class ..._MArgs>
+class _LIBCPP_TYPE_VIS_ONLY lock_guard
+{
+    static_assert(sizeof...(_MArgs) >= 2, "At least 2 lock types required");
+    typedef tuple<_MArgs&...> _MutexTuple;
+
+public:
+    _LIBCPP_INLINE_VISIBILITY
+    explicit lock_guard(_MArgs&... __margs)
+      : __t_(__margs...)
+    {
+        _VSTD::lock(__margs...);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    lock_guard(_MArgs&... __margs, adopt_lock_t)
+        : __t_(__margs...)
+    {
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    ~lock_guard() {
+        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;
+
+private:
+    template <size_t ..._Indx>
+    _LIBCPP_INLINE_VISIBILITY
+    static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
+        _VSTD::__unlock(_VSTD::get<_Indx>(__mt)...);
+    }
+
+    _MutexTuple __t_;
+};
+
+#endif // _LIBCPP_ABI_VARIADIC_LOCK_GUARD
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_MUTEX

Added: libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_mangling.pass.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// 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.
+
+#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
+#include <mutex>
+#include <typeinfo>
+#include <cassert>
+#include <iostream>
+
+int main() {
+    const std::string expect = "NSt3__110lock_guardIJNS_5mutexEEEE";
+    assert(typeid(std::lock_guard<std::mutex>).name() == expect);
+}

Modified: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp?rev=272634&r1=272633&r2=272634&view=diff
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp (original)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp Mon Jun 13 22:48:09 2016
@@ -7,6 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: libcpp-has-no-threads
+
 // <mutex>
 
 // template <class Mutex> class lock_guard;
@@ -14,35 +16,9 @@
 // explicit lock_guard(mutex_type& m);
 
 #include <mutex>
-#include <thread>
-#include <cstdlib>
-#include <cassert>
-
-std::mutex m;
-
-typedef std::chrono::system_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f()
-{
-    time_point t0 = Clock::now();
-    time_point t1;
-    {
-    std::lock_guard<std::mutex> lg = m;
-    t1 = Clock::now();
-    }
-    ns d = t1 - t0 - ms(250);
-    assert(d < ns(2500000));  // within 2.5ms
-}
 
 int main()
 {
-    m.lock();
-    std::thread t(f);
-    std::this_thread::sleep_for(ms(250));
-    m.unlock();
-    t.join();
+    std::mutex m;
+    std::lock_guard<std::mutex> lg = m; // expected-error{{no viable conversion}}
 }

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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);
+
+#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; return locked = 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);
+    }
+
+}

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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;
+
+#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 '='}}
+    }
+}

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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;
+
+#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'}}
+    }
+}

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.fail.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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&...);
+
+#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}}
+    }
+}

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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);
+
+#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
+#include <mutex>
+#include <cassert>
+
+struct TestMutex {
+    bool locked = false;
+    TestMutex() = default;
+    ~TestMutex() { assert(!locked); }
+
+    void lock() { assert(!locked); locked = true; }
+    bool try_lock() { if (locked) return false; return locked = 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
+}

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex_cxx03.pass.cpp Mon Jun 13 22:48:09 2016
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+
+#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD
+#include "mutex.pass.cpp" // Use the existing non-variadic test

Added: libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp?rev=272634&view=auto
==============================================================================
--- libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp (added)
+++ libcxx/trunk/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp Mon Jun 13 22:48:09 2016
@@ -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
+
+// <mutex>
+
+// template <class Mutex>
+// class lock_guard
+// {
+// public:
+//     typedef Mutex mutex_type;
+//     ...
+// };
+
+#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>(), "");
+    }
+}

Modified: libcxx/trunk/www/cxx1z_status.html
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=272634&r1=272633&r2=272634&view=diff
==============================================================================
--- libcxx/trunk/www/cxx1z_status.html (original)
+++ libcxx/trunk/www/cxx1z_status.html Mon Jun 13 22:48:09 2016
@@ -74,7 +74,7 @@
 	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0006R0.html">P0006R0</a></td><td>LWG</td><td>Adopt Type Traits Variable Templates for C++17.</td><td>Kona</td><td>Complete</td><td>3.8</td></tr>
 	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0092R1.html">P0092R1</a></td><td>LWG</td><td>Polishing <chrono></td><td>Kona</td><td>Complete</td><td>3.8</td></tr>
 	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0007R1.html">P0007R1</a></td><td>LWG</td><td>Constant View: A proposal for a <tt>std::as_const</tt> helper function template.</td><td>Kona</td><td>Complete</td><td>3.8</td></tr>
-	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0156R0.htm" >P0156R0</a></td><td>LWG</td><td>Variadic lock_guard(rev 3).</td><td>Kona</td><td></td><td></td></tr>
+	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0156r0.html" >P0156R0</a></td><td>LWG</td><td>Variadic lock_guard(rev 3).</td><td>Kona</td><td>Complete (ABI V2 Only)</td><td>3.9</td></tr>
 	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0074R0.html">P0074R0</a></td><td>LWG</td><td>Making <tt>std::owner_less</tt> more flexible</td><td>Kona</td><td>Complete</td><td>3.8</td></tr>
 	<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/P0013R1.html">P0013R1</a></td><td>LWG</td><td>Logical type traits rev 2</td><td>Kona</td><td>Complete</td><td>3.8</td></tr>
   	<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>




More information about the cfe-commits mailing list