]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Avoid instantiation of _Hash_node before it's needed
authorJonathan Wakely <jwakely@redhat.com>
Fri, 8 Oct 2021 12:35:54 +0000 (13:35 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Fri, 8 Oct 2021 23:57:47 +0000 (00:57 +0100)
This is a step towards restoring support for incomplete types in
unordered containers (PR 53339).

We do not need to instantiate the node type to get its value_type
member, because we know that the value type is the first template
parameter. We can deduce that template argument using a custom trait and
a partial specialization for _Hash_node. If we wanted to support custom
hash node types we could still use typename _Tp::value_type in the
primary template of that trait, but that seems unnecessary.

The other change needed is to defer a static assert at class scope, so
that it is done when the types are complete. We must have a complete
type in the destructor, so we can do it there instead.

libstdc++-v3/ChangeLog:

* include/bits/hashtable.h: Move static assertion to destructor.
* include/bits/hashtable_policy.h: Deduce value type from node
type without instantiating it.

libstdc++-v3/include/bits/hashtable.h
libstdc++-v3/include/bits/hashtable_policy.h

index 79a3096b62b6f4be2b06282b82269bc3f5f7a75f..ff8af2201cd1ec174fb7ad5c03c31590403a88ee 100644 (file)
@@ -329,14 +329,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       struct __hash_code_base_access : __hash_code_base
       { using __hash_code_base::_M_bucket_index; };
 
-      // Getting a bucket index from a node shall not throw because it is used
-      // in methods (erase, swap...) that shall not throw.
-      static_assert(noexcept(declval<const __hash_code_base_access&>()
-                       ._M_bucket_index(declval<const __node_value_type&>(),
-                                        (std::size_t)0)),
-                   "Cache the hash code or qualify your functors involved"
-                   " in hash code and bucket index computation with noexcept");
-
       // To get bucket index we need _RangeHash not to throw.
       static_assert(is_nothrow_default_constructible<_RangeHash>::value,
                    "Functor used to map hash code to bucket index"
@@ -1556,6 +1548,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
               _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
     ~_Hashtable() noexcept
     {
+      // Getting a bucket index from a node shall not throw because it is used
+      // in methods (erase, swap...) that shall not throw. Need a complete
+      // type to check this, so do it in the destructor not at class scope.
+      static_assert(noexcept(declval<const __hash_code_base_access&>()
+                       ._M_bucket_index(declval<const __node_value_type&>(),
+                                        (std::size_t)0)),
+                   "Cache the hash code or qualify your functors involved"
+                   " in hash code and bucket index computation with noexcept");
+
       clear();
       _M_deallocate_buckets();
     }
index 2f8502588f58abd90b0de6061ebaf0002cfbf7a6..75488da13f7db5c51afb1789b049f6d95b6fc9bd 100644 (file)
@@ -1840,6 +1840,13 @@ namespace __detail
     {
     private:
       using __ebo_node_alloc = _Hashtable_ebo_helper<0, _NodeAlloc>;
+
+      template<typename>
+       struct __get_value_type;
+      template<typename _Val, bool _Cache_hash_code>
+       struct __get_value_type<_Hash_node<_Val, _Cache_hash_code>>
+       { using type = _Val; };
+
     public:
       using __node_type = typename _NodeAlloc::value_type;
       using __node_alloc_type = _NodeAlloc;
@@ -1847,7 +1854,7 @@ namespace __detail
       using __node_alloc_traits = __gnu_cxx::__alloc_traits<__node_alloc_type>;
 
       using __value_alloc_traits = typename __node_alloc_traits::template
-       rebind_traits<typename __node_type::value_type>;
+       rebind_traits<typename __get_value_type<__node_type>::type>;
 
       using __node_ptr = __node_type*;
       using __node_base = _Hash_node_base;