Skip to content

Commit 4aa858f

Browse files
committed
[libcxx] Fix ODR violation in iostream.
Note: This commit does not need a test, we already validate it via: * It compiles successfully after replacing `#include <istream>` with `#include <iostream>` in `iostream.cpp` * It passes existing tests after removing the ODR violation exception from the allowlist * There are already existing tests to validate that it runs correctly. Also tested with -ftrivial-auto-var-init and confirmed that it doesn't affect this (probably since it's a global variable)
1 parent 383e5f3 commit 4aa858f

File tree

7 files changed

+109
-56
lines changed

7 files changed

+109
-56
lines changed

libcxx/include/__ostream/basic_ostream.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
5757
}
5858
~basic_ostream() override;
5959

60+
// Required by iostream to create cin as uninitialized.
61+
_LIBCPP_HIDE_FROM_ABI explicit basic_ostream(__uninitialized_ios_tag __uninit)
62+
: basic_ios<_CharT, _Traits>(__uninit) {}
63+
6064
basic_ostream(const basic_ostream& __rhs) = delete;
6165
basic_ostream& operator=(const basic_ostream& __rhs) = delete;
6266

libcxx/include/ios

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
251251

252252
typedef ptrdiff_t streamsize;
253253

254+
struct _LIBCPP_HIDE_FROM_ABI __uninitialized_ios_tag {
255+
_LIBCPP_HIDE_FROM_ABI explicit __uninitialized_ios_tag() = default;
256+
};
257+
254258
class _LIBCPP_EXPORTED_FROM_ABI ios_base {
255259
public:
256260
class _LIBCPP_EXPORTED_FROM_ABI failure;
@@ -371,6 +375,9 @@ protected:
371375
// for the details.
372376
}
373377

378+
// Intentionally do not make this constexpr. Members cannot be uninitialized when using constexpr.
379+
_LIBCPP_HIDE_FROM_ABI ios_base(__uninitialized_ios_tag) {}
380+
374381
void init(void* __sb);
375382
_LIBCPP_HIDE_FROM_ABI void* rdbuf() const { return __rdbuf_; }
376383

@@ -619,6 +626,9 @@ protected:
619626
// purposefully does no initialization
620627
// since the destructor does nothing this does not have ios_base issues.
621628
}
629+
630+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR basic_ios(__uninitialized_ios_tag __uninit) : ios_base{__uninit} {}
631+
622632
_LIBCPP_HIDE_FROM_ABI void init(basic_streambuf<char_type, traits_type>* __sb);
623633

624634
_LIBCPP_HIDE_FROM_ABI void move(basic_ios& __rhs);

libcxx/include/istream

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ protected:
225225
}
226226

227227
public:
228+
// Required by iostream to create cin as uninitialized.
229+
_LIBCPP_HIDE_FROM_ABI explicit basic_istream(__uninitialized_ios_tag __uninit)
230+
: basic_ios<_CharT, _Traits>(__uninit) {}
231+
228232
basic_istream(const basic_istream& __rhs) = delete;
229233
basic_istream& operator=(const basic_istream& __rhs) = delete;
230234

libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@
12231223
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
12241224
{'is_defined': True, 'name': '_ZNSt6__ndk132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
12251225
{'is_defined': True, 'name': '_ZNSt6__ndk134__construct_barrier_algorithm_baseERi', 'type': 'FUNC'}
1226-
{'is_defined': True, 'name': '_ZNSt6__ndk13cinE', 'size': 148, 'type': 'OBJECT'}
1226+
{'is_defined': True, 'name': '_ZNSt6__ndk13cinE', 'size': 88, 'type': 'OBJECT'}
12271227
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD0Ev', 'type': 'FUNC'}
12281228
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD1Ev', 'type': 'FUNC'}
12291229
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD2Ev', 'type': 'FUNC'}
@@ -1291,9 +1291,9 @@
12911291
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__removeERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'}
12921292
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__renameERKNS1_4pathES4_PNS_10error_codeE', 'type': 'FUNC'}
12931293
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__statusERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'}
1294-
{'is_defined': True, 'name': '_ZNSt6__ndk14cerrE', 'size': 136, 'type': 'OBJECT'}
1295-
{'is_defined': True, 'name': '_ZNSt6__ndk14clogE', 'size': 136, 'type': 'OBJECT'}
1296-
{'is_defined': True, 'name': '_ZNSt6__ndk14coutE', 'size': 136, 'type': 'OBJECT'}
1294+
{'is_defined': True, 'name': '_ZNSt6__ndk14cerrE', 'size': 84, 'type': 'OBJECT'}
1295+
{'is_defined': True, 'name': '_ZNSt6__ndk14clogE', 'size': 84, 'type': 'OBJECT'}
1296+
{'is_defined': True, 'name': '_ZNSt6__ndk14coutE', 'size': 84, 'type': 'OBJECT'}
12971297
{'is_defined': True, 'name': '_ZNSt6__ndk14stodERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPj', 'type': 'FUNC'}
12981298
{'is_defined': True, 'name': '_ZNSt6__ndk14stodERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPj', 'type': 'FUNC'}
12991299
{'is_defined': True, 'name': '_ZNSt6__ndk14stofERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPj', 'type': 'FUNC'}
@@ -1302,7 +1302,7 @@
13021302
{'is_defined': True, 'name': '_ZNSt6__ndk14stoiERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPji', 'type': 'FUNC'}
13031303
{'is_defined': True, 'name': '_ZNSt6__ndk14stolERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPji', 'type': 'FUNC'}
13041304
{'is_defined': True, 'name': '_ZNSt6__ndk14stolERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPji', 'type': 'FUNC'}
1305-
{'is_defined': True, 'name': '_ZNSt6__ndk14wcinE', 'size': 148, 'type': 'OBJECT'}
1305+
{'is_defined': True, 'name': '_ZNSt6__ndk14wcinE', 'size': 88, 'type': 'OBJECT'}
13061306
{'is_defined': True, 'name': '_ZNSt6__ndk15alignEjjRPvRj', 'type': 'FUNC'}
13071307
{'is_defined': True, 'name': '_ZNSt6__ndk15ctypeIcE10table_sizeE', 'size': 4, 'type': 'OBJECT'}
13081308
{'is_defined': True, 'name': '_ZNSt6__ndk15ctypeIcE13classic_tableEv', 'type': 'FUNC'}
@@ -1327,9 +1327,9 @@
13271327
{'is_defined': True, 'name': '_ZNSt6__ndk15stollERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPji', 'type': 'FUNC'}
13281328
{'is_defined': True, 'name': '_ZNSt6__ndk15stoulERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPji', 'type': 'FUNC'}
13291329
{'is_defined': True, 'name': '_ZNSt6__ndk15stoulERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPji', 'type': 'FUNC'}
1330-
{'is_defined': True, 'name': '_ZNSt6__ndk15wcerrE', 'size': 136, 'type': 'OBJECT'}
1331-
{'is_defined': True, 'name': '_ZNSt6__ndk15wclogE', 'size': 136, 'type': 'OBJECT'}
1332-
{'is_defined': True, 'name': '_ZNSt6__ndk15wcoutE', 'size': 136, 'type': 'OBJECT'}
1330+
{'is_defined': True, 'name': '_ZNSt6__ndk15wcerrE', 'size': 84, 'type': 'OBJECT'}
1331+
{'is_defined': True, 'name': '_ZNSt6__ndk15wclogE', 'size': 84, 'type': 'OBJECT'}
1332+
{'is_defined': True, 'name': '_ZNSt6__ndk15wcoutE', 'size': 84, 'type': 'OBJECT'}
13331333
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
13341334
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
13351335
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEyPc', 'type': 'FUNC'}

libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@
12231223
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
12241224
{'is_defined': True, 'name': '_ZNSt6__ndk132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
12251225
{'is_defined': True, 'name': '_ZNSt6__ndk134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
1226-
{'is_defined': True, 'name': '_ZNSt6__ndk13cinE', 'size': 280, 'type': 'OBJECT'}
1226+
{'is_defined': True, 'name': '_ZNSt6__ndk13cinE', 'size': 168, 'type': 'OBJECT'}
12271227
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD0Ev', 'type': 'FUNC'}
12281228
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD1Ev', 'type': 'FUNC'}
12291229
{'is_defined': True, 'name': '_ZNSt6__ndk13pmr15memory_resourceD2Ev', 'type': 'FUNC'}
@@ -1291,9 +1291,9 @@
12911291
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__removeERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'}
12921292
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__renameERKNS1_4pathES4_PNS_10error_codeE', 'type': 'FUNC'}
12931293
{'is_defined': True, 'name': '_ZNSt6__ndk14__fs10filesystem8__statusERKNS1_4pathEPNS_10error_codeE', 'type': 'FUNC'}
1294-
{'is_defined': True, 'name': '_ZNSt6__ndk14cerrE', 'size': 264, 'type': 'OBJECT'}
1295-
{'is_defined': True, 'name': '_ZNSt6__ndk14clogE', 'size': 264, 'type': 'OBJECT'}
1296-
{'is_defined': True, 'name': '_ZNSt6__ndk14coutE', 'size': 264, 'type': 'OBJECT'}
1294+
{'is_defined': True, 'name': '_ZNSt6__ndk14cerrE', 'size': 160, 'type': 'OBJECT'}
1295+
{'is_defined': True, 'name': '_ZNSt6__ndk14clogE', 'size': 160, 'type': 'OBJECT'}
1296+
{'is_defined': True, 'name': '_ZNSt6__ndk14coutE', 'size': 160, 'type': 'OBJECT'}
12971297
{'is_defined': True, 'name': '_ZNSt6__ndk14stodERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPm', 'type': 'FUNC'}
12981298
{'is_defined': True, 'name': '_ZNSt6__ndk14stodERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPm', 'type': 'FUNC'}
12991299
{'is_defined': True, 'name': '_ZNSt6__ndk14stofERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPm', 'type': 'FUNC'}
@@ -1302,7 +1302,7 @@
13021302
{'is_defined': True, 'name': '_ZNSt6__ndk14stoiERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPmi', 'type': 'FUNC'}
13031303
{'is_defined': True, 'name': '_ZNSt6__ndk14stolERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPmi', 'type': 'FUNC'}
13041304
{'is_defined': True, 'name': '_ZNSt6__ndk14stolERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPmi', 'type': 'FUNC'}
1305-
{'is_defined': True, 'name': '_ZNSt6__ndk14wcinE', 'size': 280, 'type': 'OBJECT'}
1305+
{'is_defined': True, 'name': '_ZNSt6__ndk14wcinE', 'size': 168, 'type': 'OBJECT'}
13061306
{'is_defined': True, 'name': '_ZNSt6__ndk15alignEmmRPvRm', 'type': 'FUNC'}
13071307
{'is_defined': True, 'name': '_ZNSt6__ndk15ctypeIcE10table_sizeE', 'size': 8, 'type': 'OBJECT'}
13081308
{'is_defined': True, 'name': '_ZNSt6__ndk15ctypeIcE13classic_tableEv', 'type': 'FUNC'}
@@ -1327,9 +1327,9 @@
13271327
{'is_defined': True, 'name': '_ZNSt6__ndk15stollERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPmi', 'type': 'FUNC'}
13281328
{'is_defined': True, 'name': '_ZNSt6__ndk15stoulERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPmi', 'type': 'FUNC'}
13291329
{'is_defined': True, 'name': '_ZNSt6__ndk15stoulERKNS_12basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEEEPmi', 'type': 'FUNC'}
1330-
{'is_defined': True, 'name': '_ZNSt6__ndk15wcerrE', 'size': 264, 'type': 'OBJECT'}
1331-
{'is_defined': True, 'name': '_ZNSt6__ndk15wclogE', 'size': 264, 'type': 'OBJECT'}
1332-
{'is_defined': True, 'name': '_ZNSt6__ndk15wcoutE', 'size': 264, 'type': 'OBJECT'}
1330+
{'is_defined': True, 'name': '_ZNSt6__ndk15wcerrE', 'size': 160, 'type': 'OBJECT'}
1331+
{'is_defined': True, 'name': '_ZNSt6__ndk15wclogE', 'size': 160, 'type': 'OBJECT'}
1332+
{'is_defined': True, 'name': '_ZNSt6__ndk15wcoutE', 'size': 160, 'type': 'OBJECT'}
13331333
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
13341334
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
13351335
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}

libcxx/src/iostream.cpp

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,19 @@
99
#include "std_stream.h"
1010

1111
#include <__memory/construct_at.h>
12-
#include <__ostream/basic_ostream.h>
13-
#include <istream>
12+
#include <iostream>
1413

1514
#define ABI_NAMESPACE_STR _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE)
1615

1716
_LIBCPP_BEGIN_NAMESPACE_STD
1817
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
1918

20-
template <class StreamT, class BufferT>
19+
template <class BufferT, typename StreamT, StreamT& stream>
2120
union stream_data {
2221
constexpr stream_data() {}
2322
constexpr ~stream_data() {}
23+
// Make this a struct inside a union so it can be uninitialized.
2424
struct {
25-
// The stream has to be the first element, since that's referenced by the stream declarations in <iostream>
26-
StreamT stream;
2725
BufferT buffer;
2826
mbstate_t mb;
2927
};
@@ -51,31 +49,36 @@ union stream_data {
5149
"?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \
5250
"@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12@A")
5351
#else
54-
# define STREAM(StreamT, BufferT, CharT, var) STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var
55-
#endif
5652

57-
// These definitions and the declarations in <iostream> technically cause ODR violations, since they have different
58-
// types (stream_data and {i,o}stream respectively). This means that <iostream> should never be included in this TU.
53+
// To avoid ODR violations without breaking the ABI, we need to define it as a StreamT<CharT>.
54+
// However, since initialization order of statics is arbitrary, we could run DoIOSInit first and then
55+
// construct the stream for a second time, overwriting the data in it.
56+
// To avoid this, we call a constructor overload that specifically avoids initializing any members.
57+
# define STREAM(StreamT, BufferT, CharT, var) \
58+
StreamT<CharT> var{std::__uninitialized_ios_tag{}}; \
59+
stream_data<BufferT<CharT>, StreamT<CharT>, var> sd_##var;
60+
#endif
5961

60-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, char, cin);
61-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cout);
62-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cerr);
63-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, clog);
62+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, char, cin)
63+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cout)
64+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cerr)
65+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, clog)
6466
#if _LIBCPP_HAS_WIDE_CHARACTERS
65-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, wchar_t, wcin);
66-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout);
67-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr);
68-
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog);
67+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, wchar_t, wcin)
68+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout)
69+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr)
70+
_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog)
6971
#endif // _LIBCPP_HAS_WIDE_CHARACTERS
7072

7173
// Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority
7274
// attribute with a value that's reserved for the implementation (we're the implementation).
7375
#include "iostream_init.h"
7476

75-
// On Windows the TLS storage for locales needs to be initialized before we create
76-
// the standard streams, otherwise it may not be alive during program termination
77-
// when we flush the streams.
78-
static void force_locale_initialization() {
77+
// Clang-format indents this incorrectly, no clue why.
78+
// On Windows the TLS storage for locales needs to be initialized before we create
79+
// the standard streams, otherwise it may not be alive during program termination
80+
// when we flush the streams.
81+
static void force_locale_initialization() {
7982
#if defined(_LIBCPP_MSVCRT_LIKE)
8083
static bool once = []() {
8184
auto loc = __locale::__newlocale(_LIBCPP_ALL_MASK, "C", 0);
@@ -99,34 +102,34 @@ class DoIOSInit {
99102
DoIOSInit::DoIOSInit() {
100103
force_locale_initialization();
101104

102-
cin.init(stdin);
103-
cout.init(stdout);
104-
cerr.init(stderr);
105-
clog.init(stderr);
105+
sd_cin.init(stdin);
106+
sd_cout.init(stdout);
107+
sd_cerr.init(stderr);
108+
sd_clog.init(stderr);
106109

107-
cin.stream.tie(&cout.stream);
108-
std::unitbuf(cerr.stream);
109-
cerr.stream.tie(&cout.stream);
110+
cin.tie(&cout);
111+
std::unitbuf(cerr);
112+
cerr.tie(&cout);
110113

111114
#if _LIBCPP_HAS_WIDE_CHARACTERS
112-
wcin.init(stdin);
113-
wcout.init(stdout);
114-
wcerr.init(stderr);
115-
wclog.init(stderr);
116-
117-
wcin.stream.tie(&wcout.stream);
118-
std::unitbuf(wcerr.stream);
119-
wcerr.stream.tie(&wcout.stream);
115+
sd_wcin.init(stdin);
116+
sd_wcout.init(stdout);
117+
sd_wcerr.init(stderr);
118+
sd_wclog.init(stderr);
119+
120+
wcin.tie(&wcout);
121+
std::unitbuf(wcerr);
122+
wcerr.tie(&wcout);
120123
#endif
121124
}
122125

123126
DoIOSInit::~DoIOSInit() {
124-
cout.stream.flush();
125-
clog.stream.flush();
127+
cout.flush();
128+
clog.flush();
126129

127130
#if _LIBCPP_HAS_WIDE_CHARACTERS
128-
wcout.stream.flush();
129-
wclog.stream.flush();
131+
wcout.flush();
132+
wclog.flush();
130133
#endif
131134
}
132135

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
// REQUIRES: asserts
10+
11+
#include <cassert>
12+
#include <cstddef>
13+
#include <iostream>
14+
#include <memory>
15+
16+
template <typename T>
17+
void run_test(std::byte value) {
18+
std::array<std::byte, sizeof(T)> initial;
19+
initial.fill(value);
20+
21+
auto constructed = initial;
22+
std::construct_at(reinterpret_cast<T*>(constructed.data()), std::__uninitialized_ios_tag());
23+
24+
assert(constructed == initial);
25+
}
26+
27+
int main(int, char**) {
28+
run_test<std::basic_istream<char>>(std::byte(0));
29+
run_test<std::basic_istream<char>>(std::byte(255));
30+
run_test<std::basic_ostream<char>>(std::byte(0));
31+
run_test<std::basic_ostream<char>>(std::byte(255));
32+
}

0 commit comments

Comments
 (0)