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 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@272634 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -76,8 +76,21 @@ constexpr adopt_lock_t adopt_lock = adopt_lock_t();
|
||||
|
||||
#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>
|
||||
|
||||
@@ -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, _L3& ...__l3)
|
||||
__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 _Callable& __func)
|
||||
|
||||
#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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 '='}}
|
||||
}
|
||||
}
|
||||
@@ -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'}}
|
||||
}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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>(), "");
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user