139 lines · cpp
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-exception6//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_STD18 19template <class StreamT, class BufferT>20union stream_data {21 constexpr stream_data() {}22 constexpr ~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_##CharT40 41#ifdef _LIBCPP_COMPILER_CLANG_BASED42# define STRING_DATA_CONSTINIT constinit43#else44# define STRING_DATA_CONSTINIT45#endif46 47#ifdef _LIBCPP_ABI_MICROSOFT48# define STREAM(StreamT, BufferT, CharT, var) \49 STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var __asm__( \50 "?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \51 "@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12@A")52#else53# define STREAM(StreamT, BufferT, CharT, var) STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var54#endif55 56// These definitions and the declarations in <iostream> technically cause ODR violations, since they have different57// types (stream_data and {i,o}stream respectively). This means that <iostream> should never be included in this TU.58 59_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, char, cin);60_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cout);61_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cerr);62_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, clog);63#if _LIBCPP_HAS_WIDE_CHARACTERS64_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, wchar_t, wcin);65_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout);66_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr);67_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog);68#endif // _LIBCPP_HAS_WIDE_CHARACTERS69 70// Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority71// attribute with a value that's reserved for the implementation (we're the implementation).72#include "iostream_init.h"73 74// On Windows the TLS storage for locales needs to be initialized before we create75// the standard streams, otherwise it may not be alive during program termination76// when we flush the streams.77static void force_locale_initialization() {78#if defined(_LIBCPP_MSVCRT_LIKE)79 static bool once = []() {80 auto loc = __locale::__newlocale(_LIBCPP_ALL_MASK, "C", 0);81 {82 __locale::__locale_guard g(loc); // forces initialization of locale TLS83 ((void)g);84 }85 __locale::__freelocale(loc);86 return true;87 }();88 ((void)once);89#endif90}91 92class DoIOSInit {93public:94 DoIOSInit();95 ~DoIOSInit();96};97 98DoIOSInit::DoIOSInit() {99 force_locale_initialization();100 101 cin.init(stdin);102 cout.init(stdout);103 cerr.init(stderr);104 clog.init(stderr);105 106 cin.stream.tie(&cout.stream);107 std::unitbuf(cerr.stream);108 cerr.stream.tie(&cout.stream);109 110#if _LIBCPP_HAS_WIDE_CHARACTERS111 wcin.init(stdin);112 wcout.init(stdout);113 wcerr.init(stderr);114 wclog.init(stderr);115 116 wcin.stream.tie(&wcout.stream);117 std::unitbuf(wcerr.stream);118 wcerr.stream.tie(&wcout.stream);119#endif120}121 122DoIOSInit::~DoIOSInit() {123 cout.stream.flush();124 clog.stream.flush();125 126#if _LIBCPP_HAS_WIDE_CHARACTERS127 wcout.stream.flush();128 wclog.stream.flush();129#endif130}131 132ios_base::Init::Init() {133 static DoIOSInit init_the_streams; // gets initialized once134}135 136ios_base::Init::~Init() {}137 138_LIBCPP_END_NAMESPACE_STD139