https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102028
--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> --- This is the template which gets matched: /** * @brief Generic inserter for rvalue stream * @param __os An input stream. * @param __x A reference to the object being inserted. * @return __os * * This is just a forwarding function to allow insertion to * rvalue streams since they won't bind to the inserter functions * that take an lvalue reference. */ template<typename _Ostream, typename _Tp> inline __rvalue_stream_insertion_t<_Ostream, _Tp> operator<<(_Ostream&& __os, const _Tp& __x) { __os << __x; return std::move(__os); } That is the code is same as: std::stringstream &&a = std::stringstream{}; std::ostream &b = a; b<<A{}; foo(std::move(a)); The original code is able to compile on GCC, clang (with libc++) and MSVC.