https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99692
--- Comment #11 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Jonathan Wakely from comment #10) > template<typename _Ostream, typename _Tp> > struct __is_insertable<_Ostream, _Tp, > void_t<decltype(declval<_Ostream&>() > << declval<const _Tp&>())>> The problem is that this check produces a hard error (rather than substitution failure) for declval<std::ostream&>() << declval<const N::A&>(). The relevant operator is not found by ADL, because it's not in the associated namespaces of std::ostream or N::A (which is IMHO a design error in the code, but nevermind). So the void_t expression should get a substitution error. I think the problem is that PR 51577 causes GCC to look in the global scope and so incorrectly find the declaration of: std::ostream& operator<<(std::ostream& s, const N::A&) which means that the __is_insertable check ... goes wrong somehow? I think it makes the void_t expression ambiguous because of the global operator<< overload which is not meant to be found. The reduced example above can be reduced further: namespace std { struct ostream { }; template<typename T> T&& declval(); template<typename...> using void_t = void; struct false_type { static constexpr bool value = false; }; struct true_type { static constexpr bool value = true; }; template<typename _Ostream, typename _Tp, typename = void> struct __is_insertable : false_type {}; template<typename _Ostream, typename _Tp> struct __is_insertable<_Ostream, _Tp, void_t<decltype(declval<_Ostream&>() << declval<const _Tp&>())>> : true_type {}; } struct CustomStream : std::ostream {}; namespace N { class A{}; } std::ostream& operator<<(std::ostream& s, const N::A&) { return s; } int main() { static_assert( ! std::__is_insertable<std::ostream, N::A>::value, "" ); } This avoids the hard error in __is_insertable, but GCC fails the static_assert (where as Clang passes it) which is PR 51577.