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.

Reply via email to