The solution for PR 77537 causes ambiguities due to the extra copy assignment operator taking a __nonesuch_no_braces parameter. The copy and move assignment operators can be defined as defaulted to meet the semantics required by the standard.
In order to preserve ABI compatibility (specifically argument passing conventions for pair<T, T>) we need a new base class that makes the assignment operators non-trivial. PR libstdc++/86751 * include/bits/stl_pair.h (__nonesuch_no_braces): Remove. (__pair_base): New class with non-trivial copy assignment operator. (pair): Derive from __pair_base. Define copy assignment and move assignment operators as defaulted. * testsuite/20_util/pair/86751.cc: New test. Ville, this passes all our tests, but am I forgetting something that means this isn't right?
commit 766fc07c06b774fc6a0bd30d5bd8add8e4185d69 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Jul 31 17:26:04 2018 +0100 PR libstdc++/86751 default assignment operators for std::pair The solution for PR 77537 causes ambiguities due to the extra copy assignment operator taking a __nonesuch_no_braces parameter. The copy and move assignment operators can be defined as defaulted to meet the semantics required by the standard. In order to preserve ABI compatibility (specifically argument passing conventions for pair<T, T>) we need a new base class that makes the assignment operators non-trivial. PR libstdc++/86751 * include/bits/stl_pair.h (__nonesuch_no_braces): Remove. (__pair_base): New class with non-trivial copy assignment operator. (pair): Derive from __pair_base. Define copy assignment and move assignment operators as defaulted. * testsuite/20_util/pair/86751.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index a2486ba8244..03261fef1ea 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -179,14 +179,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; - // PR libstdc++/79141, a utility type for preventing - // initialization of an argument of a disabled assignment - // operator from a pair of empty braces. - struct __nonesuch_no_braces : std::__nonesuch { - explicit __nonesuch_no_braces(const __nonesuch&) = delete; +#if !_GLIBCXX_INLINE_VERSION + class __pair_base + { + template<typename _T1, typename _T2> friend struct pair; + __pair_base() = default; + ~__pair_base() = default; + __pair_base(const __pair_base&) = default; + // Ensure !is_trivially_copy_assignable<pair<T,U>> for ABI compatibility: + __pair_base& operator=(const __pair_base&) noexcept { return *this; } }; - -#endif +#endif // !_GLIBCXX_INLINE_VERSION +#endif // C++11 /** * @brief Struct holding two objects of arbitrary type. @@ -196,6 +200,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template<typename _T1, typename _T2> struct pair +#if __cplusplus >= 201103L && !_GLIBCXX_INLINE_VERSION + // GLIBCXX_ABI Deprecated + : private __pair_base +#endif { typedef _T1 first_type; /// @c first_type is the first bound type typedef _T2 second_type; /// @c second_type is the second bound type @@ -363,35 +371,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename... _Args1, typename... _Args2> pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); - pair& - operator=(typename conditional< - __and_<is_copy_assignable<_T1>, - is_copy_assignable<_T2>>::value, - const pair&, const __nonesuch_no_braces&>::type __p) - { - first = __p.first; - second = __p.second; - return *this; - } - - pair& - operator=(typename conditional< - __not_<__and_<is_copy_assignable<_T1>, - is_copy_assignable<_T2>>>::value, - const pair&, const __nonesuch_no_braces&>::type __p) = delete; - - pair& - operator=(typename conditional< - __and_<is_move_assignable<_T1>, - is_move_assignable<_T2>>::value, - pair&&, __nonesuch_no_braces&&>::type __p) - noexcept(__and_<is_nothrow_move_assignable<_T1>, - is_nothrow_move_assignable<_T2>>::value) - { - first = std::forward<first_type>(__p.first); - second = std::forward<second_type>(__p.second); - return *this; - } + pair& operator=(const pair&) = default; + pair& operator=(pair&&) = default; template<typename _U1, typename _U2> typename enable_if<__and_<is_assignable<_T1&, const _U1&>, diff --git a/libstdc++-v3/testsuite/20_util/pair/86751.cc b/libstdc++-v3/testsuite/20_util/pair/86751.cc new file mode 100644 index 00000000000..76a76c0d656 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/86751.cc @@ -0,0 +1,33 @@ +// Copyright (C) 2018 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/>. + +// { dg-do compile { target c++11 } } + +#include <utility> + +struct X { + template<typename T> operator T() const; +}; + + +void +test01() +{ + std::pair<int, int> p; + X x; + p = x; // PR libstdc++/86751 +}