master
  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
 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_##CharT
 40
 41#ifdef _LIBCPP_COMPILER_CLANG_BASED
 42#  define STRING_DATA_CONSTINIT constinit
 43#else
 44#  define STRING_DATA_CONSTINIT
 45#endif
 46
 47#ifdef _LIBCPP_ABI_MICROSOFT
 48#  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#else
 53#  define STREAM(StreamT, BufferT, CharT, var) STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var
 54#endif
 55
 56// These definitions and the declarations in <iostream> technically cause ODR violations, since they have different
 57// 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_CHARACTERS
 64_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_CHARACTERS
 69
 70// Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority
 71// 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 create
 75// the standard streams, otherwise it may not be alive during program termination
 76// 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 TLS
 83      ((void)g);
 84    }
 85    __locale::__freelocale(loc);
 86    return true;
 87  }();
 88  ((void)once);
 89#endif
 90}
 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_CHARACTERS
111  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#endif
120}
121
122DoIOSInit::~DoIOSInit() {
123  cout.stream.flush();
124  clog.stream.flush();
125
126#if _LIBCPP_HAS_WIDE_CHARACTERS
127  wcout.stream.flush();
128  wclog.stream.flush();
129#endif
130}
131
132ios_base::Init::Init() {
133  static DoIOSInit init_the_streams; // gets initialized once
134}
135
136ios_base::Init::~Init() {}
137
138_LIBCPP_END_NAMESPACE_STD