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.