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