Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -33,24 +33,6 @@ #define _LIBCPP_ABI_VERSION 1 #endif -#if defined(_LIBCPP_ABI_UNSTABLE) || _LIBCPP_ABI_VERSION >= 2 -// Change short string represention so that string data starts at offset 0, -// improving its alignment in some cases. -#define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT -// Fix deque iterator type in order to support incomplete types. -#define _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE -// Fix undefined behavior in how std::list stores it's linked nodes. -#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 -#endif - -#define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y -#define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) - -#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__,_LIBCPP_ABI_VERSION) - - #ifndef __has_attribute #define __has_attribute(__x) 0 #endif @@ -69,6 +51,27 @@ #define __is_identifier(__x) 1 #endif +#if defined(_LIBCPP_ABI_UNSTABLE) || _LIBCPP_ABI_VERSION >= 2 +// Change short string represention so that string data starts at offset 0, +// improving its alignment in some cases. +#define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +// Fix deque iterator type in order to support incomplete types. +#define _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE +// Fix undefined behavior in how std::list stores it's linked nodes. +#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 +// This secretly requires variadic templates in C++03 to provide a stable ABI in +// in all dialects. All supported compilers provide this extension in system +// headers. GCC has since 2002. +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#endif + +#define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y +#define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) + +#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__,_LIBCPP_ABI_VERSION) + #ifdef __LITTLE_ENDIAN__ #if __LITTLE_ENDIAN__ Index: include/__mutex_base =================================================================== --- include/__mutex_base +++ include/__mutex_base @@ -14,6 +14,7 @@ #include <__config> #include #include +#include #include <__threading_support> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -76,29 +77,6 @@ #endif -template -class _LIBCPP_TYPE_VIS_ONLY _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard -{ -public: - typedef _Mutex mutex_type; - -private: - mutex_type& __m_; -public: - - _LIBCPP_INLINE_VISIBILITY - explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) - : __m_(__m) {__m_.lock();} - _LIBCPP_INLINE_VISIBILITY - lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) - : __m_(__m) {} - _LIBCPP_INLINE_VISIBILITY - ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} - -private: - lock_guard(lock_guard const&);// = delete; - lock_guard& operator=(lock_guard const&);// = delete; -}; template class _LIBCPP_TYPE_VIS_ONLY unique_lock @@ -264,6 +242,234 @@ swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT {__x.swap(__y);} + +template +int +try_lock(_L0& __l0, _L1& __l1) +{ + unique_lock<_L0> __u0(__l0, try_to_lock); + if (__u0.owns_lock()) + { + if (__l1.try_lock()) + { + __u0.release(); + return -1; + } + else + return 1; + } + return 0; +} + +#ifndef _LIBCPP_HAS_NO_VARIADICS + +template +int +try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) +{ + int __r = 0; + unique_lock<_L0> __u0(__l0, try_to_lock); + if (__u0.owns_lock()) + { + __r = try_lock(__l1, __l2, __l3...); + if (__r == -1) + __u0.release(); + else + ++__r; + } + return __r; +} + +#endif // _LIBCPP_HAS_NO_VARIADICS + +template +void +lock(_L0& __l0, _L1& __l1) +{ + while (true) + { + { + unique_lock<_L0> __u0(__l0); + if (__l1.try_lock()) + { + __u0.release(); + break; + } + } + sched_yield(); + { + unique_lock<_L1> __u1(__l1); + if (__l0.try_lock()) + { + __u1.release(); + break; + } + } + sched_yield(); + } +} + +#ifndef _LIBCPP_HAS_NO_VARIADICS +template +void +__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) +{ + while (true) + { + switch (__i) + { + case 0: + { + unique_lock<_L0> __u0(__l0); + __i = try_lock(__l1, __l2, __l3...); + if (__i == -1) + { + __u0.release(); + return; + } + } + ++__i; + sched_yield(); + break; + case 1: + { + unique_lock<_L1> __u1(__l1); + __i = try_lock(__l2, __l3..., __l0); + if (__i == -1) + { + __u1.release(); + return; + } + } + if (__i == sizeof...(_L3) + 1) + __i = 0; + else + __i += 2; + sched_yield(); + break; + default: + __lock_first(__i - 2, __l2, __l3..., __l0, __l1); + return; + } + } +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void +lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) +{ + __lock_first(0, __l0, __l1, __l2, __l3...); +} + +#endif // _LIBCPP_HAS_NO_VARIADICS + +#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) +template +class _LIBCPP_TYPE_VIS_ONLY lock_guard; +#endif + +template +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; + +private: + mutex_type& __m_; +public: + + _LIBCPP_INLINE_VISIBILITY + explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m)) + : __m_(__m) {__m_.lock();} + _LIBCPP_INLINE_VISIBILITY + lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) + : __m_(__m) {} + _LIBCPP_INLINE_VISIBILITY + ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();} + +private: + lock_guard(lock_guard const&);// = delete; + lock_guard& operator=(lock_guard const&);// = delete; +}; + + +#if defined(_LIBCPP_ABI_VARIADIC_LOCK_GUARD) \ + && !defined(_LIBCPP_CXX03_LANG) +template <> +struct _LIBCPP_TYPE_VIS_ONLY lock_guard<> { + explicit lock_guard() = default; + ~lock_guard() = default; + + _LIBCPP_INLINE_VISIBILITY + explicit lock_guard(adopt_lock_t) {} + + explicit lock_guard(lock_guard const&) = delete; + lock_guard& operator=(lock_guard const&) = delete; +}; + +template +struct __lock_guard_base {}; + +template +struct __lock_guard_base<_Mutex, true> { + typedef _Mutex mutex_type; +}; + +template +class _LIBCPP_TYPE_VIS_ONLY lock_guard<_M1, _M2, _MRest...> + : public __lock_guard_base<_M1, __all::value, + is_same<_M1, _MRest>::value...>::value> +{ + typedef tuple<_M1&, _M2&, _MRest&...> _MutexTuple; + +public: + _LIBCPP_INLINE_VISIBILITY + explicit lock_guard(_M1& __m1, _M2& __m2, _MRest&... __mrest) + : __t_(__m1, __m2, __mrest...) + { + _VSTD::lock(__m1, __m2, __mrest...); + } + + _LIBCPP_INLINE_VISIBILITY + lock_guard(_M1& __m1, _M2& __m2, _MRest&... __mrest, adopt_lock_t) + : __t_(__m1, __m2, __mrest...) + { + } + + _LIBCPP_INLINE_VISIBILITY + ~lock_guard() { + typedef typename __make_tuple_indices::type _Indices; + __unlock_unpack(_Indices{}, __t_); + } + + lock_guard(lock_guard const&) = delete; + lock_guard& operator=(lock_guard const&) = delete; + +private: + template + _LIBCPP_INLINE_VISIBILITY + static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) + { + _VSTD::__swallow(__unlock(_VSTD::get<_Indx>(__mt))...); + } + + template + _LIBCPP_INLINE_VISIBILITY + static bool __unlock(_Mutex& __m) { + __m.unlock(); return false; + } + + _MutexTuple __t_; +}; + +#endif // _LIBCPP_ABI_VARIADIC_LOCK_GUARD + //enum class cv_status _LIBCPP_DECLARE_STRONG_ENUM(cv_status) { Index: include/mutex =================================================================== --- include/mutex +++ include/mutex @@ -307,128 +307,6 @@ return false; } -template -int -try_lock(_L0& __l0, _L1& __l1) -{ - unique_lock<_L0> __u0(__l0, try_to_lock); - if (__u0.owns_lock()) - { - if (__l1.try_lock()) - { - __u0.release(); - return -1; - } - else - return 1; - } - return 0; -} - -#ifndef _LIBCPP_HAS_NO_VARIADICS - -template -int -try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) -{ - int __r = 0; - unique_lock<_L0> __u0(__l0, try_to_lock); - if (__u0.owns_lock()) - { - __r = try_lock(__l1, __l2, __l3...); - if (__r == -1) - __u0.release(); - else - ++__r; - } - return __r; -} - -#endif // _LIBCPP_HAS_NO_VARIADICS - -template -void -lock(_L0& __l0, _L1& __l1) -{ - while (true) - { - { - unique_lock<_L0> __u0(__l0); - if (__l1.try_lock()) - { - __u0.release(); - break; - } - } - __libcpp_thread_yield(); - { - unique_lock<_L1> __u1(__l1); - if (__l0.try_lock()) - { - __u1.release(); - break; - } - } - __libcpp_thread_yield(); - } -} - -#ifndef _LIBCPP_HAS_NO_VARIADICS - -template -void -__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) -{ - while (true) - { - switch (__i) - { - case 0: - { - unique_lock<_L0> __u0(__l0); - __i = try_lock(__l1, __l2, __l3...); - if (__i == -1) - { - __u0.release(); - return; - } - } - ++__i; - __libcpp_thread_yield(); - break; - case 1: - { - unique_lock<_L1> __u1(__l1); - __i = try_lock(__l2, __l3..., __l0); - if (__i == -1) - { - __u1.release(); - return; - } - } - if (__i == sizeof...(_L3) + 1) - __i = 0; - else - __i += 2; - __libcpp_thread_yield(); - break; - default: - __lock_first(__i - 2, __l2, __l3..., __l0, __l1); - return; - } - } -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void -lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3) -{ - __lock_first(0, __l0, __l1, __l2, __l3...); -} - -#endif // _LIBCPP_HAS_NO_VARIADICS - #endif // !_LIBCPP_HAS_NO_THREADS struct _LIBCPP_TYPE_VIS_ONLY once_flag; Index: include/tuple =================================================================== --- include/tuple +++ include/tuple @@ -376,15 +376,6 @@ }; template -_LIBCPP_INLINE_VISIBILITY -void __swallow(_Tp&&...) _NOEXCEPT {} - -template -struct __all - : is_same<__all<_Pred...>, __all<(_Pred, true)...>> -{ }; - -template struct __lazy_all : __all<_Tp::value...> {}; template Index: include/type_traits =================================================================== --- include/type_traits +++ include/type_traits @@ -4692,6 +4692,15 @@ struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy> : false_type {}; +template +struct __all + : is_same<__all<_Pred...>, __all<(_Pred, true)...> > +{ }; + +template +_LIBCPP_INLINE_VISIBILITY +void __swallow(_Tp&&...) _NOEXCEPT {} + #endif _LIBCPP_END_NAMESPACE_STD Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp =================================================================== --- test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/mutex.fail.cpp @@ -14,35 +14,9 @@ // explicit lock_guard(mutex_type& m); #include -#include -#include -#include - -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 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 lg = m; // expected-error{{no viable conversion}} } Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_adopt_lock.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// + +// template class lock_guard; + +// lock_guard(Mutex&..., adopt_lock_t); + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include +#include + +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; + 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; + 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_assign.fail.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_assign.fail.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++98, c++03 + +// + +// template class lock_guard; + +// lock_guard& operator=(lock_guard const&) = delete; + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include + +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; + LG lg1(m0, m1); + LG lg2(om0, om1); + lg1 = lg2; // expected-error{{overload resolution selected deleted operator '='}} + } + { + using LG = std::lock_guard; + 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_copy.fail.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_copy.fail.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++98, c++03 + +// + +// template class lock_guard; + +// lock_guard(lock_guard const&) = delete; + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include + +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; + const LG Orig(m0, m1); + LG Copy(Orig); // expected-error{{call to deleted constructor of 'LG'}} + } + { + using LG = std::lock_guard; + 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_mutex.fail.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.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: c++98, c++03 + +// + +// template class lock_guard; + +// explicit lock_guard(Mutex&...); + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include + +template +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({}); // expected-error{{no matching function for call}} + ((void)lg); + } + { + using LG = std::lock_guard; + LG lg = {m0, m1}; // expected-error{{chosen constructor is explicit in copy-initialization}} + test_conversion({n0, n1}); // expected-error{{no matching function for call}} + ((void)lg); + } + { + using LG = std::lock_guard; + LG lg = {m0, m1, m2}; // expected-error{{chosen constructor is explicit in copy-initialization}} + test_conversion({n0, n1, n2}); // expected-error{{no matching function for call}} + } +} Index: test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_mutex.pass.cpp @@ -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 + +// + +// template class lock_guard; + +// explicit lock_guard(mutex_type& m); + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include +#include + +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 m1, m2; + { + LG lg(m1, m2); + assert(m1.locked && m2.locked); + } + assert(!m1.locked && !m2.locked); + } + { + using LG = std::lock_guard; + 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 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 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_types.pass.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.lock/thread.lock.guard/variadic_types.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class lock_guard +// { +// public: +// typedef Mutex mutex_type; +// ... +// }; + +#define _LIBCPP_ABI_VARIADIC_LOCK_GUARD +#include +#include + +struct NAT {}; + +template +auto test_typedef(int) -> typename LG::mutex_type; + +template +auto test_typedef(...) -> NAT; + +template +constexpr bool has_mutex_type() { + return !std::is_same(0)), NAT>::value; +} + +int main() +{ + { + using T = std::lock_guard<>; + static_assert(!has_mutex_type(), ""); + } + { + using M1 = std::mutex; + using M2 = std::recursive_mutex; + using T = std::lock_guard; + static_assert(!has_mutex_type(), ""); + } + { + using M1 = std::mutex; + using M2 = std::recursive_mutex; + using T = std::lock_guard; + static_assert(!has_mutex_type(), ""); + } + { + using M1 = std::mutex; + using T = std::lock_guard; + static_assert(std::is_same::value, ""); + } + { + using M1 = std::recursive_mutex; + using T = std::lock_guard; + static_assert(std::is_same::value, ""); + } +} Index: www/cxx1z_status.html =================================================================== --- www/cxx1z_status.html +++ www/cxx1z_status.html @@ -74,7 +74,7 @@ P0006R0LWGAdopt Type Traits Variable Templates for C++17.KonaComplete3.8 P0092R1LWGPolishing <chrono>KonaComplete3.8 P0007R1LWGConstant View: A proposal for a std::as_const helper function template.KonaComplete3.8 - P0156R0LWGVariadic lock_guard(rev 3).Kona + P0156R0LWGVariadic lock_guard(rev 3).Kona P0074R0LWGMaking std::owner_less more flexibleKonaComplete3.8 P0013R1LWGLogical type traits rev 2KonaComplete3.8