public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][Hashtable 3/6] Fix noexcept qualifications
@ 2019-11-17 21:01 François Dumont
  2020-07-17  9:55 ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: François Dumont @ 2019-11-17 21:01 UTC (permalink / raw)
  To: libstdc++, gcc-patches

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

This patch adds noexcept qualification on allocator aware constructors 
and fix the one on the default constructor.

     * include/bits/hashtable.h
     (_Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, true_type)):
     Add noexcept qualification.
     (_Hashtable(_Hashtable&&)): Fix noexcept qualification.
     (_Hashtable(_Hashtable&&, const allocator_type&)): Add noexcept
     qualification.
     * include/bits/unordered_map.h
     (unordered_map(unordered_map&&, const allocator_type&)): Add noexcept
     qualification.
     (unordered_multimap(unordered_multimap&&, const allocator_type&)): Add
     noexcept qualification.
     * include/bits/unordered_set.h
     (unordered_set(unordered_set&&, const allocator_type&)): Add noexcept
     qualification.
     (unordered_multiset(unordered_multiset&&, const allocator_type&)): Add
     noexcept qualification.
     * testsuite/23_containers/unordered_map/allocator/default_init.cc:
     New.
     * testsuite/23_containers/unordered_map/cons/
     noexcept_default_construct.cc: New.
     * testsuite/23_containers/unordered_map/cons/
     noexcept_move_construct.cc: New.
     * testsuite/23_containers/unordered_map/modifiers/move_assign.cc:
     New.
     * testsuite/23_containers/unordered_multimap/cons/
     noexcept_default_construct.cc: New.
     * testsuite/23_containers/unordered_multimap/cons/
     noexcept_move_construct.cc: New.
     * testsuite/23_containers/unordered_multiset/cons/
     noexcept_default_construct.cc: New.
     * testsuite/23_containers/unordered_multiset/cons/
     noexcept_move_construct.cc: New.
     * testsuite/23_containers/unordered_set/allocator/default_init.cc: New.
     * testsuite/23_containers/unordered_set/cons/
     noexcept_default_construct.cc: New.
     * 
testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc:
     New.

Tested under Linux x86_64.

François


[-- Attachment #2: hashtable#4.patch --]
[-- Type: text/x-patch, Size: 35199 bytes --]

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 5f785d4904d..ad07a36eb83 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -463,6 +463,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__hashtable_alloc(__node_alloc_type(__a))
       { }
 
+      _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, true_type)
+	noexcept(std::is_nothrow_copy_constructible<_H1>::value &&
+		 std::is_nothrow_copy_constructible<_Equal>::value)
+      : __hashtable_base(__ht),
+	__map_base(__ht),
+	__rehash_base(__ht),
+	__hashtable_alloc(std::move(__a)),
+	_M_buckets(__ht._M_buckets),
+	_M_bucket_count(__ht._M_bucket_count),
+	_M_before_begin(__ht._M_before_begin._M_nxt),
+	_M_element_count(__ht._M_element_count),
+	_M_rehash_policy(__ht._M_rehash_policy)
+      {
+	// Update, if necessary, buckets if __ht is using its single bucket.
+	if (__ht._M_uses_single_bucket())
+	  {
+	    _M_buckets = &_M_single_bucket;
+	    _M_single_bucket = __ht._M_single_bucket;
+	  }
+
+	// Fix bucket containing the _M_before_begin pointer that can't be
+	// moved.
+	_M_update_bbegin();
+
+	__ht._M_reset();
+      }
+
+      _Hashtable(_Hashtable&&, __node_alloc_type&&, false_type);
+
       template<typename _InputIterator>
 	_Hashtable(_InputIterator __first, _InputIterator __last,
 		   size_type __bkt_count_hint,
@@ -489,11 +518,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Hashtable(const _Hashtable&);
 
-      _Hashtable(_Hashtable&&) noexcept;
+      _Hashtable(_Hashtable&& __ht)
+	noexcept( noexcept(
+	  _Hashtable(std::declval<_Hashtable&&>(),
+	    std::declval<__node_alloc_type&&>(), std::declval<true_type>())) )
+      : _Hashtable(std::move(__ht), std::move(__ht._M_node_allocator()),
+		   true_type{})
+      { }
 
       _Hashtable(const _Hashtable&, const allocator_type&);
 
-      _Hashtable(_Hashtable&&, const allocator_type&);
+      _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
+	noexcept( noexcept(
+	  _Hashtable(std::declval<_Hashtable&&>(),
+	    std::declval<__node_alloc_type&&>(),
+	    std::declval<typename __node_alloc_traits::is_always_equal>())) )
+      : _Hashtable(std::move(__ht), __node_alloc_type(__a),
+		   typename __node_alloc_traits::is_always_equal{})
+      { }
 
       // Use delegating constructors.
       template<typename _InputIterator>
@@ -1368,36 +1410,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_assign(__ht, __alloc_node_gen);
     }
 
-  template<typename _Key, typename _Value,
-	   typename _Alloc, typename _ExtractKey, typename _Equal,
-	   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
-	   typename _Traits>
-    _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
-	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
-    _Hashtable(_Hashtable&& __ht) noexcept
-    : __hashtable_base(__ht),
-      __map_base(__ht),
-      __rehash_base(__ht),
-      __hashtable_alloc(std::move(__ht._M_base_alloc())),
-      _M_buckets(__ht._M_buckets),
-      _M_bucket_count(__ht._M_bucket_count),
-      _M_before_begin(__ht._M_before_begin._M_nxt),
-      _M_element_count(__ht._M_element_count),
-      _M_rehash_policy(__ht._M_rehash_policy)
-    {
-      // Update, if necessary, buckets if __ht is using its single bucket.
-      if (__ht._M_uses_single_bucket())
-	{
-	  _M_buckets = &_M_single_bucket;
-	  _M_single_bucket = __ht._M_single_bucket;
-	}
-
-      // Fix bucket containing the _M_before_begin pointer that can't be moved.
-      _M_update_bbegin();
-
-      __ht._M_reset();
-    }
-
   template<typename _Key, typename _Value,
 	   typename _Alloc, typename _ExtractKey, typename _Equal,
 	   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
@@ -1424,11 +1436,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   typename _Traits>
     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
 	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
-    _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
+    _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, false_type)
     : __hashtable_base(__ht),
       __map_base(__ht),
       __rehash_base(__ht),
-      __hashtable_alloc(__node_alloc_type(__a)),
+      __hashtable_alloc(std::move(__a)),
       _M_buckets(nullptr),
       _M_bucket_count(__ht._M_bucket_count),
       _M_element_count(__ht._M_element_count),
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 49c175a90be..5131e02e8aa 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -209,6 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_map(unordered_map&& __umap,
 		    const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
       : _M_h(std::move(__umap._M_h), __a)
       { }
 
@@ -1356,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_multimap(unordered_multimap&& __ummap,
 			 const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
       : _M_h(std::move(__ummap._M_h), __a)
       { }
 
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index 855579ee623..7154ec843db 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -203,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_set(unordered_set&& __uset,
 		    const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
       : _M_h(std::move(__uset._M_h), __a)
       { }
 
@@ -1044,6 +1045,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_multiset(unordered_multiset&& __umset,
 			 const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
       : _M_h(std::move(__umset._M_h), __a)
       { }
 
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
new file mode 100644
index 00000000000..8c3103c2614
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2019 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 run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<std::pair<const T, T>> alloc_type;
+  typedef std::unordered_map<T, T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<std::pair<const T, T>> alloc_type;
+  typedef std::unordered_map<T, T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..549d0a8d96a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 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 <unordered_map>
+
+using type1 = std::unordered_map<int, int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_map<int, int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_map<int, int, std::hash<int>,
+				  not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
+			not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..1929b6ac66d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 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>
+
+using type1 = std::unordered_map<int, int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_map<int, int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_map<int, int, std::hash<int>,
+				  not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc
new file mode 100644
index 00000000000..15d8e8011e6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc
@@ -0,0 +1,81 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 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 <utility>
+#include <unordered_map>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_counter_type.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  using namespace std;
+  using __gnu_test::counter_type;
+
+  std::vector<pair<int, counter_type>> insts { { 0, 0 }, { 1, 1 }, { 2, 2 } };
+  typedef unordered_map<int, counter_type> Map;
+  Map m;
+
+  counter_type::reset();
+
+  m.insert(make_move_iterator(insts.begin()), make_move_iterator(insts.end()));
+
+  VERIFY( m.size() == 3 );
+  VERIFY( counter_type::default_count == 0 );
+  VERIFY( counter_type::copy_count == 0 );
+  VERIFY( counter_type::move_count == 3 );
+}
+
+void test02()
+{
+  using namespace std;
+  using __gnu_test::counter_type;
+  using __gnu_test::propagating_allocator;
+
+  typedef propagating_allocator<pair<const int, counter_type>, false> Alloc;
+  typedef unordered_map<int, counter_type,
+			hash<int>, equal_to<int>,
+			Alloc> Map;
+
+  Alloc a1(1);
+  Map m1(3, a1);
+  m1 = { { 0, 0 }, { 1, 1 }, { 2, 2 } };
+  Alloc a2(2);
+  Map m2(3, a2);
+  m2 = { { 3, 0 }, { 4, 1 }, { 5, 2 } };
+
+  counter_type::reset();
+
+  m2 = move(m1);
+
+  VERIFY( m1.empty() );
+  VERIFY( m2.size() == 3 );
+  VERIFY( counter_type::default_count == 0 );
+  VERIFY( counter_type::copy_count == 0 );
+  VERIFY( counter_type::move_count == 3 );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..bda8c54dc4c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 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 <unordered_map>
+
+using type1 = std::unordered_multimap<int, int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multimap<int, int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multimap<int, int, std::hash<int>,
+				       not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
+				       not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..f3b1b908f2f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 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>
+
+using type1 = std::unordered_multimap<int, int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multimap<int, int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multimap<int, int, std::hash<int>,
+				       not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..5b7ff7ce655
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 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 <unordered_set>
+
+using type1 = std::unordered_multiset<int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multiset<int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multiset<int, std::hash<int>,
+				      not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>,
+				      not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..a03f7f8d959
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 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_set>
+
+using type1 = std::unordered_multiset<int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multiset<int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multiset<int, std::hash<int>,
+				      not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc
new file mode 100644
index 00000000000..51fa5e7094b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2019 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 run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::unordered_set<T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::unordered_set<T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..2966703461f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 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 <unordered_set>
+
+using type1 = std::unordered_set<int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_set<int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_set<int, std::hash<int>,
+				  not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_set<int, std::hash<int>, std::equal_to<int>,
+				  not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..2470079bc90
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2019 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_set>
+
+using type1 = std::unordered_set<int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_set<int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_set<int, std::hash<int>,
+				  not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );

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

* Re: [PATCH][Hashtable 3/6] Fix noexcept qualifications
  2019-11-17 21:01 [PATCH][Hashtable 3/6] Fix noexcept qualifications François Dumont
@ 2020-07-17  9:55 ` Jonathan Wakely
  2020-07-29  9:33   ` François Dumont
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-07-17  9:55 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 17/11/19 21:59 +0100, François Dumont wrote:
>This patch adds noexcept qualification on allocator aware constructors 
>and fix the one on the default constructor.
>
>    * include/bits/hashtable.h
>    (_Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, true_type)):
>    Add noexcept qualification.
>    (_Hashtable(_Hashtable&&)): Fix noexcept qualification.
>    (_Hashtable(_Hashtable&&, const allocator_type&)): Add noexcept
>    qualification.
>    * include/bits/unordered_map.h
>    (unordered_map(unordered_map&&, const allocator_type&)): Add noexcept
>    qualification.
>    (unordered_multimap(unordered_multimap&&, const allocator_type&)): Add
>    noexcept qualification.
>    * include/bits/unordered_set.h
>    (unordered_set(unordered_set&&, const allocator_type&)): Add noexcept
>    qualification.
>    (unordered_multiset(unordered_multiset&&, const allocator_type&)): Add
>    noexcept qualification.
>    * testsuite/23_containers/unordered_map/allocator/default_init.cc:
>    New.
>    * testsuite/23_containers/unordered_map/cons/
>    noexcept_default_construct.cc: New.
>    * testsuite/23_containers/unordered_map/cons/
>    noexcept_move_construct.cc: New.
>    * testsuite/23_containers/unordered_map/modifiers/move_assign.cc:
>    New.
>    * testsuite/23_containers/unordered_multimap/cons/
>    noexcept_default_construct.cc: New.
>    * testsuite/23_containers/unordered_multimap/cons/
>    noexcept_move_construct.cc: New.
>    * testsuite/23_containers/unordered_multiset/cons/
>    noexcept_default_construct.cc: New.
>    * testsuite/23_containers/unordered_multiset/cons/
>    noexcept_move_construct.cc: New.
>    * testsuite/23_containers/unordered_set/allocator/default_init.cc: New.
>    * testsuite/23_containers/unordered_set/cons/
>    noexcept_default_construct.cc: New.
>    * 
>testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc:
>    New.
>
>Tested under Linux x86_64.
>
>François
>

>diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
>index 5f785d4904d..ad07a36eb83 100644
>--- a/libstdc++-v3/include/bits/hashtable.h
>+++ b/libstdc++-v3/include/bits/hashtable.h
>@@ -463,6 +463,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	__hashtable_alloc(__node_alloc_type(__a))
>       { }
> 
>+      _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, true_type)
>+	noexcept(std::is_nothrow_copy_constructible<_H1>::value &&
>+		 std::is_nothrow_copy_constructible<_Equal>::value)
>+      : __hashtable_base(__ht),
>+	__map_base(__ht),
>+	__rehash_base(__ht),
>+	__hashtable_alloc(std::move(__a)),
>+	_M_buckets(__ht._M_buckets),
>+	_M_bucket_count(__ht._M_bucket_count),
>+	_M_before_begin(__ht._M_before_begin._M_nxt),
>+	_M_element_count(__ht._M_element_count),
>+	_M_rehash_policy(__ht._M_rehash_policy)
>+      {
>+	// Update, if necessary, buckets if __ht is using its single bucket.

I know the comment was already present, but I can't parse this.

There are two 'if' conditions, but don't they refer to the same thing?
It's necessary if __ht is using a single bucket, so shouldn't it be
either "Update buckets if __ht is using its single bucket" or "Update
buckets if necessary"?

"Update buckets if __ht is using its single bucket" seems preferable.

>+	if (__ht._M_uses_single_bucket())
>+	  {
>+	    _M_buckets = &_M_single_bucket;
>+	    _M_single_bucket = __ht._M_single_bucket;
>+	  }
>+
>+	// Fix bucket containing the _M_before_begin pointer that can't be
>+	// moved.
>+	_M_update_bbegin();
>+
>+	__ht._M_reset();
>+      }
>+
>+      _Hashtable(_Hashtable&&, __node_alloc_type&&, false_type);
>+
>       template<typename _InputIterator>
> 	_Hashtable(_InputIterator __first, _InputIterator __last,
> 		   size_type __bkt_count_hint,
>@@ -489,11 +518,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 
>       _Hashtable(const _Hashtable&);
> 
>-      _Hashtable(_Hashtable&&) noexcept;
>+      _Hashtable(_Hashtable&& __ht)
>+	noexcept( noexcept(
>+	  _Hashtable(std::declval<_Hashtable&&>(),

The && here is redundant, declval adds && to the type anyway.

>+	    std::declval<__node_alloc_type&&>(), std::declval<true_type>())) )

Same for __node_alloc_type&& here.

And true_type{} is shorter and simpler than std::declval<true_type>().
We know is_nothrow_default_constructible<true_type> is true, so we can
just use that.

>+      : _Hashtable(std::move(__ht), std::move(__ht._M_node_allocator()),
>+		   true_type{})
>+      { }
> 
>       _Hashtable(const _Hashtable&, const allocator_type&);
> 
>-      _Hashtable(_Hashtable&&, const allocator_type&);
>+      _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
>+	noexcept( noexcept(
>+	  _Hashtable(std::declval<_Hashtable&&>(),
>+	    std::declval<__node_alloc_type&&>(),

Redundant &&s.

>+	    std::declval<typename __node_alloc_traits::is_always_equal>())) )

Redundant declval: typename __node_alloc_traits::is_always_equal{}

>+      : _Hashtable(std::move(__ht), __node_alloc_type(__a),
>+		   typename __node_alloc_traits::is_always_equal{})
>+      { }
> 
>       // Use delegating constructors.
>       template<typename _InputIterator>
>@@ -1368,36 +1410,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       _M_assign(__ht, __alloc_node_gen);
>     }
> 
>-  template<typename _Key, typename _Value,
>-	   typename _Alloc, typename _ExtractKey, typename _Equal,
>-	   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
>-	   typename _Traits>
>-    _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
>-	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
>-    _Hashtable(_Hashtable&& __ht) noexcept
>-    : __hashtable_base(__ht),
>-      __map_base(__ht),
>-      __rehash_base(__ht),
>-      __hashtable_alloc(std::move(__ht._M_base_alloc())),
>-      _M_buckets(__ht._M_buckets),
>-      _M_bucket_count(__ht._M_bucket_count),
>-      _M_before_begin(__ht._M_before_begin._M_nxt),
>-      _M_element_count(__ht._M_element_count),
>-      _M_rehash_policy(__ht._M_rehash_policy)
>-    {
>-      // Update, if necessary, buckets if __ht is using its single bucket.
>-      if (__ht._M_uses_single_bucket())
>-	{
>-	  _M_buckets = &_M_single_bucket;
>-	  _M_single_bucket = __ht._M_single_bucket;
>-	}
>-
>-      // Fix bucket containing the _M_before_begin pointer that can't be moved.
>-      _M_update_bbegin();
>-
>-      __ht._M_reset();
>-    }
>-
>   template<typename _Key, typename _Value,
> 	   typename _Alloc, typename _ExtractKey, typename _Equal,
> 	   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
>@@ -1424,11 +1436,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	   typename _Traits>
>     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
> 	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
>-    _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
>+    _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, false_type)
>     : __hashtable_base(__ht),
>       __map_base(__ht),
>       __rehash_base(__ht),
>-      __hashtable_alloc(__node_alloc_type(__a)),
>+      __hashtable_alloc(std::move(__a)),
>       _M_buckets(nullptr),
>       _M_bucket_count(__ht._M_bucket_count),
>       _M_element_count(__ht._M_element_count),
>diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
>index 49c175a90be..5131e02e8aa 100644
>--- a/libstdc++-v3/include/bits/unordered_map.h
>+++ b/libstdc++-v3/include/bits/unordered_map.h
>@@ -209,6 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>        */
>       unordered_map(unordered_map&& __umap,
> 		    const allocator_type& __a)
>+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )

declval should be qualified. It might be simpler to just say:

	noexcept( noexcept(_Hashtable(std::move(__umap._M_h), __a)) )

>       : _M_h(std::move(__umap._M_h), __a)
>       { }
> 
>@@ -1356,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>        */
>       unordered_multimap(unordered_multimap&& __ummap,
> 			 const allocator_type& __a)
>+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )

Same here.

>       : _M_h(std::move(__ummap._M_h), __a)
>       { }
> 
>diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
>index 855579ee623..7154ec843db 100644
>--- a/libstdc++-v3/include/bits/unordered_set.h
>+++ b/libstdc++-v3/include/bits/unordered_set.h
>@@ -203,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>        */
>       unordered_set(unordered_set&& __uset,
> 		    const allocator_type& __a)
>+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )

Same here.

>       : _M_h(std::move(__uset._M_h), __a)
>       { }
> 
>@@ -1044,6 +1045,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>        */
>       unordered_multiset(unordered_multiset&& __umset,
> 			 const allocator_type& __a)
>+	noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )

Same here.

>       : _M_h(std::move(__umset._M_h), __a)
>       { }
> 
>diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
>new file mode 100644
>index 00000000000..8c3103c2614
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
>@@ -0,0 +1,69 @@
>+// Copyright (C) 2019 Free Software Foundation, Inc.

Please remember to update the dates in the new tests.

OK for master with those adjustments. Thanks.



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

* Re: [PATCH][Hashtable 3/6] Fix noexcept qualifications
  2020-07-17  9:55 ` Jonathan Wakely
@ 2020-07-29  9:33   ` François Dumont
  2020-07-30 12:13     ` Jonathan Wakely
  2020-07-30 17:42     ` Jonathan Wakely
  0 siblings, 2 replies; 5+ messages in thread
From: François Dumont @ 2020-07-29  9:33 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

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

I eventually committed the attached patch which consider all your 
remarks and moreover put back the move constructor implementation where 
it used to be (not inline). It limits the size of the patch.

I also added comments on true_type/false_type new usages like you 
advised on [Hashtable 0/6] thread.

François

On 17/07/20 11:55 am, Jonathan Wakely wrote:
> On 17/11/19 21:59 +0100, François Dumont wrote:
>> This patch adds noexcept qualification on allocator aware 
>> constructors and fix the one on the default constructor.
>>
>>     * include/bits/hashtable.h
>>     (_Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, 
>> true_type)):
>>     Add noexcept qualification.
>>     (_Hashtable(_Hashtable&&)): Fix noexcept qualification.
>>     (_Hashtable(_Hashtable&&, const allocator_type&)): Add noexcept
>>     qualification.
>>     * include/bits/unordered_map.h
>>     (unordered_map(unordered_map&&, const allocator_type&)): Add 
>> noexcept
>>     qualification.
>>     (unordered_multimap(unordered_multimap&&, const 
>> allocator_type&)): Add
>>     noexcept qualification.
>>     * include/bits/unordered_set.h
>>     (unordered_set(unordered_set&&, const allocator_type&)): Add 
>> noexcept
>>     qualification.
>>     (unordered_multiset(unordered_multiset&&, const 
>> allocator_type&)): Add
>>     noexcept qualification.
>>     * 
>> testsuite/23_containers/unordered_map/allocator/default_init.cc:
>>     New.
>>     * testsuite/23_containers/unordered_map/cons/
>>     noexcept_default_construct.cc: New.
>>     * testsuite/23_containers/unordered_map/cons/
>>     noexcept_move_construct.cc: New.
>>     * testsuite/23_containers/unordered_map/modifiers/move_assign.cc:
>>     New.
>>     * testsuite/23_containers/unordered_multimap/cons/
>>     noexcept_default_construct.cc: New.
>>     * testsuite/23_containers/unordered_multimap/cons/
>>     noexcept_move_construct.cc: New.
>>     * testsuite/23_containers/unordered_multiset/cons/
>>     noexcept_default_construct.cc: New.
>>     * testsuite/23_containers/unordered_multiset/cons/
>>     noexcept_move_construct.cc: New.
>>     * 
>> testsuite/23_containers/unordered_set/allocator/default_init.cc: New.
>>     * testsuite/23_containers/unordered_set/cons/
>>     noexcept_default_construct.cc: New.
>>     * 
>> testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc:
>>     New.
>>
>> Tested under Linux x86_64.
>>
>> François
>>
>
>> diff --git a/libstdc++-v3/include/bits/hashtable.h 
>> b/libstdc++-v3/include/bits/hashtable.h
>> index 5f785d4904d..ad07a36eb83 100644
>> --- a/libstdc++-v3/include/bits/hashtable.h
>> +++ b/libstdc++-v3/include/bits/hashtable.h
>> @@ -463,6 +463,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>     __hashtable_alloc(__node_alloc_type(__a))
>>       { }
>>
>> +      _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, true_type)
>> + noexcept(std::is_nothrow_copy_constructible<_H1>::value &&
>> + std::is_nothrow_copy_constructible<_Equal>::value)
>> +      : __hashtable_base(__ht),
>> +    __map_base(__ht),
>> +    __rehash_base(__ht),
>> +    __hashtable_alloc(std::move(__a)),
>> +    _M_buckets(__ht._M_buckets),
>> +    _M_bucket_count(__ht._M_bucket_count),
>> +    _M_before_begin(__ht._M_before_begin._M_nxt),
>> +    _M_element_count(__ht._M_element_count),
>> +    _M_rehash_policy(__ht._M_rehash_policy)
>> +      {
>> +    // Update, if necessary, buckets if __ht is using its single 
>> bucket.
>
> I know the comment was already present, but I can't parse this.
>
> There are two 'if' conditions, but don't they refer to the same thing?
> It's necessary if __ht is using a single bucket, so shouldn't it be
> either "Update buckets if __ht is using its single bucket" or "Update
> buckets if necessary"?
>
> "Update buckets if __ht is using its single bucket" seems preferable.
>
>> +    if (__ht._M_uses_single_bucket())
>> +      {
>> +        _M_buckets = &_M_single_bucket;
>> +        _M_single_bucket = __ht._M_single_bucket;
>> +      }
>> +
>> +    // Fix bucket containing the _M_before_begin pointer that can't be
>> +    // moved.
>> +    _M_update_bbegin();
>> +
>> +    __ht._M_reset();
>> +      }
>> +
>> +      _Hashtable(_Hashtable&&, __node_alloc_type&&, false_type);
>> +
>>       template<typename _InputIterator>
>>     _Hashtable(_InputIterator __first, _InputIterator __last,
>>            size_type __bkt_count_hint,
>> @@ -489,11 +518,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>
>>       _Hashtable(const _Hashtable&);
>>
>> -      _Hashtable(_Hashtable&&) noexcept;
>> +      _Hashtable(_Hashtable&& __ht)
>> +    noexcept( noexcept(
>> +      _Hashtable(std::declval<_Hashtable&&>(),
>
> The && here is redundant, declval adds && to the type anyway.
>
>> + std::declval<__node_alloc_type&&>(), std::declval<true_type>())) )
>
> Same for __node_alloc_type&& here.
>
> And true_type{} is shorter and simpler than std::declval<true_type>().
> We know is_nothrow_default_constructible<true_type> is true, so we can
> just use that.
>
>> +      : _Hashtable(std::move(__ht), 
>> std::move(__ht._M_node_allocator()),
>> +           true_type{})
>> +      { }
>>
>>       _Hashtable(const _Hashtable&, const allocator_type&);
>>
>> -      _Hashtable(_Hashtable&&, const allocator_type&);
>> +      _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
>> +    noexcept( noexcept(
>> +      _Hashtable(std::declval<_Hashtable&&>(),
>> +        std::declval<__node_alloc_type&&>(),
>
> Redundant &&s.
>
>> +        std::declval<typename 
>> __node_alloc_traits::is_always_equal>())) )
>
> Redundant declval: typename __node_alloc_traits::is_always_equal{}
>
>> +      : _Hashtable(std::move(__ht), __node_alloc_type(__a),
>> +           typename __node_alloc_traits::is_always_equal{})
>> +      { }
>>
>>       // Use delegating constructors.
>>       template<typename _InputIterator>
>> @@ -1368,36 +1410,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>       _M_assign(__ht, __alloc_node_gen);
>>     }
>>
>> -  template<typename _Key, typename _Value,
>> -       typename _Alloc, typename _ExtractKey, typename _Equal,
>> -       typename _H1, typename _H2, typename _Hash, typename 
>> _RehashPolicy,
>> -       typename _Traits>
>> -    _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
>> -           _H1, _H2, _Hash, _RehashPolicy, _Traits>::
>> -    _Hashtable(_Hashtable&& __ht) noexcept
>> -    : __hashtable_base(__ht),
>> -      __map_base(__ht),
>> -      __rehash_base(__ht),
>> -      __hashtable_alloc(std::move(__ht._M_base_alloc())),
>> -      _M_buckets(__ht._M_buckets),
>> -      _M_bucket_count(__ht._M_bucket_count),
>> -      _M_before_begin(__ht._M_before_begin._M_nxt),
>> -      _M_element_count(__ht._M_element_count),
>> -      _M_rehash_policy(__ht._M_rehash_policy)
>> -    {
>> -      // Update, if necessary, buckets if __ht is using its single 
>> bucket.
>> -      if (__ht._M_uses_single_bucket())
>> -    {
>> -      _M_buckets = &_M_single_bucket;
>> -      _M_single_bucket = __ht._M_single_bucket;
>> -    }
>> -
>> -      // Fix bucket containing the _M_before_begin pointer that 
>> can't be moved.
>> -      _M_update_bbegin();
>> -
>> -      __ht._M_reset();
>> -    }
>> -
>>   template<typename _Key, typename _Value,
>>        typename _Alloc, typename _ExtractKey, typename _Equal,
>>        typename _H1, typename _H2, typename _Hash, typename 
>> _RehashPolicy,
>> @@ -1424,11 +1436,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        typename _Traits>
>>     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
>>            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
>> -    _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
>> +    _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a, false_type)
>>     : __hashtable_base(__ht),
>>       __map_base(__ht),
>>       __rehash_base(__ht),
>> -      __hashtable_alloc(__node_alloc_type(__a)),
>> +      __hashtable_alloc(std::move(__a)),
>>       _M_buckets(nullptr),
>>       _M_bucket_count(__ht._M_bucket_count),
>>       _M_element_count(__ht._M_element_count),
>> diff --git a/libstdc++-v3/include/bits/unordered_map.h 
>> b/libstdc++-v3/include/bits/unordered_map.h
>> index 49c175a90be..5131e02e8aa 100644
>> --- a/libstdc++-v3/include/bits/unordered_map.h
>> +++ b/libstdc++-v3/include/bits/unordered_map.h
>> @@ -209,6 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       unordered_map(unordered_map&& __umap,
>>             const allocator_type& __a)
>> +    noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
>
> declval should be qualified. It might be simpler to just say:
>
>     noexcept( noexcept(_Hashtable(std::move(__umap._M_h), __a)) )
>
>>       : _M_h(std::move(__umap._M_h), __a)
>>       { }
>>
>> @@ -1356,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       unordered_multimap(unordered_multimap&& __ummap,
>>              const allocator_type& __a)
>> +    noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
>
> Same here.
>
>>       : _M_h(std::move(__ummap._M_h), __a)
>>       { }
>>
>> diff --git a/libstdc++-v3/include/bits/unordered_set.h 
>> b/libstdc++-v3/include/bits/unordered_set.h
>> index 855579ee623..7154ec843db 100644
>> --- a/libstdc++-v3/include/bits/unordered_set.h
>> +++ b/libstdc++-v3/include/bits/unordered_set.h
>> @@ -203,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       unordered_set(unordered_set&& __uset,
>>             const allocator_type& __a)
>> +    noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
>
> Same here.
>
>>       : _M_h(std::move(__uset._M_h), __a)
>>       { }
>>
>> @@ -1044,6 +1045,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       unordered_multiset(unordered_multiset&& __umset,
>>              const allocator_type& __a)
>> +    noexcept( noexcept(_Hashtable(declval<_Hashtable&&>(), __a)) )
>
> Same here.
>
>>       : _M_h(std::move(__umset._M_h), __a)
>>       { }
>>
>> diff --git 
>> a/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc 
>> b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc 
>>
>> new file mode 100644
>> index 00000000000..8c3103c2614
>> --- /dev/null
>> +++ 
>> b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
>> @@ -0,0 +1,69 @@
>> +// Copyright (C) 2019 Free Software Foundation, Inc.
>
> Please remember to update the dates in the new tests.
>
> OK for master with those adjustments. Thanks.
>
>


[-- Attachment #2: hashtable.patch --]
[-- Type: text/x-patch, Size: 35948 bytes --]

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 9d1ad592553..dc8ed2ee18c 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -460,6 +460,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__hashtable_alloc(__node_alloc_type(__a))
       { }
 
+      _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
+		 true_type /* alloc always equal */)
+	noexcept(std::is_nothrow_copy_constructible<_H1>::value &&
+		 std::is_nothrow_copy_constructible<_Equal>::value);
+
+      _Hashtable(_Hashtable&&, __node_alloc_type&&,
+		 false_type /* alloc always equal */);
+
       template<typename _InputIterator>
 	_Hashtable(_InputIterator __first, _InputIterator __last,
 		   size_type __bkt_count_hint,
@@ -486,11 +494,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Hashtable(const _Hashtable&);
 
-      _Hashtable(_Hashtable&&) noexcept;
+      _Hashtable(_Hashtable&& __ht)
+	noexcept( noexcept(
+	  _Hashtable(std::declval<_Hashtable>(),
+		     std::declval<__node_alloc_type>(),
+		     true_type{})) )
+      : _Hashtable(std::move(__ht), std::move(__ht._M_node_allocator()),
+		   true_type{})
+      { }
 
       _Hashtable(const _Hashtable&, const allocator_type&);
 
-      _Hashtable(_Hashtable&&, const allocator_type&);
+      _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
+	noexcept( noexcept(
+	  _Hashtable(std::declval<_Hashtable>(),
+		     std::declval<__node_alloc_type>(),
+		     typename __node_alloc_traits::is_always_equal{})) )
+      : _Hashtable(std::move(__ht), __node_alloc_type(__a),
+		   typename __node_alloc_traits::is_always_equal{})
+      { }
 
       // Use delegating constructors.
       template<typename _InputIterator>
@@ -1342,18 +1364,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   typename _Traits>
     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
 	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
-    _Hashtable(_Hashtable&& __ht) noexcept
+    _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
+	       true_type /* alloc always equal */)
+    noexcept(std::is_nothrow_copy_constructible<_H1>::value &&
+	     std::is_nothrow_copy_constructible<_Equal>::value)
     : __hashtable_base(__ht),
       __map_base(__ht),
       __rehash_base(__ht),
-      __hashtable_alloc(std::move(__ht._M_base_alloc())),
+      __hashtable_alloc(std::move(__a)),
       _M_buckets(__ht._M_buckets),
       _M_bucket_count(__ht._M_bucket_count),
       _M_before_begin(__ht._M_before_begin._M_nxt),
       _M_element_count(__ht._M_element_count),
       _M_rehash_policy(__ht._M_rehash_policy)
     {
-      // Update, if necessary, buckets if __ht is using its single bucket.
+      // Update buckets if __ht is using its single bucket.
       if (__ht._M_uses_single_bucket())
 	{
 	  _M_buckets = &_M_single_bucket;
@@ -1392,11 +1417,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   typename _Traits>
     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
 	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
-    _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
+    _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
+	       false_type /* alloc always equal */)
     : __hashtable_base(__ht),
       __map_base(__ht),
       __rehash_base(__ht),
-      __hashtable_alloc(__node_alloc_type(__a)),
+      __hashtable_alloc(std::move(__a)),
       _M_buckets(nullptr),
       _M_bucket_count(__ht._M_bucket_count),
       _M_element_count(__ht._M_element_count),
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 33f632ddb79..1aaa1a1a6ee 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -209,6 +209,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_map(unordered_map&& __umap,
 		    const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(std::move(__umap._M_h), __a)) )
       : _M_h(std::move(__umap._M_h), __a)
       { }
 
@@ -1303,6 +1304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_multimap(unordered_multimap&& __ummap,
 			 const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(std::move(__ummap._M_h), __a)) )
       : _M_h(std::move(__ummap._M_h), __a)
       { }
 
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index c9c9e9f38b7..6cbfcb1f0b6 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -203,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_set(unordered_set&& __uset,
 		    const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(std::move(__uset._M_h), __a)) )
       : _M_h(std::move(__uset._M_h), __a)
       { }
 
@@ -1044,6 +1045,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       unordered_multiset(unordered_multiset&& __umset,
 			 const allocator_type& __a)
+	noexcept( noexcept(_Hashtable(std::move(__umset._M_h), __a)) )
       : _M_h(std::move(__umset._M_h), __a)
       { }
 
diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map
index 7d55174f63b..4fa5c124d5a 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -144,6 +144,7 @@ namespace __debug
 
       unordered_map(unordered_map&& __umap,
 		    const allocator_type& __a)
+      noexcept( noexcept(_Base(std::move(__umap._M_base()), __a)) )
       : _Safe(std::move(__umap._M_safe()), __a),
 	_Base(std::move(__umap._M_base()), __a) { }
 
@@ -847,6 +848,7 @@ namespace __debug
 
       unordered_multimap(unordered_multimap&& __umap,
 			 const allocator_type& __a)
+      noexcept( noexcept(_Base(std::move(__umap._M_base()), __a)) )
       : _Safe(std::move(__umap._M_safe()), __a),
 	_Base(std::move(__umap._M_base()), __a) { }
 
diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set
index 37031da947e..94dde0d0ded 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -141,6 +141,7 @@ namespace __debug
 
       unordered_set(unordered_set&& __uset,
 		    const allocator_type& __a)
+      noexcept( noexcept(_Base(std::move(__uset._M_base()), __a)) )
       : _Safe(std::move(__uset._M_safe()), __a),
 	_Base(std::move(__uset._M_base()), __a) { }
 
@@ -717,6 +718,7 @@ namespace __debug
 
       unordered_multiset(unordered_multiset&& __uset,
 			 const allocator_type& __a)
+      noexcept( noexcept(_Base(std::move(__uset._M_base()), __a)) )
       : _Safe(std::move(__uset._M_safe()), __a),
 	_Base(std::move(__uset._M_base()), __a) { }
 
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
new file mode 100644
index 00000000000..473a5f1ce47
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/allocator/default_init.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 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 run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<std::pair<const T, T>> alloc_type;
+  typedef std::unordered_map<T, T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<std::pair<const T, T>> alloc_type;
+  typedef std::unordered_map<T, T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..f859ec939d0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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 <unordered_map>
+
+using type1 = std::unordered_map<int, int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_map<int, int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_map<int, int, std::hash<int>,
+				  not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
+			not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..99852b248d0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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>
+
+using type1 = std::unordered_map<int, int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_map<int, int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_map<int, int, std::hash<int>,
+				  not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc
new file mode 100644
index 00000000000..0a5ef1113d9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/move_assign.cc
@@ -0,0 +1,81 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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 <utility>
+#include <unordered_map>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_counter_type.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  using namespace std;
+  using __gnu_test::counter_type;
+
+  std::vector<pair<int, counter_type>> insts { { 0, 0 }, { 1, 1 }, { 2, 2 } };
+  typedef unordered_map<int, counter_type> Map;
+  Map m;
+
+  counter_type::reset();
+
+  m.insert(make_move_iterator(insts.begin()), make_move_iterator(insts.end()));
+
+  VERIFY( m.size() == 3 );
+  VERIFY( counter_type::default_count == 0 );
+  VERIFY( counter_type::copy_count == 0 );
+  VERIFY( counter_type::move_count == 3 );
+}
+
+void test02()
+{
+  using namespace std;
+  using __gnu_test::counter_type;
+  using __gnu_test::propagating_allocator;
+
+  typedef propagating_allocator<pair<const int, counter_type>, false> Alloc;
+  typedef unordered_map<int, counter_type,
+			hash<int>, equal_to<int>,
+			Alloc> Map;
+
+  Alloc a1(1);
+  Map m1(3, a1);
+  m1 = { { 0, 0 }, { 1, 1 }, { 2, 2 } };
+  Alloc a2(2);
+  Map m2(3, a2);
+  m2 = { { 3, 0 }, { 4, 1 }, { 5, 2 } };
+
+  counter_type::reset();
+
+  m2 = move(m1);
+
+  VERIFY( m1.empty() );
+  VERIFY( m2.size() == 3 );
+  VERIFY( counter_type::default_count == 0 );
+  VERIFY( counter_type::copy_count == 0 );
+  VERIFY( counter_type::move_count == 3 );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..98e2b017ca9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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 <unordered_map>
+
+using type1 = std::unordered_multimap<int, int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multimap<int, int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multimap<int, int, std::hash<int>,
+				       not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
+				       not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..1d60c0184eb
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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>
+
+using type1 = std::unordered_multimap<int, int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multimap<int, int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multimap<int, int, std::hash<int>,
+				       not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..b7c0d802125
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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 <unordered_set>
+
+using type1 = std::unordered_multiset<int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multiset<int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multiset<int, std::hash<int>,
+				      not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>,
+				      not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..dd0e4ca920b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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_set>
+
+using type1 = std::unordered_multiset<int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_multiset<int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_multiset<int, std::hash<int>,
+				      not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc
new file mode 100644
index 00000000000..37110dd6eb0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/allocator/default_init.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 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 run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::unordered_set<T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::unordered_set<T, std::hash<T>, std::equal_to<T>,
+			     alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
new file mode 100644
index 00000000000..d60a81ffb7c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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 <unordered_set>
+
+using type1 = std::unordered_set<int>;
+
+static_assert(std::is_nothrow_default_constructible<type1>::value,
+	      "noexcept default constructible");
+
+struct not_noexcept_dflt_cons_hash
+{
+  not_noexcept_dflt_cons_hash() /* noexcept */;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_set<int, not_noexcept_dflt_cons_hash>;
+
+static_assert( !std::is_nothrow_default_constructible<type2>::value,
+	       "not noexcept default constructible");
+
+struct not_noexcept_dflt_cons_equal_to
+{
+  not_noexcept_dflt_cons_equal_to() /* noexcept */;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_set<int, std::hash<int>,
+				  not_noexcept_dflt_cons_equal_to>;
+
+static_assert( !std::is_nothrow_default_constructible<type3>::value,
+	       "not noexcept default constructible");
+
+template<typename _Tp>
+  struct not_noexcept_dflt_cons_alloc : std::allocator<_Tp>
+  {
+    not_noexcept_dflt_cons_alloc() /* noexcept */;
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_dflt_cons_alloc<_Tp1> other; };
+  };
+
+using type4 = std::unordered_set<int, std::hash<int>, std::equal_to<int>,
+				  not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+
+static_assert(!std::is_nothrow_default_constructible<type4>::value,
+	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc
new file mode 100644
index 00000000000..9be5ed07a33
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_move_construct.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2020 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_set>
+
+using type1 = std::unordered_set<int>;
+
+static_assert( std::is_nothrow_move_constructible<type1>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<type1,
+	       type1&&, const typename type1::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_hash
+{
+  not_noexcept_copy_cons_hash() noexcept;
+  not_noexcept_copy_cons_hash(const not_noexcept_copy_cons_hash&) /* noexcept */;
+  not_noexcept_copy_cons_hash(not_noexcept_copy_cons_hash&&) noexcept;
+
+  std::size_t
+  operator()(int) const noexcept;
+};
+
+using type2 = std::unordered_set<int, not_noexcept_copy_cons_hash>;
+
+static_assert( !std::is_nothrow_move_constructible<type2>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type2, type2&&,
+	       const typename type2::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );
+
+struct not_noexcept_copy_cons_equal_to
+{
+  not_noexcept_copy_cons_equal_to() noexcept;
+  not_noexcept_copy_cons_equal_to(const not_noexcept_copy_cons_equal_to&) /* noexcept */;
+  not_noexcept_copy_cons_equal_to(not_noexcept_copy_cons_equal_to&&) noexcept;
+
+  bool
+  operator()(int, int) const noexcept;
+};
+
+using type3 = std::unordered_set<int, std::hash<int>,
+				  not_noexcept_copy_cons_equal_to>;
+
+static_assert( !std::is_nothrow_move_constructible<type3>::value,
+	       "noexcept move constructor" );
+static_assert( !std::is_nothrow_constructible<type3, type3&&,
+	       const typename type3::allocator_type&>::value,
+	       "not noexcept move constructor with allocator" );

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

* Re: [PATCH][Hashtable 3/6] Fix noexcept qualifications
  2020-07-29  9:33   ` François Dumont
@ 2020-07-30 12:13     ` Jonathan Wakely
  2020-07-30 17:42     ` Jonathan Wakely
  1 sibling, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-07-30 12:13 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 29/07/20 11:33 +0200, François Dumont via Libstdc++ wrote:
>I eventually committed the attached patch which consider all your 
>remarks and moreover put back the move constructor implementation 
>where it used to be (not inline). It limits the size of the patch.
>
>I also added comments on true_type/false_type new usages like you 
>advised on [Hashtable 0/6] thread.

Thanks!



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

* Re: [PATCH][Hashtable 3/6] Fix noexcept qualifications
  2020-07-29  9:33   ` François Dumont
  2020-07-30 12:13     ` Jonathan Wakely
@ 2020-07-30 17:42     ` Jonathan Wakely
  1 sibling, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-07-30 17:42 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

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

On 29/07/20 11:33 +0200, François Dumont via Libstdc++ wrote:
>+using type4 = std::unordered_set<int, std::hash<int>, std::equal_to<int>,
>+				  not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;

A couple of these tests use the wrong allocator type, which means they
fail when compiled as C++20.

Fixed with this patch. Tested x86_64-linux, committed to trunk.



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

commit 357beca8bce179315bdf112c0f1df20ff5874f39
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jul 30 18:41:47 2020

    libstdc++: Fix tests using wrong allocator type
    
    libstdc++-v3/ChangeLog:
    
            * testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc:
            Use allocator with the correct value type.
            * testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc:
            Likewise.

diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
index b7c0d802125..8511cb95421 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/noexcept_default_construct.cc
@@ -62,7 +62,7 @@ template<typename _Tp>
   };
 
 using type4 = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>,
-				      not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+				      not_noexcept_dflt_cons_alloc<int>>;
 
 static_assert(!std::is_nothrow_default_constructible<type4>::value,
 	      "not noexcept default constructible");
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
index d60a81ffb7c..44db4aec6cf 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/noexcept_default_construct.cc
@@ -62,7 +62,7 @@ template<typename _Tp>
   };
 
 using type4 = std::unordered_set<int, std::hash<int>, std::equal_to<int>,
-				  not_noexcept_dflt_cons_alloc<std::pair<const int, int>>>;
+				 not_noexcept_dflt_cons_alloc<int>>;
 
 static_assert(!std::is_nothrow_default_constructible<type4>::value,
 	      "not noexcept default constructible");

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

end of thread, other threads:[~2020-07-30 17:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-17 21:01 [PATCH][Hashtable 3/6] Fix noexcept qualifications François Dumont
2020-07-17  9:55 ` Jonathan Wakely
2020-07-29  9:33   ` François Dumont
2020-07-30 12:13     ` Jonathan Wakely
2020-07-30 17:42     ` 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).