public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector
@ 2013-01-16  9:25 Jonathan Wakely
  2013-01-16  9:44 ` Jonathan Wakely
  2013-01-16 23:57 ` Jonathan Wakely
  0 siblings, 2 replies; 4+ messages in thread
From: Jonathan Wakely @ 2013-01-16  9:25 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1346 bytes --]

This fixes a regression caused by supporting the C++11 allocator
requirements in std::vector, and the fact that the unordered
containers don't have noexcept move constructors.  Fixed by
specializing is_copy_constructible for the unordered containers so
vector doesn't try to copy them when their element type is not
CopyInsertable into the container, and instead resorts to a move that
might throw.

        PR libstdc++/55043
        * include/std/unordered_map: Include alloc_traits.h
        * include/std/unordered_set: Likewise.
        * include/bits/alloc_traits.h: Define __is_copy_insertable.
        * include/bits/unordered_map.h: Use it.
        * include/bits/unordered_set.h: Likewise.
        * include/debug/unordered_map.h: Likewise.
        * include/debug/unordered_set.h: Likewise.
        * include/profile/unordered_map.h: Likewise.
        * include/profile/unordered_set.h: Likewise.
        * include/bits/hashtable.h: Fix comment typos.
        * testsuite/23_containers/unordered_map/55043.cc: New.
        * testsuite/23_containers/unordered_multimap/55043.cc: New.
        * testsuite/23_containers/unordered_multiset/55043.cc: New.
        * testsuite/23_containers/unordered_set/55043.cc: New.

Tested x86_64-linux, in normal, debug and profile modes.
Committed to trunk, to be committed to the 4.7 branch shortly.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 24300 bytes --]

commit e9c94b31c67f26e52c9927a4eedb39095efcd8be
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Wed Jan 16 09:19:11 2013 +0000

    	PR libstdc++/55043
    	* include/std/unordered_map: Include alloc_traits.h
    	* include/std/unordered_set: Likewise.
    	* include/bits/alloc_traits.h: Define __is_copy_insertable.
    	* include/bits/unordered_map.h: Use it.
    	* include/bits/unordered_set.h: Likewise.
    	* include/debug/unordered_map.h: Likewise.
    	* include/debug/unordered_set.h: Likewise.
    	* include/profile/unordered_map.h: Likewise.
    	* include/profile/unordered_set.h: Likewise.
    	* include/bits/hashtable.h: Fix comment typos.
    	* testsuite/23_containers/unordered_map/55043.cc: New.
    	* testsuite/23_containers/unordered_multimap/55043.cc: New.
    	* testsuite/23_containers/unordered_multiset/55043.cc: New.
    	* testsuite/23_containers/unordered_set/55043.cc: New.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 9abadbb..c6259a1 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -1,6 +1,6 @@
 // Allocator traits -*- C++ -*-
 
-// Copyright (C) 2011-2012 Free Software Foundation, Inc.
+// Copyright (C) 2011-2013 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
@@ -39,6 +39,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  template<typename _Tp>
+    class allocator;
+
   template<typename _Alloc, typename _Tp>
     class __alloctr_rebind_helper
     {
@@ -506,6 +509,41 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
       __do_alloc_on_swap(__one, __two, __pocs());
     }
 
+  template<typename _Alloc>
+    class __is_copy_insertable_impl
+    {
+      typedef allocator_traits<_Alloc> _Traits;
+
+      template<typename _Up, typename
+	       = decltype(_Traits::construct(std::declval<_Alloc&>(),
+					     std::declval<_Up*>(),
+					     std::declval<const _Up&>()))>
+	static true_type
+	_M_select(int);
+
+      template<typename _Up>
+	static false_type
+	_M_select(...);
+
+    public:
+	typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
+    };
+
+  template<typename _Alloc>
+    struct __is_copy_insertable
+    : __is_copy_insertable_impl<_Alloc>::type
+    { };
+
+  // std::allocator<_Tp> just requires CopyConstructible
+  template<typename _Tp>
+    struct __is_copy_insertable<allocator<_Tp>>
+    : is_copy_constructible<_Tp>
+    { };
+
+  template<typename _Container>
+    using __has_copy_insertable_val
+      = __is_copy_insertable<typename _Container::allocator_type>;
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index fab6c7c..49cb4db 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -370,7 +370,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Hashtable(_Hashtable&&);
 
-      // Use delegating construtors.
+      // Use delegating constructors.
       explicit
       _Hashtable(size_type __n = 10,
 		 const _H1& __hf = _H1(),
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_element_count(__ht._M_element_count),
       _M_rehash_policy(__ht._M_rehash_policy)
     {
-      // Update, if necessary, bucket pointing to before begin that hasn't move.
+      // Update, if necessary, bucket pointing to before begin that hasn't moved.
       if (_M_begin())
 	_M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin();
       __ht._M_rehash_policy = _RehashPolicy();
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 9fa0553..0235a99 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -1408,6 +1408,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return !(__x == __y); }
 
 _GLIBCXX_END_NAMESPACE_CONTAINER
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
+							_Pred, _Alloc>>
+    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
+							      _Pred, _Alloc>>
+    { };
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
+							     _Pred, _Alloc>>
+    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp,
+								   _Hash, _Pred,
+								   _Alloc>>
+    { };
+
 } // namespace std
 
 #endif /* _UNORDERED_MAP_H */
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index c3eaa48..2ada63d 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -1,6 +1,6 @@
 // unordered_set implementation -*- C++ -*-
 
-// Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2010-2013 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
@@ -1291,6 +1291,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return !(__x == __y); }
 
 _GLIBCXX_END_NAMESPACE_CONTAINER
+
+  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
+    struct is_copy_constructible<_GLIBCXX_STD_C::unordered_set<_Key, _Hash,
+							       _Pred, _Alloc>>
+    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_set<_Key, _Hash,
+							      _Pred, _Alloc>>
+    { };
+
+  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
+    struct
+    is_copy_constructible<_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash,
+							     _Pred, _Alloc>>
+    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash,
+								   _Pred,
+								   _Alloc>>
+    { };
+
 } // namespace std
 
 #endif /* _UNORDERED_SET_H */
diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map
index 1c99ac8..115abb5 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -1,7 +1,6 @@
 // Debugging unordered_map/unordered_multimap implementation -*- C++ -*-
 
-// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-// Free Software Foundation, Inc.
+// Copyright (C) 2003-2013 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
@@ -939,6 +938,30 @@ namespace __debug
     { return !(__x == __y); }
 
 } // namespace __debug
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<__debug::unordered_map<_Key, _Tp, _Hash, _Pred,
+						 _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_C::unordered_map<_Key, _Tp,
+							   _Hash, _Pred,
+							   _Alloc> >
+    { };
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<__debug::unordered_multimap<_Key, _Tp, _Hash, _Pred,
+						      _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp,
+								_Hash, _Pred,
+								_Alloc> >
+    { };
+
+_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif // C++11
diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set
index d270ecc..895c943 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -1,7 +1,6 @@
 // Debugging unordered_set/unordered_multiset implementation -*- C++ -*-
 
-// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-// Free Software Foundation, Inc.
+// Copyright (C) 2003-2013 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
@@ -921,6 +920,27 @@ namespace __debug
     { return !(__x == __y); }
 
 } // namespace __debug
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
+    struct
+    is_copy_constructible<__debug::unordered_set<_Key, _Hash, _Pred, _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_C::unordered_set<_Key,
+							   _Hash, _Pred,
+							   _Alloc> >
+    { };
+
+  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
+    struct
+    is_copy_constructible<__debug::unordered_multiset<_Key, _Hash, _Pred,
+						      _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_C::unordered_multiset<_Key,
+								_Hash, _Pred,
+								_Alloc> >
+    { };
+
+_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif // C++11
diff --git a/libstdc++-v3/include/profile/unordered_map b/libstdc++-v3/include/profile/unordered_map
index e7b4c37..5ebcbf6 100644
--- a/libstdc++-v3/include/profile/unordered_map
+++ b/libstdc++-v3/include/profile/unordered_map
@@ -1,6 +1,6 @@
 // Profiling unordered_map/unordered_multimap implementation -*- C++ -*-
 
-// Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2009-2013 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
@@ -339,11 +339,25 @@ namespace __profile
 	       const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { return !(__x == __y); }
 
+} // namespace __profile
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<__profile::unordered_map<_Key, _Tp, _Hash,
+						   _Pred, _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_BASE >
+    { };
+_GLIBCXX_END_NAMESPACE_VERSION
+
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_BASE unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>
 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
 
+namespace __profile
+{
   /// Class std::unordered_multimap wrapper with performance instrumentation.
   template<typename _Key, typename _Tp,
 	   typename _Hash  = std::hash<_Key>,
@@ -609,6 +623,18 @@ namespace __profile
     { return !(__x == __y); }
 
 } // namespace __profile
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
+	   typename _Alloc>
+    struct
+    is_copy_constructible<__profile::unordered_multimap<_Key, _Tp, _Hash,
+							_Pred, _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_BASE >
+    { };
+
+_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #undef _GLIBCXX_BASE
diff --git a/libstdc++-v3/include/profile/unordered_set b/libstdc++-v3/include/profile/unordered_set
index 357c073..ebe1c7d 100644
--- a/libstdc++-v3/include/profile/unordered_set
+++ b/libstdc++-v3/include/profile/unordered_set
@@ -1,6 +1,6 @@
 // Profiling unordered_set/unordered_multiset implementation -*- C++ -*-
 
-// Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2009-2013 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
@@ -305,11 +305,23 @@ namespace __profile
 	       const unordered_set<_Key, _Hash, _Pred, _Alloc>& __y)
     { return !(__x == __y); }
 
+} // namespace __profile
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
+    struct
+    is_copy_constructible<__profile::unordered_set<_Key, _Hash, _Pred, _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_BASE >
+    { };
+_GLIBCXX_END_NAMESPACE_VERSION
+
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
 #define _GLIBCXX_BASE unordered_multiset<_Value, _Hash, _Pred, _Alloc>
 
+namespace __profile
+{
   /** @brief Unordered_multiset wrapper with performance instrumentation.  */
   template<typename _Value,
        typename _Hash  = std::hash<_Value>,
@@ -568,6 +580,17 @@ namespace __profile
     { return !(__x == __y); }
 
 } // namespace __profile
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    struct
+    is_copy_constructible<__profile::unordered_multiset<_Value, _Hash,
+							_Pred, _Alloc>>
+    : is_copy_constructible< _GLIBCXX_STD_BASE >
+    { };
+
+_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #undef _GLIBCXX_BASE
diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map
index 3514203..7c10173 100644
--- a/libstdc++-v3/include/std/unordered_map
+++ b/libstdc++-v3/include/std/unordered_map
@@ -1,6 +1,6 @@
 // <unordered_map> -*- C++ -*-
 
-// Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2007-2013 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
@@ -41,6 +41,7 @@
 #include <tuple>
 #include <bits/stl_algobase.h>
 #include <bits/allocator.h>
+#include <bits/alloc_traits.h>
 #include <bits/stl_function.h> // equal_to, _Identity, _Select1st
 #include <bits/functional_hash.h>
 #include <bits/hashtable.h>
diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/include/std/unordered_set
index af6f624..cfe91ad 100644
--- a/libstdc++-v3/include/std/unordered_set
+++ b/libstdc++-v3/include/std/unordered_set
@@ -1,6 +1,6 @@
 // <unordered_set> -*- C++ -*-
 
-// Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2007-2013 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
@@ -41,6 +41,7 @@
 #include <tuple>
 #include <bits/stl_algobase.h>
 #include <bits/allocator.h>
+#include <bits/alloc_traits.h>
 #include <bits/stl_function.h> // equal_to, _Identity, _Select1st
 #include <bits/functional_hash.h>
 #include <bits/hashtable.h>
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
new file mode 100644
index 0000000..10d36a0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_map>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+using hash = std::hash<int>;
+using equal = std::equal_to<int>;
+
+template<typename Alloc>
+  using test_type = std::unordered_map<int, MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
new file mode 100644
index 0000000..9ae912ef6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_map>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+using hash = std::hash<int>;
+using equal = std::equal_to<int>;
+
+template<typename Alloc>
+  using test_type = std::unordered_multimap<int, MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
new file mode 100644
index 0000000..ebb8cb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_set>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+struct equal {
+  bool operator()(const MoveOnly&, const MoveOnly) const { return true; }
+};
+struct hash {
+  size_t operator()(const MoveOnly&) const { return 0; }
+};
+
+template<typename Alloc>
+  using test_type = std::unordered_multiset<MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
new file mode 100644
index 0000000..3b0b973
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_set>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+struct equal {
+  bool operator()(const MoveOnly&, const MoveOnly) const { return true; }
+};
+struct hash {
+  size_t operator()(const MoveOnly&) const { return 0; }
+};
+
+template<typename Alloc>
+  using test_type = std::unordered_set<MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector
  2013-01-16  9:25 [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector Jonathan Wakely
@ 2013-01-16  9:44 ` Jonathan Wakely
  2013-01-16 23:57 ` Jonathan Wakely
  1 sibling, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2013-01-16  9:44 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 16 January 2013 09:25, Jonathan Wakely wrote:
> This fixes a regression caused by supporting the C++11 allocator
> requirements in std::vector, and the fact that the unordered
> containers don't have noexcept move constructors.  Fixed by
> specializing is_copy_constructible for the unordered containers so
> vector doesn't try to copy them when their element type is not
> CopyInsertable into the container, and instead resorts to a move that
> might throw.
>
>         PR libstdc++/55043
>         * include/std/unordered_map: Include alloc_traits.h
>         * include/std/unordered_set: Likewise.
>         * include/bits/alloc_traits.h: Define __is_copy_insertable.
>         * include/bits/unordered_map.h: Use it.
>         * include/bits/unordered_set.h: Likewise.
>         * include/debug/unordered_map.h: Likewise.
>         * include/debug/unordered_set.h: Likewise.
>         * include/profile/unordered_map.h: Likewise.
>         * include/profile/unordered_set.h: Likewise.
>         * include/bits/hashtable.h: Fix comment typos.
>         * testsuite/23_containers/unordered_map/55043.cc: New.
>         * testsuite/23_containers/unordered_multimap/55043.cc: New.
>         * testsuite/23_containers/unordered_multiset/55043.cc: New.
>         * testsuite/23_containers/unordered_set/55043.cc: New.
>
> Tested x86_64-linux, in normal, debug and profile modes.
> Committed to trunk, to be committed to the 4.7 branch shortly.

Daniel K has pointed out a problem with this fix, so I'll try to fix
it again, properly, this evening.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector
  2013-01-16  9:25 [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector Jonathan Wakely
  2013-01-16  9:44 ` Jonathan Wakely
@ 2013-01-16 23:57 ` Jonathan Wakely
  2013-02-18 22:40   ` Jonathan Wakely
  1 sibling, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2013-01-16 23:57 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2128 bytes --]

Here's another attempt to fix this regression, I hope this time it
doesn't cause more problems than it solves.

Instead of specializing is_copy_constructible for the unordered
containers this causes their copy constructors to be deleted if the
value_type is not CopyInsertable into the container.  This makes
is_copy_constructible naturally give the right result, and so
__move_if_noexcept does the right thing and the testcase in the PR
passes. Yay.

As Daniel pointed out in the PR comments, the unfortunate side effect
of this approach is that we can no longer support instantiating
unordered containers with incomplete types. That's undefined
behaviour, but was allowed as QoI.  Conformance trumps QoI, I'm
afraid.  If someday we have noexcept move constructors for the
unordered containers we could allow incomplete types again.

        PR libstdc++/55043 (again)
        * include/bits/alloc_traits.h (allocator_traits::construct): Disable
        unless construction would be well-formed.
        (__allow_copy_cons, __check_copy_constructible): Define.
        * include/bits/unordered_map.h (__check_copy_constructible): Use as
        base class so copy constructor will be deleted if appropriate.
        (is_copy_constructible): Remove specialization.
        * include/bits/unordered_set.h: Likewise.
        * include/debug/unordered_map.h: Undo previous commit. Default copy
        and move constructors.
        * include/debug/unordered_set.h: Likewise.
        * include/profile/unordered_map.h: Undo previous commit.
        * include/profile/unordered_set.h: Likewise.
        * testsuite/23_containers/unordered_map/55043.cc: Fix test.
        * testsuite/23_containers/unordered_multimap/55043.cc: Likewise.
        * testsuite/23_containers/unordered_multiset/55043.cc: Likewise.
        * testsuite/23_containers/unordered_set/55043.cc: Likewise.
        * testsuite/23_containers/unordered_map/requirements/53339.cc: XFAIL,
        cannot support incomplete types.
        * testsuite/23_containers/unordered_multimap/requirements/53339.cc:
        Likewise.

Tested x86_86-linux, committed to trunk.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 19540 bytes --]

commit 20ee8df23bc999c8cf8876b88a188c4f51fb7665
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Wed Jan 16 09:50:47 2013 +0000

    	PR libstdc++/55043 (again)
    	* include/bits/alloc_traits.h (allocator_traits::construct): Disable
    	unless construction would be well-formed.
    	(__allow_copy_cons, __check_copy_constructible): Define.
    	* include/bits/unordered_map.h (__check_copy_constructible): Use as
    	base class so copy constructor will be deleted if appropriate.
    	(is_copy_constructible): Remove specialization.
    	* include/bits/unordered_set.h: Likewise.
    	* include/debug/unordered_map.h: Undo previous commit. Default copy
    	and move constructors.
    	* include/debug/unordered_set.h: Likewise.
    	* include/profile/unordered_map.h: Undo previous commit.
    	* include/profile/unordered_set.h: Likewise.
    	* testsuite/23_containers/unordered_map/55043.cc: Fix test.
    	* testsuite/23_containers/unordered_multimap/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_multiset/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_set/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_map/requirements/53339.cc: XFAIL,
    	cannot support incomplete types.
    	* testsuite/23_containers/unordered_multimap/requirements/53339.cc:
    	Likewise.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index c6259a1..26c64f2 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -257,7 +257,8 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 
       template<typename _Tp, typename... _Args>
 	static typename
-       	enable_if<!__construct_helper<_Tp, _Args...>::value, void>::type
+	enable_if<__and_<__not_<__construct_helper<_Tp, _Args...>>,
+			 is_constructible<_Tp, _Args...>>::value, void>::type
        	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
 	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
 
@@ -389,7 +390,8 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
        *  arguments @a __args...
       */
       template<typename _Tp, typename... _Args>
-	static void construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
 	{ _S_construct(__a, __p, std::forward<_Args>(__args)...); }
 
       /**
@@ -526,9 +528,10 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	_M_select(...);
 
     public:
-	typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
+      typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
     };
 
+  // true if _Alloc::value_type is CopyInsertable into containers using _Alloc
   template<typename _Alloc>
     struct __is_copy_insertable
     : __is_copy_insertable_impl<_Alloc>::type
@@ -540,9 +543,23 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
     : is_copy_constructible<_Tp>
     { };
 
-  template<typename _Container>
-    using __has_copy_insertable_val
-      = __is_copy_insertable<typename _Container::allocator_type>;
+  // Used to allow copy construction of unordered containers
+  template<bool> struct __allow_copy_cons { };
+
+  // Used to delete copy constructor of unordered containers
+  template<>
+    struct __allow_copy_cons<false>
+    {
+      __allow_copy_cons() = default;
+      __allow_copy_cons(const __allow_copy_cons&) = delete;
+      __allow_copy_cons(__allow_copy_cons&&) = default;
+      __allow_copy_cons& operator=(const __allow_copy_cons&) = default;
+      __allow_copy_cons& operator=(__allow_copy_cons&&) = default;
+    };
+
+  template<typename _Alloc>
+    using __check_copy_constructible
+      = __allow_copy_cons<__is_copy_insertable<_Alloc>::value>;
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 0235a99..be213e0 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -94,7 +94,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	   class _Hash = hash<_Key>,
 	   class _Pred = std::equal_to<_Key>,
 	   class _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
-    class unordered_map
+    class unordered_map : __check_copy_constructible<_Alloc>
     {
       typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
       _Hashtable _M_h;
@@ -775,7 +775,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	   class _Hash = hash<_Key>,
 	   class _Pred = std::equal_to<_Key>,
 	   class _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
-    class unordered_multimap
+    class unordered_multimap : __check_copy_constructible<_Alloc>
     {
       typedef __ummap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
       _Hashtable _M_h;
@@ -1408,26 +1408,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return !(__x == __y); }
 
 _GLIBCXX_END_NAMESPACE_CONTAINER
-
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
-							_Pred, _Alloc>>
-    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
-							      _Pred, _Alloc>>
-    { };
-
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
-							     _Pred, _Alloc>>
-    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp,
-								   _Hash, _Pred,
-								   _Alloc>>
-    { };
-
 } // namespace std
 
 #endif /* _UNORDERED_MAP_H */
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index 2ada63d..50c233d 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	   class _Hash = hash<_Value>,
 	   class _Pred = std::equal_to<_Value>,
 	   class _Alloc = std::allocator<_Value> >
-    class unordered_set
+    class unordered_set : __check_copy_constructible<_Alloc>
     {
       typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc>  _Hashtable;
       _Hashtable _M_h;
@@ -695,7 +695,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	   class _Hash = hash<_Value>,
 	   class _Pred = std::equal_to<_Value>,
 	   class _Alloc = std::allocator<_Value> >
-    class unordered_multiset
+    class unordered_multiset : __check_copy_constructible<_Alloc>
     {
       typedef __umset_hashtable<_Value, _Hash, _Pred, _Alloc>  _Hashtable;
       _Hashtable _M_h;
@@ -1291,23 +1291,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return !(__x == __y); }
 
 _GLIBCXX_END_NAMESPACE_CONTAINER
-
-  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
-    struct is_copy_constructible<_GLIBCXX_STD_C::unordered_set<_Key, _Hash,
-							       _Pred, _Alloc>>
-    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_set<_Key, _Hash,
-							      _Pred, _Alloc>>
-    { };
-
-  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
-    struct
-    is_copy_constructible<_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash,
-							     _Pred, _Alloc>>
-    : __has_copy_insertable_val<_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash,
-								   _Pred,
-								   _Alloc>>
-    { };
-
 } // namespace std
 
 #endif /* _UNORDERED_SET_H */
diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map
index 115abb5..284450f 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -96,14 +96,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_map(const unordered_map& __x) 
-      : _Base(__x) { }
+      unordered_map(const unordered_map& __x) = default;
 
       unordered_map(const _Base& __x)
       : _Base(__x) { }
 
-      unordered_map(unordered_map&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_map(unordered_map&& __x) = default;
 
       unordered_map(initializer_list<value_type> __l,
 		    size_type __n = 0,
@@ -547,14 +545,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_multimap(const unordered_multimap& __x) 
-      : _Base(__x) { }
+      unordered_multimap(const unordered_multimap& __x) = default;
 
       unordered_multimap(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_multimap(unordered_multimap&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_multimap(unordered_multimap&& __x) = default;
 
       unordered_multimap(initializer_list<value_type> __l,
 			 size_type __n = 0,
@@ -938,30 +934,6 @@ namespace __debug
     { return !(__x == __y); }
 
 } // namespace __debug
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<__debug::unordered_map<_Key, _Tp, _Hash, _Pred,
-						 _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_C::unordered_map<_Key, _Tp,
-							   _Hash, _Pred,
-							   _Alloc> >
-    { };
-
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<__debug::unordered_multimap<_Key, _Tp, _Hash, _Pred,
-						      _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp,
-								_Hash, _Pred,
-								_Alloc> >
-    { };
-
-_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif // C++11
diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set
index 895c943..2fe71e4 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -96,14 +96,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_set(const unordered_set& __x) 
-      : _Base(__x) { }
+      unordered_set(const unordered_set& __x) = default;
 
       unordered_set(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_set(unordered_set&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_set(unordered_set&& __x) = default;
 
       unordered_set(initializer_list<value_type> __l,
 		    size_type __n = 0,
@@ -542,14 +540,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_multiset(const unordered_multiset& __x) 
-      : _Base(__x) { }
+      unordered_multiset(const unordered_multiset& __x) = default;
 
       unordered_multiset(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_multiset(unordered_multiset&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_multiset(unordered_multiset&& __x) = default;
 
       unordered_multiset(initializer_list<value_type> __l,
 			 size_type __n = 0,
@@ -920,27 +916,6 @@ namespace __debug
     { return !(__x == __y); }
 
 } // namespace __debug
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
-    struct
-    is_copy_constructible<__debug::unordered_set<_Key, _Hash, _Pred, _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_C::unordered_set<_Key,
-							   _Hash, _Pred,
-							   _Alloc> >
-    { };
-
-  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
-    struct
-    is_copy_constructible<__debug::unordered_multiset<_Key, _Hash, _Pred,
-						      _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_C::unordered_multiset<_Key,
-								_Hash, _Pred,
-								_Alloc> >
-    { };
-
-_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif // C++11
diff --git a/libstdc++-v3/include/profile/unordered_map b/libstdc++-v3/include/profile/unordered_map
index 5ebcbf6..0fee176 100644
--- a/libstdc++-v3/include/profile/unordered_map
+++ b/libstdc++-v3/include/profile/unordered_map
@@ -339,25 +339,11 @@ namespace __profile
 	       const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { return !(__x == __y); }
 
-} // namespace __profile
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<__profile::unordered_map<_Key, _Tp, _Hash,
-						   _Pred, _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_BASE >
-    { };
-_GLIBCXX_END_NAMESPACE_VERSION
-
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_BASE unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>
 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
 
-namespace __profile
-{
   /// Class std::unordered_multimap wrapper with performance instrumentation.
   template<typename _Key, typename _Tp,
 	   typename _Hash  = std::hash<_Key>,
@@ -623,18 +609,6 @@ namespace __profile
     { return !(__x == __y); }
 
 } // namespace __profile
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  template<typename _Key, typename _Tp, typename _Hash, typename _Pred,
-	   typename _Alloc>
-    struct
-    is_copy_constructible<__profile::unordered_multimap<_Key, _Tp, _Hash,
-							_Pred, _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_BASE >
-    { };
-
-_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #undef _GLIBCXX_BASE
diff --git a/libstdc++-v3/include/profile/unordered_set b/libstdc++-v3/include/profile/unordered_set
index ebe1c7d..737b6ec 100644
--- a/libstdc++-v3/include/profile/unordered_set
+++ b/libstdc++-v3/include/profile/unordered_set
@@ -305,23 +305,11 @@ namespace __profile
 	       const unordered_set<_Key, _Hash, _Pred, _Alloc>& __y)
     { return !(__x == __y); }
 
-} // namespace __profile
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-  template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
-    struct
-    is_copy_constructible<__profile::unordered_set<_Key, _Hash, _Pred, _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_BASE >
-    { };
-_GLIBCXX_END_NAMESPACE_VERSION
-
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
 #define _GLIBCXX_BASE unordered_multiset<_Value, _Hash, _Pred, _Alloc>
 
-namespace __profile
-{
   /** @brief Unordered_multiset wrapper with performance instrumentation.  */
   template<typename _Value,
        typename _Hash  = std::hash<_Value>,
@@ -580,17 +568,6 @@ namespace __profile
     { return !(__x == __y); }
 
 } // namespace __profile
-
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
-    struct
-    is_copy_constructible<__profile::unordered_multiset<_Value, _Hash,
-							_Pred, _Alloc>>
-    : is_copy_constructible< _GLIBCXX_STD_BASE >
-    { };
-
-_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #undef _GLIBCXX_BASE
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
index 10d36a0..50e5437 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
@@ -63,7 +63,7 @@ struct Alloc : std::allocator<T>
 
 // verify is_copy_constructible depends on allocator
 typedef test_type<Alloc<MoveOnly, true>> uim_rval;
-static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
 
 typedef test_type<Alloc<MoveOnly, false>> uim_lval;
 static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc
index 4df4493..10404ce 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc
@@ -1,7 +1,9 @@
-// { dg-do compile }
+// XFAIL because of PR libstdc++/55043 fix
+// { dg-do compile { xfail *-*-* } }
+// { dg-excess-errors "" }
 // { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2012 Free Software Foundation, Inc.
+// Copyright (C) 2012-2013 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
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
index 9ae912ef6..afeecaa 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
@@ -63,7 +63,7 @@ struct Alloc : std::allocator<T>
 
 // verify is_copy_constructible depends on allocator
 typedef test_type<Alloc<MoveOnly, true>> uim_rval;
-static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
 
 typedef test_type<Alloc<MoveOnly, false>> uim_lval;
 static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc
index 5745618..cccd2a8 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc
@@ -1,7 +1,9 @@
-// { dg-do compile }
+// XFAIL because of PR libstdc++/55043 fix
+// { dg-do compile { xfail *-*-* } }
+// { dg-excess-errors "" }
 // { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2012 Free Software Foundation, Inc.
+// Copyright (C) 2012-2013 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
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
index ebb8cb8..445e4e4 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
@@ -67,7 +67,7 @@ struct Alloc : std::allocator<T>
 
 // verify is_copy_constructible depends on allocator
 typedef test_type<Alloc<MoveOnly, true>> uim_rval;
-static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
 
 typedef test_type<Alloc<MoveOnly, false>> uim_lval;
 static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
index 3b0b973..e5ba065 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
@@ -67,7 +67,7 @@ struct Alloc : std::allocator<T>
 
 // verify is_copy_constructible depends on allocator
 typedef test_type<Alloc<MoveOnly, true>> uim_rval;
-static_assert(std::is_copy_constructible<uim_rval>::value, "is not copyable");
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
 
 typedef test_type<Alloc<MoveOnly, false>> uim_lval;
 static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector
  2013-01-16 23:57 ` Jonathan Wakely
@ 2013-02-18 22:40   ` Jonathan Wakely
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2013-02-18 22:40 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2335 bytes --]

On 16 January 2013 23:57, Jonathan Wakely wrote:
> Here's another attempt to fix this regression, I hope this time it
> doesn't cause more problems than it solves.
>
> Instead of specializing is_copy_constructible for the unordered
> containers this causes their copy constructors to be deleted if the
> value_type is not CopyInsertable into the container.  This makes
> is_copy_constructible naturally give the right result, and so
> __move_if_noexcept does the right thing and the testcase in the PR
> passes. Yay.
>
> As Daniel pointed out in the PR comments, the unfortunate side effect
> of this approach is that we can no longer support instantiating
> unordered containers with incomplete types. That's undefined
> behaviour, but was allowed as QoI.  Conformance trumps QoI, I'm
> afraid.  If someday we have noexcept move constructors for the
> unordered containers we could allow incomplete types again.
>
>         PR libstdc++/55043 (again)
>         * include/bits/alloc_traits.h (allocator_traits::construct): Disable
>         unless construction would be well-formed.
>         (__allow_copy_cons, __check_copy_constructible): Define.
>         * include/bits/unordered_map.h (__check_copy_constructible): Use as
>         base class so copy constructor will be deleted if appropriate.
>         (is_copy_constructible): Remove specialization.
>         * include/bits/unordered_set.h: Likewise.
>         * include/debug/unordered_map.h: Undo previous commit. Default copy
>         and move constructors.
>         * include/debug/unordered_set.h: Likewise.
>         * include/profile/unordered_map.h: Undo previous commit.
>         * include/profile/unordered_set.h: Likewise.
>         * testsuite/23_containers/unordered_map/55043.cc: Fix test.
>         * testsuite/23_containers/unordered_multimap/55043.cc: Likewise.
>         * testsuite/23_containers/unordered_multiset/55043.cc: Likewise.
>         * testsuite/23_containers/unordered_set/55043.cc: Likewise.
>         * testsuite/23_containers/unordered_map/requirements/53339.cc: XFAIL,
>         cannot support incomplete types.
>         * testsuite/23_containers/unordered_multimap/requirements/53339.cc:
>         Likewise.
>
> Tested x86_86-linux, committed to trunk.

I plan to commit the attached to the 4.7 branch to fix the regression there too.

[-- Attachment #2: patch-c.txt --]
[-- Type: text/plain, Size: 25028 bytes --]

commit 0162956f34307f5918c0c022485547297e59a1d8
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Mon Feb 18 21:26:45 2013 +0000

    	PR libstdc++/55043
    	* include/bits/alloc_traits.h (allocator_traits::construct): Disable
    	unless construction would be well-formed.
    	(__allow_copy_cons, __check_copy_constructible): Define.
    	* include/bits/unordered_map.h (__check_copy_constructible): Use as
    	base class so copy constructor will be deleted if appropriate.
    	* include/bits/unordered_set.h: Likewise.
    	* include/std/unordered_set: Include alloc_traits.h.
    	* include/std/unordered_set: Likewise.
    	* include/debug/unordered_map.h: Default copy and move constructors.
    	* include/debug/unordered_set.h: Likewise.
    	* testsuite/23_containers/unordered_map/55043.cc: Fix test.
    	* testsuite/23_containers/unordered_multimap/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_multiset/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_set/55043.cc: Likewise.
    	* testsuite/23_containers/unordered_map/requirements/53339.cc: XFAIL,
    	cannot support incomplete types.
    	* testsuite/23_containers/unordered_multimap/requirements/53339.cc:
    	Likewise.
    	* testsuite/23_containers/unordered_set/instantiation_neg.cc: Adjust
    	dg-error line number.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 3b12981..bfa50de 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -1,6 +1,6 @@
 // Allocator traits -*- C++ -*-
 
-// Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2011, 2012, 2013 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
@@ -39,6 +39,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  template<typename _Tp>
+    class allocator;
+
   template<typename _Alloc, typename _Tp>
     class __alloctr_rebind_helper
     {
@@ -254,7 +257,8 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 
       template<typename _Tp, typename... _Args>
 	static typename
-       	enable_if<!__construct_helper<_Tp, _Args...>::value, void>::type
+	enable_if<__and_<__not_<__construct_helper<_Tp, _Args...>>,
+			 is_constructible<_Tp, _Args...>>::value, void>::type
        	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
 	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
 
@@ -386,7 +390,8 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
        *  arguments @a __args...
       */
       template<typename _Tp, typename... _Args>
-	static void construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
 	{ _S_construct(__a, __p, std::forward<_Args>(__args)...); }
 
       /**
@@ -506,6 +511,56 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
       __do_alloc_on_swap(__one, __two, __pocs());
     }
 
+  template<typename _Alloc>
+    class __is_copy_insertable_impl
+    {
+      typedef allocator_traits<_Alloc> _Traits;
+
+      template<typename _Up, typename
+	       = decltype(_Traits::construct(std::declval<_Alloc&>(),
+					     std::declval<_Up*>(),
+					     std::declval<const _Up&>()))>
+	static true_type
+	_M_select(int);
+
+      template<typename _Up>
+	static false_type
+	_M_select(...);
+
+    public:
+      typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
+    };
+
+  // true if _Alloc::value_type is CopyInsertable into containers using _Alloc
+  template<typename _Alloc>
+    struct __is_copy_insertable
+    : __is_copy_insertable_impl<_Alloc>::type
+    { };
+
+  // std::allocator<_Tp> just requires CopyConstructible
+  template<typename _Tp>
+    struct __is_copy_insertable<allocator<_Tp>>
+    : is_copy_constructible<_Tp>
+    { };
+
+  // Used to allow copy construction of unordered containers
+  template<bool> struct __allow_copy_cons { };
+
+  // Used to delete copy constructor of unordered containers
+  template<>
+    struct __allow_copy_cons<false>
+    {
+      __allow_copy_cons() = default;
+      __allow_copy_cons(const __allow_copy_cons&) = delete;
+      __allow_copy_cons(__allow_copy_cons&&) = default;
+      __allow_copy_cons& operator=(const __allow_copy_cons&) = default;
+      __allow_copy_cons& operator=(__allow_copy_cons&&) = default;
+    };
+
+  template<typename _Alloc>
+    using __check_copy_constructible
+      = __allow_copy_cons<__is_copy_insertable<_Alloc>::value>;
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 95f5657..37e570f 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -1,6 +1,6 @@
 // unordered_map implementation -*- C++ -*-
 
-// Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2010, 2011, 2013 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
@@ -50,7 +50,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 			_Hash, __detail::_Mod_range_hashing,
 			__detail::_Default_ranged_hash,
 			__detail::_Prime_rehash_policy,
-			__cache_hash_code, false, true>
+			__cache_hash_code, false, true>,
+      __check_copy_constructible<_Alloc>
     {
       typedef _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc,
 			 std::_Select1st<std::pair<const _Key, _Tp> >, _Pred,
@@ -123,7 +124,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 			_Hash, __detail::_Mod_range_hashing,
 			__detail::_Default_ranged_hash,
 			__detail::_Prime_rehash_policy,
-			__cache_hash_code, false, false>
+			__cache_hash_code, false, false>,
+      __check_copy_constructible<_Alloc>
     {
       typedef _Hashtable<_Key, std::pair<const _Key, _Tp>,
 			 _Alloc,
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index 3d5361d..d65c79c 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -1,6 +1,6 @@
 // unordered_set implementation -*- C++ -*-
 
-// Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2010, 2011, 2013 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
@@ -50,7 +50,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 			_Hash, __detail::_Mod_range_hashing,
 			__detail::_Default_ranged_hash,
 			__detail::_Prime_rehash_policy,
-			__cache_hash_code, true, true>
+			__cache_hash_code, true, true>,
+      __check_copy_constructible<_Alloc>
     {
       typedef _Hashtable<_Value, _Value, _Alloc,
 			 std::_Identity<_Value>, _Pred,
@@ -134,7 +135,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 			_Hash, __detail::_Mod_range_hashing,
 			__detail::_Default_ranged_hash,
 			__detail::_Prime_rehash_policy,
-			__cache_hash_code, true, false>
+			__cache_hash_code, true, false>,
+      __check_copy_constructible<_Alloc>
     {
       typedef _Hashtable<_Value, _Value, _Alloc,
 			 std::_Identity<_Value>, _Pred,
diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map
index 1861b86..4c562af 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -1,6 +1,6 @@
 // Debugging unordered_map/unordered_multimap implementation -*- C++ -*-
 
-// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -97,14 +97,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_map(const unordered_map& __x) 
-      : _Base(__x) { }
+      unordered_map(const unordered_map& __x) = default;
 
       unordered_map(const _Base& __x)
       : _Base(__x) { }
 
-      unordered_map(unordered_map&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_map(unordered_map&& __x) = default;
 
       unordered_map(initializer_list<value_type> __l,
 		    size_type __n = 0,
@@ -511,14 +509,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_multimap(const unordered_multimap& __x) 
-      : _Base(__x) { }
+      unordered_multimap(const unordered_multimap& __x) = default;
 
       unordered_multimap(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_multimap(unordered_multimap&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_multimap(unordered_multimap&& __x) = default;
 
       unordered_multimap(initializer_list<value_type> __l,
 			 size_type __n = 0,
diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set
index 7323184..b91a178 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -1,6 +1,6 @@
 // Debugging unordered_set/unordered_multiset implementation -*- C++ -*-
 
-// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -97,14 +97,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_set(const unordered_set& __x) 
-      : _Base(__x) { }
+      unordered_set(const unordered_set& __x) = default;
 
       unordered_set(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_set(unordered_set&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_set(unordered_set&& __x) = default;
 
       unordered_set(initializer_list<value_type> __l,
 		    size_type __n = 0,
@@ -506,14 +504,12 @@ namespace __debug
 		__gnu_debug::__base(__last), __n,
 		__hf, __eql, __a) { }
 
-      unordered_multiset(const unordered_multiset& __x) 
-      : _Base(__x) { }
+      unordered_multiset(const unordered_multiset& __x) = default;
 
       unordered_multiset(const _Base& __x) 
       : _Base(__x) { }
 
-      unordered_multiset(unordered_multiset&& __x)
-      : _Base(std::move(__x)) { }
+      unordered_multiset(unordered_multiset&& __x) = default;
 
       unordered_multiset(initializer_list<value_type> __l,
 			 size_type __n = 0,
diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map
index e77a297..bfeabec 100644
--- a/libstdc++-v3/include/std/unordered_map
+++ b/libstdc++-v3/include/std/unordered_map
@@ -40,6 +40,7 @@
 #include <initializer_list>
 #include <bits/stl_algobase.h>
 #include <bits/allocator.h>
+#include <bits/alloc_traits.h>
 #include <bits/stl_function.h> // equal_to, _Identity, _Select1st
 #include <bits/functional_hash.h>
 #include <bits/hashtable.h>
diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/include/std/unordered_set
index 739e0a4..0c75404 100644
--- a/libstdc++-v3/include/std/unordered_set
+++ b/libstdc++-v3/include/std/unordered_set
@@ -40,6 +40,7 @@
 #include <initializer_list>
 #include <bits/stl_algobase.h>
 #include <bits/allocator.h>
+#include <bits/alloc_traits.h>
 #include <bits/stl_function.h> // equal_to, _Identity, _Select1st
 #include <bits/functional_hash.h>
 #include <bits/hashtable.h>
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
new file mode 100644
index 0000000..50e5437
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/55043.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_map>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+using hash = std::hash<int>;
+using equal = std::equal_to<int>;
+
+template<typename Alloc>
+  using test_type = std::unordered_map<int, MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc
new file mode 100644
index 0000000..10404ce
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53339.cc
@@ -0,0 +1,36 @@
+// XFAIL because of PR libstdc++/55043 fix
+// { dg-do compile { xfail *-*-* } }
+// { dg-excess-errors "" }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012-2013 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/>.
+
+#include <unordered_map>
+
+struct LinkedHashMap
+{
+  struct Entry;
+
+  typedef std::unordered_map<int, Entry> Storage;
+  typedef Storage::iterator EntryPtr;
+
+  struct Entry
+  {
+    EntryPtr prev, next;
+  };
+};
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
new file mode 100644
index 0000000..afeecaa
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/55043.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_map>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+using hash = std::hash<int>;
+using equal = std::equal_to<int>;
+
+template<typename Alloc>
+  using test_type = std::unordered_multimap<int, MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc
new file mode 100644
index 0000000..cccd2a8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/requirements/53339.cc
@@ -0,0 +1,36 @@
+// XFAIL because of PR libstdc++/55043 fix
+// { dg-do compile { xfail *-*-* } }
+// { dg-excess-errors "" }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012-2013 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/>.
+
+#include <unordered_map>
+
+struct LinkedHashMap
+{
+  struct Entry;
+
+  typedef std::unordered_multimap<int, Entry> Storage;
+  typedef Storage::iterator EntryPtr;
+
+  struct Entry
+  {
+    EntryPtr prev, next;
+  };
+};
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
new file mode 100644
index 0000000..9d71cff
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/55043.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_set>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+struct equal {
+  bool operator()(const MoveOnly&, const MoveOnly) const { return true; }
+};
+struct hash {
+  std::size_t operator()(const MoveOnly&) const { return 0; }
+};
+
+template<typename Alloc>
+  using test_type = std::unordered_multiset<MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
new file mode 100644
index 0000000..1524890
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/55043.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2013 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++/55043
+
+#include <unordered_set>
+#include <vector>
+
+struct MoveOnly
+{
+  MoveOnly() = default;
+  MoveOnly(MoveOnly&&) = default;
+};
+
+struct equal {
+  bool operator()(const MoveOnly&, const MoveOnly) const { return true; }
+};
+struct hash {
+  std::size_t operator()(const MoveOnly&) const { return 0; }
+};
+
+template<typename Alloc>
+  using test_type = std::unordered_set<MoveOnly, hash, equal, Alloc>;
+
+void test01()
+{
+  typedef test_type<std::allocator<MoveOnly>> uim;
+  std::vector<uim> v;
+  v.emplace_back(uim());
+}
+
+// Unordered containers don't use allocator_traits yet so need full
+// Allocator interface, derive from std::allocator to get it.
+template<typename T, bool R>
+struct Alloc : std::allocator<T>
+{
+  template<typename U>
+    struct rebind { typedef Alloc<U, R> other; };
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U, R>&) { }
+
+  typedef typename std::conditional<R, T&&, const T&>::type arg_type;
+
+  void construct(T* p, arg_type) const
+  { new((void*)p) T(); }
+};
+
+// verify is_copy_constructible depends on allocator
+typedef test_type<Alloc<MoveOnly, true>> uim_rval;
+static_assert(!std::is_copy_constructible<uim_rval>::value, "is not copyable");
+
+typedef test_type<Alloc<MoveOnly, false>> uim_lval;
+static_assert(std::is_copy_constructible<uim_lval>::value, "is copyable");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc
index 3a6984c..19e5d5e 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc
@@ -19,7 +19,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 185 }
+// { dg-error "static assertion failed" "" { target *-*-* } 187 }
 
 #include <unordered_set>
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-02-18 22:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-16  9:25 [patch] Fix libstdc++/55043 - issue with nesting unordered_map containing unique_ptr into vector Jonathan Wakely
2013-01-16  9:44 ` Jonathan Wakely
2013-01-16 23:57 ` Jonathan Wakely
2013-02-18 22:40   ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).