From 793f59e7676ca997ffe0a919d9135bb3dcad7ecf Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sat, 13 Jun 2015 02:23:00 +0000 Subject: [PATCH] LWG2442: call_once() shouldn't DECAY_COPY(). Patch from K-Ballo. This patch fixes LWG issue 2422 by removing the DECAY_COPY from call once. The review can be found here: http://reviews.llvm.org/D10191 llvm-svn: 239654 --- libcxx/include/mutex | 52 +++++++++++++--------- .../thread.once.callonce/call_once.pass.cpp | 48 +++++++++++++++++++- libcxx/www/cxx1z_status.html | 2 +- 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/libcxx/include/mutex b/libcxx/include/mutex index e2a0daa..0adf1e6 100644 --- a/libcxx/include/mutex +++ b/libcxx/include/mutex @@ -442,7 +442,11 @@ void call_once(once_flag&, _Callable&&, _Args&&...); template _LIBCPP_INLINE_VISIBILITY -void call_once(once_flag&, _Callable); +void call_once(once_flag&, _Callable&); + +template +_LIBCPP_INLINE_VISIBILITY +void call_once(once_flag&, const _Callable&); #endif // _LIBCPP_HAS_NO_VARIADICS @@ -465,7 +469,11 @@ private: #else // _LIBCPP_HAS_NO_VARIADICS template friend - void call_once(once_flag&, _Callable); + void call_once(once_flag&, _Callable&); + + template + friend + void call_once(once_flag&, const _Callable&); #endif // _LIBCPP_HAS_NO_VARIADICS }; @@ -474,15 +482,10 @@ private: template class __call_once_param { - _Fp __f_; + _Fp& __f_; public: -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY - explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {} -#else - _LIBCPP_INLINE_VISIBILITY - explicit __call_once_param(const _Fp& __f) : __f_(__f) {} -#endif + explicit __call_once_param(_Fp& __f) : __f_(__f) {} _LIBCPP_INLINE_VISIBILITY void operator()() @@ -496,7 +499,7 @@ private: _LIBCPP_INLINE_VISIBILITY void __execute(__tuple_indices<_Indices...>) { - __invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...); + __invoke(_VSTD::get<0>(_VSTD::move(__f_)), _VSTD::get<_Indices>(_VSTD::move(__f_))...); } }; @@ -505,15 +508,10 @@ private: template class __call_once_param { - _Fp __f_; + _Fp& __f_; public: -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY - explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {} -#else _LIBCPP_INLINE_VISIBILITY - explicit __call_once_param(const _Fp& __f) : __f_(__f) {} -#endif + explicit __call_once_param(_Fp& __f) : __f_(__f) {} _LIBCPP_INLINE_VISIBILITY void operator()() @@ -543,9 +541,9 @@ call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) { if (__flag.__state_ != ~0ul) { - typedef tuple::type, typename decay<_Args>::type...> _Gp; - __call_once_param<_Gp> __p(_Gp(__decay_copy(_VSTD::forward<_Callable>(__func)), - __decay_copy(_VSTD::forward<_Args>(__args))...)); + typedef tuple<_Callable&&, _Args&&...> _Gp; + _Gp __f(_VSTD::forward<_Callable>(__func), _VSTD::forward<_Args>(__args)...); + __call_once_param<_Gp> __p(__f); __call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>); } } @@ -555,7 +553,7 @@ call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) template inline _LIBCPP_INLINE_VISIBILITY void -call_once(once_flag& __flag, _Callable __func) +call_once(once_flag& __flag, _Callable& __func) { if (__flag.__state_ != ~0ul) { @@ -564,6 +562,18 @@ call_once(once_flag& __flag, _Callable __func) } } +template +inline _LIBCPP_INLINE_VISIBILITY +void +call_once(once_flag& __flag, const _Callable& __func) +{ + if (__flag.__state_ != ~0ul) + { + __call_once_param __p(__func); + __call_once(__flag.__state_, &__p, &__call_once_proxy); + } +} + #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp index 5395c85..89b9934 100644 --- a/libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp +++ b/libcxx/test/std/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp @@ -14,7 +14,7 @@ // struct once_flag; // template -// void call_once(once_flag& flag, Callable func, Args&&... args); +// void call_once(once_flag& flag, Callable&& func, Args&&... args); #include #include @@ -153,6 +153,35 @@ public: } }; +class NonCopyable +{ +#if !defined(__clang__) + // GCC 4.8 complains about the following being private +public: + NonCopyable(const NonCopyable&) + { + } +#else + NonCopyable(const NonCopyable&); +#endif +public: + NonCopyable() {} + + void operator()(int&) {} +}; + +#if __cplusplus >= 201103L +// reference qualifiers on functions are a C++11 extension +struct RefQual +{ + int lv_called, rv_called; + + RefQual() : lv_called(0), rv_called(0) {} + + void operator()() & { ++lv_called; } + void operator()() && { ++rv_called; } +}; +#endif #endif int main() @@ -204,5 +233,22 @@ int main() std::once_flag f; std::call_once(f, MoveOnly(), MoveOnly()); } + // check LWG2442: call_once() shouldn't DECAY_COPY() + { + std::once_flag f; + int i = 0; + std::call_once(f, NonCopyable(), i); + } +#if __cplusplus >= 201103L +// reference qualifiers on functions are a C++11 extension + { + std::once_flag f1, f2; + RefQual rq; + std::call_once(f1, rq); + assert(rq.lv_called == 1); + std::call_once(f2, std::move(rq)); + assert(rq.rv_called == 1); + } +#endif #endif // _LIBCPP_HAS_NO_VARIADICS } diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html index b94fe60..6387616 100644 --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -127,7 +127,7 @@ 2438std::iterator inheritance shouldn't be mandatedLenexaComplete 2439unique_copy() sometimes can't fall back to reading its outputLenexa 2440seed_seq::size() should be noexceptLenexaComplete - 2442call_once() shouldn't DECAY_COPY()Lenexa + 2442call_once() shouldn't DECAY_COPY()LenexaComplete 2448Non-normative Container destructor specificationLenexaComplete 2454Add raw_storage_iterator::base() memberLenexaComplete 2455Allocator default construction should be allowed to throwLenexaComplete -- 2.7.4