https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90413

            Bug ID: 90413
           Summary: Bad diagnostic when trying to copy an uncopyable type
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Here's a short repro:

template<class T>
struct Bar {
    Bar() {}
    Bar(const Bar&) {
        static_assert(sizeof(T) == 1, "");
    }
};
template<class T>
struct Foo {
    Foo() {}
    Foo(const Foo&) = default;
    Bar<T> b;
};
template<class T>
struct Baz {
    Baz() {}
    Baz(const Baz& o) : b(o.b) {}
    Bar<T> b;
};
int main() { 
#ifdef DEFAULT
    Foo<int> f;
    Foo<int> g = f;
#else
    Baz<int> f;
    Baz<int> g = f;
#endif
}

Without -DDEFAULT, the diagnostic points to the offending line (<source>:26
does appear in the trace):

<source>: In instantiation of 'Bar<T>::Bar(const Bar<T>&) [with T = int]':
<source>:17:30:   required from 'Baz<T>::Baz(const Baz<T>&) [with T = int]'
<source>:26:18:   required from here
<source>:5:33: error: static assertion failed
    5 |         static_assert(sizeof(T) == 1, "");
      |                       ~~~~~~~~~~^~~~
Compiler returned: 1

With -DDEFAULT, the offending line disappears (no mention of <source>:23 here
at all)!

<source>: In instantiation of 'Bar<T>::Bar(const Bar<T>&) [with T = int]':
<source>:11:5:   required from here
<source>:5:33: error: static assertion failed
    5 |         static_assert(sizeof(T) == 1, "");
      |                       ~~~~~~~~~~^~~~
Compiler returned: 1

In larger examples, this makes it very difficult to actually find the source of
error. A larger reproduction, closer to the real example we ran into:

#include <unordered_map>

struct X {
    X(X const&) = delete;
};

using Map = std::unordered_map<int, X>;

void copy_func(Map) {}

void map_error(Map& m) {
    copy_func(m);
}

The 9.1 error is as follows (note that the line copy_func(m) appears nowhere in
this trace, despite being the proximal cause of offense):

In file included from
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/x86_64-linux-gnu/bits/c++allocator.h:33,
                 from
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/allocator.h:46,
                 from
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/unordered_map:40,
                 from <source>:1:
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/ext/new_allocator.h:
In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*,
_Args&& ...) [with _Up = std::pair<const int, X>; _Args = {const
std::pair<const int, X>&}; _Tp = std::__detail::_Hash_node<std::pair<const int,
X>, false>]':
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/alloc_traits.h:482:2:
  required from 'static void std::allocator_traits<std::allocator<_Tp1>
>::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&,
_Up*, _Args&& ...) [with _Up = std::pair<const int, X>; _Args = {const
std::pair<const int, X>&}; _Tp = std::__detail::_Hash_node<std::pair<const int,
X>, false>; std::allocator_traits<std::allocator<_Tp1> >::allocator_type =
std::allocator<std::__detail::_Hash_node<std::pair<const int, X>, false> >]'
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/hashtable_policy.h:2087:36:
  required from 'std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type*
std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...)
[with _Args = {const std::pair<const int, X>&}; _NodeAlloc =
std::allocator<std::__detail::_Hash_node<std::pair<const int, X>, false> >;
std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type =
std::__detail::_Hash_node<std::pair<const int, X>, false>]'
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/hashtable.h:1243:46:
  required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable(const
std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
_RehashPolicy, _Traits>&) [with _Key = int; _Value = std::pair<const int, X>;
_Alloc = std::allocator<std::pair<const int, X> >; _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>]'
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/unordered_map.h:181:7:
  required from here
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/ext/new_allocator.h:145:20:
error: use of deleted function 'constexpr std::pair<_T1, _T2>::pair(const
std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = X]'
  145 |  noexcept(noexcept(::new((void *)__p)
      |                    ^~~~~~~~~~~~~~~~~~
  146 |        _Up(std::forward<_Args>(__args)...)))
      |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/unordered_map:43,
                 from <source>:1:
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/stl_pair.h:318:17:
note: 'constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with
_T1 = const int; _T2 = X]' is implicitly deleted because the default definition
would be ill-formed:
  318 |       constexpr pair(const pair&) = default; ///< Copy constructor
      |                 ^~~~
/opt/compiler-explorer/gcc-trunk-20190509/include/c++/10.0.0/bits/stl_pair.h:318:17:
error: use of deleted function 'X::X(const X&)'
<source>:4:5: note: declared here
    4 |     X(X const&) = delete;
      |     ^
Compiler returned: 1

Compile the above with clang using -stdlib=libc++ and you get, somewhere in the
trace:

<source>:12:15: note: in instantiation of member function
'std::__1::unordered_map<int, X, std::__1::hash<int>, std::__1::equal_to<int>,
std::__1::allocator<std::__1::pair<const int, X> > >::unordered_map' requested
here
    copy_func(m);
              ^

It's still not generally a _great_ error diagnostic, but it does point me back
to the original source which makes it possible to track down the problem.

Reply via email to