http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59751
Bug ID: 59751 Summary: Hash tables don't use allocator_traits Product: gcc Version: 4.8.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: martinho.fernandes at gmail dot com Take the following program: --- #include <unordered_map> #include <functional> #include <utility> #include <cstddef> template <typename T> struct my_allocator { using value_type = T; T* allocate(std::size_t) { return nullptr; } void deallocate(T*, std::size_t) {} }; int main() { using map_type = std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double>>>; map_type m { { 1, 1. } , { 2, 2. } }; } --- As far as I understand the allocator used is a minimally complete. std::allocator_traits can fill in all the rest, so the program is well-formed. However, attempting compilation with GCC 4.8.1 results in: --- In file included from /usr/include/c++/4.8/unordered_map:47:0, from main.cpp:1: /usr/include/c++/4.8/bits/hashtable.h: In instantiation of ‘class std::_Hashtable<int, std::pair<const int, double>, my_allocator<std::pair<const int, double> >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >’: /usr/include/c++/4.8/bits/unordered_map.h:100:18: required from ‘class std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >’ main.cpp:17:14: required from here /usr/include/c++/4.8/bits/hashtable.h:194:47: error: no type named ‘pointer’ in ‘struct my_allocator<std::pair<const int, double> >’ typedef typename _Alloc::pointer pointer; ^ /usr/include/c++/4.8/bits/hashtable.h:195:55: error: no type named ‘const_pointer’ in ‘struct my_allocator<std::pair<const int, double> >’ typedef typename _Alloc::const_pointer const_pointer; ^ /usr/include/c++/4.8/bits/hashtable.h:196:55: error: no type named ‘reference’ in ‘struct my_allocator<std::pair<const int, double> >’ typedef typename _Alloc::reference reference; ^ /usr/include/c++/4.8/bits/hashtable.h:197:55: error: no type named ‘const_reference’ in ‘struct my_allocator<std::pair<const int, double> >’ typedef typename _Alloc::const_reference const_reference; ^ /usr/include/c++/4.8/bits/hashtable.h:317:8: error: no class template named ‘rebind’ in ‘struct my_allocator<std::pair<const int, double> >’ _Node_allocator_type; ^ /usr/include/c++/4.8/bits/hashtable.h:319:8: error: no class template named ‘rebind’ in ‘struct my_allocator<std::pair<const int, double> >’ _Bucket_allocator_type; ^ /usr/include/c++/4.8/bits/hashtable.h:321:75: error: no class template named ‘rebind’ in ‘struct my_allocator<std::pair<const int, double> >’ using __before_begin = __detail::_Before_begin<_Node_allocator_type> ^ In file included from /usr/include/c++/4.8/unordered_map:48:0, from main.cpp:1: /usr/include/c++/4.8/bits/unordered_map.h: In instantiation of ‘class std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >’: main.cpp:17:14: required from here /usr/include/c++/4.8/bits/unordered_map.h:116:49: error: no type named ‘pointer’ in ‘std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >::allocator_type {aka struct my_allocator<std::pair<const int, double> >}’ typedef typename allocator_type::pointer pointer; ^ /usr/include/c++/4.8/bits/unordered_map.h:117:54: error: no type named ‘const_pointer’ in ‘std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >::allocator_type {aka struct my_allocator<std::pair<const int, double> >}’ typedef typename allocator_type::const_pointer const_pointer; ^ /usr/include/c++/4.8/bits/unordered_map.h:118:50: error: no type named ‘reference’ in ‘std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >::allocator_type {aka struct my_allocator<std::pair<const int, double> >}’ typedef typename allocator_type::reference reference; ^ /usr/include/c++/4.8/bits/unordered_map.h:119:56: error: no type named ‘const_reference’ in ‘std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, double> > >::allocator_type {aka struct my_allocator<std::pair<const int, double> >}’ typedef typename allocator_type::const_reference const_reference; ^ In file included from /usr/include/c++/4.8/unordered_map:47:0, from main.cpp:1: /usr/include/c++/4.8/bits/hashtable.h: In instantiation of ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable(_InputIterator, _InputIterator, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const _H1&, const _H2&, const _Hash&, const _Equal&, const _ExtractKey&, const allocator_type&) [with _InputIterator = const std::pair<const int, double>*; _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::allocator_type = my_allocator<std::pair<const int, double> >]’: /usr/include/c++/4.8/bits/hashtable.h:419:26: required from ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable(std::initializer_list<_Value>, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const _H1&, const key_equal&, const allocator_type&) [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_equal = std::equal_to<int> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::allocator_type = my_allocator<std::pair<const int, double> >]’ /usr/include/c++/4.8/bits/unordered_map.h:189:35: required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(std::initializer_list<typename std::_Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::is_default_constructible<_Hash>, std::is_copy_assignable<_Hash>, std::__detail::__is_noexcept_hash<_Key, _Hash> > >::value, false, true> >::value_type>, std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type, const hasher&, const key_equal&, const allocator_type&) [with _Key = int; _Tp = double; _Hash = std::hash<int> _Pred = std::equal_to<int> _Alloc = my_allocator<std::pair<const int, double> > typename std::_Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc, std::__detail::_Select1st, _Pred, _Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<std::__not_<std::__and_<std::__is_fast_hash<_Hash>, std::is_default_constructible<_Hash>, std::is_copy_assignable<_Hash>, std::__detail::__is_noexcept_hash<_Key, _Hash> > >::value, false, true> >::value_type = std::pair<const int, double> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type = long unsigned int; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::hasher = std::hash<int> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_equal = std::equal_to<int> std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::allocator_type = my_allocator<std::pair<const int, double> >]’ main.cpp:17:40: required from here /usr/include/c++/4.8/bits/hashtable.h:852:19: error: using invalid field ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_bbegin’ _M_rehash_policy() ^ /usr/include/c++/4.8/bits/hashtable.h: In instantiation of ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base& std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_before_begin() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base = std::__detail::_Hash_node_base]’: /usr/include/c++/4.8/bits/hashtable.h:1644:23: required from ‘void std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::clear() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/hashtable.h:958:13: required from ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::~_Hashtable() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/unordered_map.h:97:11: required from here /usr/include/c++/4.8/bits/hashtable.h:339:26: error: using invalid field ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_bbegin’ { return _M_bbegin._M_node; } ^ /usr/include/c++/4.8/bits/hashtable.h: In instantiation of ‘void std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_deallocate_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type*) [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type = std::__detail::_Hash_node<std::pair<const int, double>, false>]’: /usr/include/c++/4.8/bits/hashtable.h:763:28: required from ‘void std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_deallocate_nodes(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type*) [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type = std::__detail::_Hash_node<std::pair<const int, double>, false>]’ /usr/include/c++/4.8/bits/hashtable.h:1641:37: required from ‘void std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::clear() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/hashtable.h:958:13: required from ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::~_Hashtable() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/unordered_map.h:97:11: required from here /usr/include/c++/4.8/bits/hashtable.h:746:25: error: ‘_M_node_allocator’ was not declared in this scope _M_node_allocator().destroy(__n); ^ /usr/include/c++/4.8/bits/hashtable.h: In instantiation of ‘const __node_base& std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_before_begin() const [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base = std::__detail::_Hash_node_base]’: /usr/include/c++/4.8/bits/hashtable.h:369:58: required from ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type* std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_begin() const [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true> std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type = std::__detail::_Hash_node<std::pair<const int, double>, false>]’ /usr/include/c++/4.8/bits/hashtable.h:1641:36: required from ‘void std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::clear() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/hashtable.h:958:13: required from ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::~_Hashtable() [with _Key = int; _Value = std::pair<const int, double> _Alloc = my_allocator<std::pair<const int, double> > _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int> _H1 = std::hash<int> _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>]’ /usr/include/c++/4.8/bits/unordered_map.h:97:11: required from here /usr/include/c++/4.8/bits/hashtable.h:343:26: error: using invalid field ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_bbegin’ { return _M_bbegin._M_node; } ^ --- It appears unordered_map uses the allocator directly instead of using its traits.