The output of
template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, thread::id id);
is affected by the state of out. The wording states
[thread.thread.id]/2
The text representation for the character type charT of an object of type thread::id is an unspecified sequence of charT such that, for two objects of type thread::id x and y, if x == y is true, the thread::id objects have the same text representation, and if x != y is true, the thread::id objects have distinct text representations.
[thread.thread.id]/9
template<class charT, class traits> basic_ostream<charT, traits>& operator<< (basic_ostream<charT, traits>& out, thread::id id); Effects: Inserts the text representation for charT of id into out.
This wording changed in C++23 due to adding a formatter specialization for
thread::id. However the requirement was the same in older versions of C++.
This issue is that thread::id is an integral or pointer and affected by the
formatting manipulators for them. Thus the text representation can differ if
x == y which violates the requirements.
The fix has to hard-code some formatting style for the text
representation. It uses the Standard specified default values
Table 124: basic_ios::init() effects [tab:basic.ios.cons] flags()
flags() skipws | dec
Fixes PR: https://llvm.org/PR62073
Is there any reason why we need <ios> and not just <iosfwd>? It would be really nice to try to avoid including <ios> from here since that's kind of a heavy header (especially with backward compatibility transitive includes enabled).