This patch ensures everywhere we use std::get we qualify it. It also changes some uses of the built-in operator& with std::__addressof() which doesn't do ADL and so doesn't try to complete its argument.
As noted in the bug report, the operator& part of this affects most of the library, so I don't think it's feasible to do anything about it right now. Tested x86_64-linux, committed to trunk.
commit d3d2b701493ab363cc9820283bf78250f5a52d31 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue May 13 15:35:29 2014 +0100 PR libstdc++/60497 * include/debug/array (get): Qualify call to other get overload. * include/profile/array (get): Likewise. * include/std/array (get): Likewise. * include/std/functional (_Mu, _Bind, _Bind_result): Qualify std::get. * include/std/mutex (unique_lock, call_once): Use __addressof. (__unlock_impl): Remove unused template. (__try_to_lock): Declare inline. (__try_lock_impl::__do_try_lock): Qualify function calls. (lock): Avoid narrowing conversion. * testsuite/20_util/bind/60497.cc: New. * testsuite/23_containers/array/element_access/60497.cc: New. * testsuite/30_threads/call_once/60497.cc: New. * testsuite/30_threads/unique_lock/cons/60497.cc: New. diff --git a/libstdc++-v3/include/debug/array b/libstdc++-v3/include/debug/array index ef01c98..2266a53 100644 --- a/libstdc++-v3/include/debug/array +++ b/libstdc++-v3/include/debug/array @@ -278,7 +278,7 @@ namespace __debug get(array<_Tp, _Nm>&& __arr) noexcept { static_assert(_Int < _Nm, "index is out of bounds"); - return std::move(get<_Int>(__arr)); + return std::move(__debug::get<_Int>(__arr)); } template<std::size_t _Int, typename _Tp, std::size_t _Nm> diff --git a/libstdc++-v3/include/profile/array b/libstdc++-v3/include/profile/array index 1c38b05..1a43a48 100644 --- a/libstdc++-v3/include/profile/array +++ b/libstdc++-v3/include/profile/array @@ -240,7 +240,7 @@ namespace __profile get(array<_Tp, _Nm>&& __arr) noexcept { static_assert(_Int < _Nm, "index is out of bounds"); - return std::move(get<_Int>(__arr)); + return std::move(__profile::get<_Int>(__arr)); } template<std::size_t _Int, typename _Tp, std::size_t _Nm> diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index 67680d6..22947ce 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -281,7 +281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER get(array<_Tp, _Nm>&& __arr) noexcept { static_assert(_Int < _Nm, "index is out of bounds"); - return std::move(get<_Int>(__arr)); + return std::move(_GLIBCXX_STD_C::get<_Int>(__arr)); } template<std::size_t _Int, typename _Tp, std::size_t _Nm> diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 295022d..2bc3d8d 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -1120,7 +1120,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) const _Index_tuple<_Indexes...>&) const volatile -> decltype(__arg(declval<_Args>()...)) { - return __arg(std::forward<_Args>(get<_Indexes>(__tuple))...); + return __arg(std::forward<_Args>(std::get<_Indexes>(__tuple))...); } }; @@ -1261,7 +1261,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) __call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call as const @@ -1270,7 +1270,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) __call_c(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) const { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call as volatile @@ -1393,7 +1393,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call unqualified, return void @@ -1403,7 +1403,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call as const @@ -1413,7 +1413,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) const { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call as const, return void @@ -1423,7 +1423,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) const { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), __args)...); + (std::get<_Indexes>(_M_bound_args), __args)...); } // Call as volatile diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index 0b481d6..3d70754 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -400,22 +400,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } explicit unique_lock(mutex_type& __m) - : _M_device(&__m), _M_owns(false) + : _M_device(std::__addressof(__m)), _M_owns(false) { lock(); _M_owns = true; } unique_lock(mutex_type& __m, defer_lock_t) noexcept - : _M_device(&__m), _M_owns(false) + : _M_device(std::__addressof(__m)), _M_owns(false) { } unique_lock(mutex_type& __m, try_to_lock_t) - : _M_device(&__m), _M_owns(_M_device->try_lock()) + : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) { } unique_lock(mutex_type& __m, adopt_lock_t) - : _M_device(&__m), _M_owns(true) + : _M_device(std::__addressof(__m)), _M_owns(true) { // XXX calling thread owns mutex } @@ -423,13 +423,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Clock, typename _Duration> unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __atime) - : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime)) + : _M_device(std::__addressof(__m)), + _M_owns(_M_device->try_lock_until(__atime)) { } template<typename _Rep, typename _Period> unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rtime) - : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime)) + : _M_device(std::__addressof(__m)), + _M_owns(_M_device->try_lock_for(__rtime)) { } ~unique_lock() @@ -563,37 +565,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _M_owns; // XXX use atomic_bool }; - /// Partial specialization for unique_lock objects. + /// Swap overload for unique_lock objects. template<typename _Mutex> inline void swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept { __x.swap(__y); } - template<int _Idx> - struct __unlock_impl - { - template<typename... _Lock> - static void - __do_unlock(tuple<_Lock&...>& __locks) - { - std::get<_Idx>(__locks).unlock(); - __unlock_impl<_Idx - 1>::__do_unlock(__locks); - } - }; - - template<> - struct __unlock_impl<-1> - { - template<typename... _Lock> - static void - __do_unlock(tuple<_Lock&...>&) - { } - }; - template<typename _Lock> - unique_lock<_Lock> + inline unique_lock<_Lock> __try_to_lock(_Lock& __l) - { return unique_lock<_Lock>(__l, try_to_lock); } + { return unique_lock<_Lock>{__l, try_to_lock}; } template<int _Idx, bool _Continue = true> struct __try_lock_impl @@ -603,11 +584,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) { __idx = _Idx; - auto __lock = __try_to_lock(std::get<_Idx>(__locks)); + auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); if (__lock.owns_lock()) { - __try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>:: - __do_try_lock(__locks, __idx); + constexpr bool __cont = _Idx + 2 < sizeof...(_Lock); + using __try_locker = __try_lock_impl<_Idx + 1, __cont>; + __try_locker::__do_try_lock(__locks, __idx); if (__idx == -1) __lock.release(); } @@ -622,7 +604,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __do_try_lock(tuple<_Lock&...>& __locks, int& __idx) { __idx = _Idx; - auto __lock = __try_to_lock(std::get<_Idx>(__locks)); + auto __lock = std::__try_to_lock(std::get<_Idx>(__locks)); if (__lock.owns_lock()) { __idx = -1; @@ -665,16 +647,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * and unlock(). If the call exits via an exception any locks that were * obtained will be released. */ - template<typename _L1, typename _L2, typename ..._L3> + template<typename _L1, typename _L2, typename... _L3> void lock(_L1& __l1, _L2& __l2, _L3&... __l3) { while (true) { + using __try_locker = __try_lock_impl<0, sizeof...(_L3) != 0>; unique_lock<_L1> __first(__l1); int __idx; auto __locks = std::tie(__l2, __l3...); - __try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx); + __try_locker::__do_try_lock(__locks, __idx); if (__idx == -1) { __first.release(); @@ -735,7 +718,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_HAVE_TLS auto __bound_functor = std::__bind_simple(std::forward<_Callable>(__f), std::forward<_Args>(__args)...); - __once_callable = &__bound_functor; + __once_callable = std::__addressof(__bound_functor); __once_call = &__once_call_impl<decltype(__bound_functor)>; #else unique_lock<mutex> __functor_lock(__get_once_mutex()); diff --git a/libstdc++-v3/testsuite/20_util/bind/60497.cc b/libstdc++-v3/testsuite/20_util/bind/60497.cc new file mode 100644 index 0000000..759c9d8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/60497.cc @@ -0,0 +1,40 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// libstdc++/60497 + +#include <functional> +#include <memory> + +struct A; +template<typename T> struct B { T t; }; + +using UP = std::unique_ptr<B<A>>; + +bool f(UP&, UP&) { return true; } + +bool g(UP& p) +{ + auto binder = std::bind(f, std::ref(p), std::placeholders::_1); + bool b1 = binder(std::ref(p)); + auto binderbinder = std::bind(binder, std::placeholders::_1); + bool b2 = binderbinder(std::ref(p)); + return b1 && b2; +} diff --git a/libstdc++-v3/testsuite/23_containers/array/element_access/60497.cc b/libstdc++-v3/testsuite/23_containers/array/element_access/60497.cc new file mode 100644 index 0000000..14932a1 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/array/element_access/60497.cc @@ -0,0 +1,38 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } +// +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// libstdc++/60497 + +#include <array> +#include <debug/array> +#include <profile/array> +#include <memory> + +struct A; +template<typename T> struct B { T t; }; + +std::array<B<A>*, 1> a; +auto b = std::get<0>(std::move(a)); + +std::__debug::array<B<A>*, 1> c; +auto d = std::__debug::get<0>(std::move(c)); + +std::__profile::array<B<A>*, 1> e; +auto f = std::__profile::get<0>(std::move(e)); diff --git a/libstdc++-v3/testsuite/30_threads/call_once/60497.cc b/libstdc++-v3/testsuite/30_threads/call_once/60497.cc new file mode 100644 index 0000000..76cc710 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/call_once/60497.cc @@ -0,0 +1,41 @@ +// { dg-do compile } +// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-gnu* powerpc-ibm-aix* } } +// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } } +// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-darwin* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } + +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// libstdc++/60497 + +#include <mutex> +#include <memory> + +struct A; +template<typename T> struct B { T t; }; + +using UP = std::unique_ptr<B<A>>; + +void f(UP&) { } + +void g(UP& p) +{ + std::once_flag o; + std::call_once(o, f, std::ref(p)); +} diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc new file mode 100644 index 0000000..19be845 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc @@ -0,0 +1,49 @@ +// { dg-do compile } +// { dg-options " -std=gnu++11 " } + +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// libstdc++/60497 + +#include <mutex> +#include <memory> + +struct A; +template<typename T> struct B { T t; }; + +template<typename Dummy> +struct Lockable +{ + void lock(); + void unlock(); + bool try_lock(); +}; + +using test_type = Lockable<std::unique_ptr<B<A>>>; + +void test01() +{ + test_type l; + std::unique_lock<test_type> ul(l); +} + +void test02() +{ + test_type l1, l2, l3; + std::lock(l1, l2, l3); +}