[PATCH] PR libstdc++/86751 default assignment operators for std::pair

Jonathan Wakely jwakely@redhat.com
Tue Jul 31 17:07:00 GMT 2018


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?


-------------- next part --------------
commit 766fc07c06b774fc6a0bd30d5bd8add8e4185d69
Author: Jonathan Wakely <jwakely@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
+}


More information about the Gcc-patches mailing list