From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 342883841476; Wed, 8 Jun 2022 22:04:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 342883841476 From: "lhyatt at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/84920] Better handling of unmatched/ambiguous calls Date: Wed, 08 Jun 2022 22:04:08 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 8.0 X-Bugzilla-Keywords: diagnostic X-Bugzilla-Severity: normal X-Bugzilla-Who: lhyatt at gcc dot gnu.org X-Bugzilla-Status: ASSIGNED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: dmalcolm at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: cc attachments.created Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 22:04:09 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D84920 Lewis Hyatt changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |lhyatt at gcc dot gnu.org --- Comment #8 from Lewis Hyatt --- Created attachment 53108 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=3D53108&action=3Dedit One possible approach Hello- What do you all think of this approach? The new options -foverload-candidates-reduce-level and -foverload-candidates-stop-level would configure the amount of information = that is output regarding overload candidates. When the number of overloads excee= ds -foverload-candidates-reduce-level (default 3), then the source lines are no longer printed for each candidate, cutting the output length in half. The source lines seem rarely useful anyway, since the diagnostic's first line already prints the overload being considered. When the number of overloads exceeds -foverload-candidates-stop-level (default 7), none of the overloads= is printed, since this is presumably a case such as a heavily overloaded opera= tor where the large number of candidates is less likely to be helpful in fixing= the problem. For a testcase like this common (for me) typo: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D #include void f(std::ostream& o, int a) { o << a < '\n'; } =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D GCC then outputs: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D iowarn.cpp: In function =E2=80=98void f(std::ostream&, int)=E2=80=99: iowarn.cpp:3:12: error: no match for =E2=80=98operator<=E2=80=99 (operand t= ypes are =E2=80=98std::basic_ostream=E2=80=99 and =E2=80=98char=E2=80=99) 3 | o << a < '\n'; | ~~~~~~ ^ ~~~~ | | | | | char | std::basic_ostream iowarn.cpp:3:12: note: declining to output 15 candidates (limit 7); compile with =E2=80=98-foverload-candidates-stop-level=3D15=E2=80=99 to see them =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D which at least for this specific case feels like an improvement to me... It= 's obvious what is wrong now. If you follow the suggestion and add the flag to the compile, then you see: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D iowarn.cpp: In function =E2=80=98void f(std::ostream&, int)=E2=80=99: iowarn.cpp:3:12: error: no match for =E2=80=98operator<=E2=80=99 (operand t= ypes are =E2=80=98std::basic_ostream=E2=80=99 and =E2=80=98char=E2=80=99) 3 | o << a < '\n'; | ~~~~~~ ^ ~~~~ | | | | | char | std::basic_ostream iowarn.cpp:3:12: note: candidate: =E2=80=98operator<(int, int)=E2=80=99 (bu= ilt-in) iowarn.cpp:3:12: note: no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2=80=99 to =E2=80=98int=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 46, from /home/lewis/gccdev/release/include/c++/13.0.0/bits/locale_classes.h:40, from /home/lewis/gccdev/release/include/c++/13.0.0/bits/ios_base.h:41, from /home/lewis/gccdev/release/include/c++/13.0.0/ios:42, from /home/lewis/gccdev/release/include/c++/13.0.0/ostream= :38, from iowarn.cpp:1: /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:451:5: no= te: candidate: =E2=80=98template constexpr bool std::operator<= (const reverse_iterator<_Iterator>&, const reverse_iterator<_Iterator>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:451:5: no= te:=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::reverse_iterator<_Iterator>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:496:5: no= te: candidate: =E2=80=98template constexpr = bool std::operator<(const reverse_iterator<_Iterator>&, const reverse_iterator<_IteratorR>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:496:5: no= te:=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::reverse_iterator<_Iterator>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1683:5: n= ote: candidate: =E2=80=98template constexpr = bool std::operator<(const move_iterator<_IteratorL>&, const move_iterator<_IteratorR>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1683:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::move_iterator<_IteratorL>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1748:5: n= ote: candidate: =E2=80=98template constexpr bool std::operator<= (const move_iterator<_IteratorL>&, const move_iterator<_IteratorL>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1748:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::move_iterator<_IteratorL>=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_algobase.h:64, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 49: /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_pair.h:665:5: note: candidate: =E2=80=98template constexpr bool std::oper= ator<(const pair<_T1, _T2>&, const pair<_T1, _T2>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_pair.h:665:5: note:= =20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::pair<_T1, _T2>=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:47, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 52: /home/lewis/gccdev/release/include/c++/13.0.0/string_view:594:5: note: candidate: =E2=80=98template constexpr bool std::operator<(basic_string_view<_CharT, _Traits>, basic_string_view<_CharT, _Traits>)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/string_view:594:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98std::basic_string_view<_CharT, _Traits>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/string_view:600:5: note: candidate: =E2=80=98template constexpr bool std::operator<(basic_string_view<_CharT, _Traits>, __type_identity_t >)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/string_view:600:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98std::basic_string_view<_CharT, _Traits>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/string_view:607:5: note: candidate: =E2=80=98template constexpr bool std::operator<(__type_identity_t >, basic_string_view<_CharT, _Traits>)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/string_view:607:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: mismatched types =E2=80=98std::basic_string_view<_= CharT, _Traits>=E2=80=99 and =E2=80=98char=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3690:5: n= ote: candidate: =E2=80=98template bool std::operator<(const __cxx11::basic_string<_CharT, _Traits, _Allocator>&, c= onst __cxx11::basic_string<_CharT, _Traits, _Allocator>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3690:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3703:5: n= ote: candidate: =E2=80=98template bool std::operator<(const __cxx11::basic_string<_CharT, _Traits, _Allocator>&, c= onst _CharT*)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3703:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3715:5: n= ote: candidate: =E2=80=98template bool std::operator<(const _CharT*, const __cxx11::basic_string<_CharT, _Traits, _Allocator>&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3715:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: mismatched types =E2=80=98const _CharT*=E2=80=99 a= nd =E2=80=98std::basic_ostream=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/memory_resource.h:47, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 56: /home/lewis/gccdev/release/include/c++/13.0.0/tuple:1538:5: note: candidate: =E2=80=98template constexpr bool std::operator<(const tuple<_UTypes ...>&, const tuple<_UTypes ...>&)=E2=80= =99 /home/lewis/gccdev/release/include/c++/13.0.0/tuple:1538:5: note: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::tuple<_UTypes ...>=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/ios_base.h:46: /home/lewis/gccdev/release/include/c++/13.0.0/system_error:314:3: note: candidate: =E2=80=98bool std::operator<(const error_code&, const error_code= &)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/system_error:314:31: note: = no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2= =80=99 to =E2=80=98const std::error_code&=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/system_error:495:3: note: candidate: =E2=80=98bool std::operator<(const error_condition&, const error_condition&)=E2=80=99 /home/lewis/gccdev/release/include/c++/13.0.0/system_error:495:36: note: = no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2= =80=99 to =E2=80=98const std::error_condition&=E2=80=99 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D This is still half the length of the current output, because the source lin= es are not printed. The current output is: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D iowarn.cpp: In function =E2=80=98void f(std::ostream&, int)=E2=80=99: iowarn.cpp:3:12: error: no match for =E2=80=98operator<=E2=80=99 (operand t= ypes are =E2=80=98std::basic_ostream=E2=80=99 and =E2=80=98char=E2=80=99) 3 | o << a < '\n'; | ~~~~~~ ^ ~~~~ | | | | | char | std::basic_ostream iowarn.cpp:3:12: note: candidate: =E2=80=98operator<(int, int)=E2=80=99 (bu= ilt-in) 3 | o << a < '\n'; | ~~~~~~~^~~~~~ iowarn.cpp:3:12: note: no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2=80=99 to =E2=80=98int=E2=80=99 In file included from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 46, from /home/lewis/gccdev/release/include/c++/13.0.0/bits/locale_classes.h:40, from /home/lewis/gccdev/release/include/c++/13.0.0/bits/ios_base.h:41, from /home/lewis/gccdev/release/include/c++/13.0.0/ios:42, from /home/lewis/gccdev/release/include/c++/13.0.0/ostream= :38, from iowarn.cpp:1: /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:451:5: no= te: candidate: =E2=80=98template constexpr bool std::operator<= (const reverse_iterator<_Iterator>&, const reverse_iterator<_Iterator>&)=E2=80=99 451 | operator<(const reverse_iterator<_Iterator>& __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:451:5: no= te:=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::reverse_iterator<_Iterator>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:496:5: no= te: candidate: =E2=80=98template constexpr = bool std::operator<(const reverse_iterator<_Iterator>&, const reverse_iterator<_IteratorR>&)=E2=80=99 496 | operator<(const reverse_iterator<_IteratorL>& __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:496:5: no= te:=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::reverse_iterator<_Iterator>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1683:5: n= ote: candidate: =E2=80=98template constexpr = bool std::operator<(const move_iterator<_IteratorL>&, const move_iterator<_IteratorR>&)=E2=80=99 1683 | operator<(const move_iterator<_IteratorL>& __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1683:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::move_iterator<_IteratorL>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1748:5: n= ote: candidate: =E2=80=98template constexpr bool std::operator<= (const move_iterator<_IteratorL>&, const move_iterator<_IteratorL>&)=E2=80=99 1748 | operator<(const move_iterator<_Iterator>& __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_iterator.h:1748:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::move_iterator<_IteratorL>=E2=80=99 3 | o << a < '\n'; | ^~~~ In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_algobase.h:64, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 49: /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_pair.h:665:5: note: candidate: =E2=80=98template constexpr bool std::oper= ator<(const pair<_T1, _T2>&, const pair<_T1, _T2>&)=E2=80=99 665 | operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/stl_pair.h:665:5: note:= =20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::pair<_T1, _T2>=E2=80=99 3 | o << a < '\n'; | ^~~~ In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:47, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 52: /home/lewis/gccdev/release/include/c++/13.0.0/string_view:594:5: note: candidate: =E2=80=98template constexpr bool std::operator<(basic_string_view<_CharT, _Traits>, basic_string_view<_CharT, _Traits>)=E2=80=99 594 | operator< (basic_string_view<_CharT, _Traits> __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/string_view:594:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98std::basic_string_view<_CharT, _Traits>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/string_view:600:5: note: candidate: =E2=80=98template constexpr bool std::operator<(basic_string_view<_CharT, _Traits>, __type_identity_t >)=E2=80=99 600 | operator< (basic_string_view<_CharT, _Traits> __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/string_view:600:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98std::basic_string_view<_CharT, _Traits>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/string_view:607:5: note: candidate: =E2=80=98template constexpr bool std::operator<(__type_identity_t >, basic_string_view<_CharT, _Traits>)=E2=80=99 607 | operator< (__type_identity_t> __x, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/string_view:607:5: note:=20=20 template argument deduction/substitution failed: iowarn.cpp:3:14: note: mismatched types =E2=80=98std::basic_string_view<_= CharT, _Traits>=E2=80=99 and =E2=80=98char=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3690:5: n= ote: candidate: =E2=80=98template bool std::operator<(const __cxx11::basic_string<_CharT, _Traits, _Allocator>&, c= onst __cxx11::basic_string<_CharT, _Traits, _Allocator>&)=E2=80=99 3690 | operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3690:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3703:5: n= ote: candidate: =E2=80=98template bool std::operator<(const __cxx11::basic_string<_CharT, _Traits, _Allocator>&, c= onst _CharT*)=E2=80=99 3703 | operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3703:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>=E2=80=99 3 | o << a < '\n'; | ^~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3715:5: n= ote: candidate: =E2=80=98template bool std::operator<(const _CharT*, const __cxx11::basic_string<_CharT, _Traits, _Allocator>&)=E2=80=99 3715 | operator<(const _CharT* __lhs, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/bits/basic_string.h:3715:5: n= ote: template argument deduction/substitution failed: iowarn.cpp:3:14: note: mismatched types =E2=80=98const _CharT*=E2=80=99 a= nd =E2=80=98std::basic_ostream=E2=80=99 3 | o << a < '\n'; | ^~~~ In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/memory_resource.h:47, from /home/lewis/gccdev/release/include/c++/13.0.0/string:= 56: /home/lewis/gccdev/release/include/c++/13.0.0/tuple:1538:5: note: candidate: =E2=80=98template constexpr bool std::operator<(const tuple<_UTypes ...>&, const tuple<_UTypes ...>&)=E2=80= =99 1538 | operator<(const tuple<_TElements...>& __t, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/tuple:1538:5: note: template argument deduction/substitution failed: iowarn.cpp:3:14: note: =E2=80=98std::basic_ostream=E2=80=99 is not = derived from =E2=80=98const std::tuple<_UTypes ...>=E2=80=99 3 | o << a < '\n'; | ^~~~ In file included from /home/lewis/gccdev/release/include/c++/13.0.0/bits/ios_base.h:46: /home/lewis/gccdev/release/include/c++/13.0.0/system_error:314:3: note: candidate: =E2=80=98bool std::operator<(const error_code&, const error_code= &)=E2=80=99 314 | operator<(const error_code& __lhs, const error_code& __rhs) noexc= ept | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/system_error:314:31: note: = no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2= =80=99 to =E2=80=98const std::error_code&=E2=80=99 314 | operator<(const error_code& __lhs, const error_code& __rhs) noexc= ept | ~~~~~~~~~~~~~~~~~~^~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/system_error:495:3: note: candidate: =E2=80=98bool std::operator<(const error_condition&, const error_condition&)=E2=80=99 495 | operator<(const error_condition& __lhs, | ^~~~~~~~ /home/lewis/gccdev/release/include/c++/13.0.0/system_error:495:36: note: = no known conversion for argument 1 from =E2=80=98std::basic_ostream=E2= =80=99 to =E2=80=98const std::error_condition&=E2=80=99 495 | operator<(const error_condition& __lhs, | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~ =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Perhaps the default thresholds of 3 and 7 could be tuned better based on experience, but I hope maybe it's at least a useful framework to set up? If= so then the patch is ready to go and I could send it to gcc-patches. Thanks for taking a look! -Lewis=