1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "std_stream.h" 10 11 #include <__memory/construct_at.h> 12 #include <__ostream/basic_ostream.h> 13 #include <istream> 14 15 #define ABI_NAMESPACE_STR _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE) 16 17 _LIBCPP_BEGIN_NAMESPACE_STD 18 19 template <class StreamT, class BufferT> 20 union stream_data { 21 stream_data() {} 22 ~stream_data() {} 23 struct { 24 // The stream has to be the first element, since that's referenced by the stream declarations in <iostream> 25 StreamT stream; 26 BufferT buffer; 27 mbstate_t mb; 28 }; 29 30 void init(FILE* stdstream) { 31 mb = {}; 32 std::construct_at(&buffer, stdstream, &mb); 33 std::construct_at(&stream, &buffer); 34 } 35 }; 36 37 #define CHAR_MANGLING_char "D" 38 #define CHAR_MANGLING_wchar_t "_W" 39 #define CHAR_MANGLING(CharT) CHAR_MANGLING_##CharT 40 41 #ifdef _LIBCPP_ABI_MICROSOFT 42 # define STREAM(StreamT, BufferT, CharT, var) \ 43 stream_data<StreamT<CharT>, BufferT<CharT>> var __asm__( \ 44 "?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \ 45 "@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12@A") 46 #else 47 # define STREAM(StreamT, BufferT, CharT, var) stream_data<StreamT<CharT>, BufferT<CharT>> var 48 #endif 49 50 // These definitions and the declarations in <iostream> technically cause ODR violations, since they have different 51 // types (stream_data and {i,o}stream respectively). This means that <iostream> should never be included in this TU. 52 53 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, char, cin); 54 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cout); 55 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cerr); 56 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, clog); 57 #if _LIBCPP_HAS_WIDE_CHARACTERS 58 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, wchar_t, wcin); 59 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout); 60 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr); 61 _LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog); 62 #endif // _LIBCPP_HAS_WIDE_CHARACTERS 63 64 // Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority 65 // attribute with a value that's reserved for the implementation (we're the implementation). 66 #include "iostream_init.h" 67 68 // On Windows the TLS storage for locales needs to be initialized before we create 69 // the standard streams, otherwise it may not be alive during program termination 70 // when we flush the streams. 71 static void force_locale_initialization() { 72 #if defined(_LIBCPP_MSVCRT_LIKE) 73 static bool once = []() { 74 auto loc = __locale::__newlocale(_LIBCPP_ALL_MASK, "C", 0); 75 { 76 __locale::__locale_guard g(loc); // forces initialization of locale TLS 77 ((void)g); 78 } 79 __locale::__freelocale(loc); 80 return true; 81 }(); 82 ((void)once); 83 #endif 84 } 85 86 class DoIOSInit { 87 public: 88 DoIOSInit(); 89 ~DoIOSInit(); 90 }; 91 92 DoIOSInit::DoIOSInit() { 93 force_locale_initialization(); 94 95 cin.init(stdin); 96 cout.init(stdout); 97 cerr.init(stderr); 98 clog.init(stderr); 99 100 cin.stream.tie(&cout.stream); 101 std::unitbuf(cerr.stream); 102 cerr.stream.tie(&cout.stream); 103 104 #if _LIBCPP_HAS_WIDE_CHARACTERS 105 wcin.init(stdin); 106 wcout.init(stdout); 107 wcerr.init(stderr); 108 wclog.init(stderr); 109 110 wcin.stream.tie(&wcout.stream); 111 std::unitbuf(wcerr.stream); 112 wcerr.stream.tie(&wcout.stream); 113 #endif 114 } 115 116 DoIOSInit::~DoIOSInit() { 117 cout.stream.flush(); 118 clog.stream.flush(); 119 120 #if _LIBCPP_HAS_WIDE_CHARACTERS 121 wcout.stream.flush(); 122 wclog.stream.flush(); 123 #endif 124 } 125 126 ios_base::Init::Init() { 127 static DoIOSInit init_the_streams; // gets initialized once 128 } 129 130 ios_base::Init::~Init() {} 131 132 _LIBCPP_END_NAMESPACE_STD 133