Bug 107022 - error: use of deleted function 'std::unordered_map
Summary: error: use of deleted function 'std::unordered_map
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 107340 (view as bug list)
Depends on:
Blocks:
 
Reported: 2022-09-23 21:58 UTC by piersh
Modified: 2022-10-24 06:47 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description piersh 2022-09-23 21:58:21 UTC
this is a regression in newer point-releases of gcc (this bug got backported). it appears first in 10.4, 11.2.1 and 12.x. 10.3 and 11.2.0 do not have this issue.


#include <unordered_map>
#include <memory>

struct key {};

struct foo
{
    struct my_hash
    {
        my_hash(int i = 42) {}
        std::size_t operator()(const key &ep) const { return 0; }
    };

private:
    std::unordered_map<key, std::weak_ptr<std::string>, foo::my_hash> things_{};
};


<source>:15:79: error: use of deleted function 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = key; _Tp = std::weak_ptr<std::__cxx11::basic_string<char> >; _Hash = foo::my_hash; _Pred = std::equal_to<key>; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >]'
   15 |     std::unordered_map<key, std::weak_ptr<std::string>, foo::my_hash> things_{};
      |                                                                               ^
In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/unordered_map:47,
                 from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/unordered_map.h:141:7: note: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = key; _Tp = std::weak_ptr<std::__cxx11::basic_string<char> >; _Hash = foo::my_hash; _Pred = std::equal_to<key>; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >]' is implicitly deleted because the default definition would be ill-formed:
  141 |       unordered_map() = default;
      |       ^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/unordered_map.h:141:7: error: use of deleted function 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::_Hashtable() [with _Key = key; _Value = std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > >; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<key>; _Hash = foo::my_hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>]'
In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/unordered_map:46:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:529:7: note: 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::_Hashtable() [with _Key = key; _Value = std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > >; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<key>; _Hash = foo::my_hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>]' is implicitly deleted because the default definition would be ill-formed:
  529 |       _Hashtable() = default;
      |       ^~~~~~~~~~
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:529:7: error: use of deleted function 'constexpr std::_Enable_default_constructor<false, _Tag>::_Enable_default_constructor() [with _Tag = std::__detail::_Hash_node_base]'
In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:36:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/enable_special_members.h:113:15: note: declared here
  113 |     constexpr _Enable_default_constructor() noexcept = delete;
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 1
Comment 1 Andrew Pinski 2022-09-23 22:00:54 UTC
This is another when is the inner type complete and the constructor can be used issues really.
Comment 2 Andrew Pinski 2022-09-23 22:05:34 UTC
Mainly read bug 102199 comment #7
Comment 3 Jonathan Wakely 2022-09-23 22:14:48 UTC
Yes, and the standard says that instantiating std::unordered_map with incomplete types is undefined.
Comment 4 piersh 2022-09-23 22:16:27 UTC
is it related to nested classes? this reproduces the issue: uncomment line 9 to repro:


#include <unordered_map>
#include <memory>

struct key {};

struct my_hash
{
    my_hash() {}
    //my_hash(int i = 42) {}  // <<-- uncomment for bug
    std::size_t operator()(const key &ep) const { return 0; }
};

struct foo
{
    foo();
private:
    std::unordered_map<key, int, my_hash> things_;
};

foo::foo() {}
Comment 5 piersh 2022-09-23 22:21:21 UTC
oh, no. scratch that last comment.
Comment 6 Andrew Pinski 2022-09-23 22:22:35 UTC
(In reply to piersh from comment #4)
> struct my_hash
> {
>     my_hash() {}
>     my_hash(int i = 42) {}  // <<-- uncomment for bug
>     std::size_t operator()(const key &ep) const { return 0; }
> };

That is because my_hash constructor call with no arguments is ambigous at that point. If you define one or the other constructor, it is no longer ambigous. If you define both, the code is invalid.
Comment 7 Andrew Pinski 2022-10-21 07:24:11 UTC
*** Bug 107340 has been marked as a duplicate of this bug. ***
Comment 8 Jens Maurer 2022-10-21 14:03:16 UTC
I understand we're in a tangled web of partially-complete class rules here,
but the standard does give you the expectation that the inner class is complete at its closing brace:

[class.pre] p2 says:

"A class is considered defined after the closing brace of its class-specifier has been seen even though its member functions are in general not yet defined."
Comment 9 Jonathan Wakely 2022-10-21 15:08:07 UTC
For the example in comment 0 the default-initializer for things_{} is the problem, removing the {} allows it to compile.

For the example in Bug 107340 the problem is the default-initializer x = 0 in the nested class, removing that allows it to compile.

The nested class is complete at the closing } but its complete class contexts are not complete until the enclosing class is complete. default-initializers and nested classes do not work well.