From: Jonathan Wakely Date: Fri, 8 Oct 2021 12:35:54 +0000 (+0100) Subject: libstdc++: Avoid instantiation of _Hash_node before it's needed X-Git-Tag: basepoints/gcc-13~4055 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=64acc43de1e33616e43b239887a260eb4a51fcc7;p=thirdparty%2Fgcc.git libstdc++: Avoid instantiation of _Hash_node before it's needed 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. --- diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 79a3096b62b6..ff8af2201cd1 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -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() - ._M_bucket_index(declval(), - (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() + ._M_bucket_index(declval(), + (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(); } diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index 2f8502588f58..75488da13f7d 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -1840,6 +1840,13 @@ namespace __detail { private: using __ebo_node_alloc = _Hashtable_ebo_helper<0, _NodeAlloc>; + + template + struct __get_value_type; + template + 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; + rebind_traits::type>; using __node_ptr = __node_type*; using __node_base = _Hash_node_base;