[libcxx-commits] [libcxx] [libc++] Optimize standard streams with sync_with_stdio(false) (PR #209161)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 21 12:55:48 PDT 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/209161
>From 059ec6cec9cb06a0be51d521c1945870a3ad2b0d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 13 Jul 2026 14:28:02 +0200
Subject: [PATCH 1/2] [libc++] Optimize standard streams with
sync_with_stdio(false)
Fixes #21566
---
libcxx/include/fstream | 15 +--
libcxx/lib/abi/CHANGELOG.TXT | 17 +++
...bcxxabi.v1.stable.exceptions.nonew.abilist | 5 +-
...bcxxabi.v1.stable.exceptions.nonew.abilist | 3 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 3 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 5 +-
...bcxxabi.v1.stable.exceptions.nonew.abilist | 3 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 3 +
...xxabi.v1.stable.noexceptions.nonew.abilist | 5 +-
libcxx/src/ios.cpp | 7 --
libcxx/src/iostream.cpp | 102 ++++++++++++++----
.../cin.sync_with_stdio.sh.cpp | 37 +++++++
.../clog.sync_with_stdio.sh.cpp | 29 +++++
.../cout.sync_with_stdio.sh.cpp | 27 +++++
.../wcin.sync_with_stdio.sh.cpp | 44 ++++++++
.../wclog.sync_with_stdio.sh.cpp | 36 +++++++
.../wcout.sync_with_stdio.sh.cpp | 34 ++++++
17 files changed, 340 insertions(+), 35 deletions(-)
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/clog.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wclog.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcout.sync_with_stdio.sh.cpp
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 7b84bf6609086..4b276251aa917 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -391,10 +391,10 @@ private:
_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
- // There are multiple (__)open function, they use different C-API open
- // function. After that call these functions behave the same. This function
- // does that part and determines the final return value.
- _LIBCPP_HIDE_FROM_ABI basic_filebuf* __do_open(FILE* __file, ios_base::openmode __mode) {
+public:
+ // Update the buffer so that __file is considered to be the underlying file and is opened as __mode. This is used in
+ // the open family of functions as well as various iostreams in sync_with_stdio(false) mode.
+ _LIBCPP_HIDE_FROM_ABI basic_filebuf* __adopt_file(FILE* __file, ios_base::openmode __mode) {
__file_ = __file;
if (!__file_)
return nullptr;
@@ -417,6 +417,7 @@ private:
return this;
}
+private:
// If the file is already open, switch to unbuffered mode. Otherwise, record
// the request to use unbuffered mode so that we use that mode when we
// eventually open the file.
@@ -742,7 +743,7 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char*
if (!__mdstr)
return nullptr;
- return __do_open(std::fopen(__s, __mdstr), __mode);
+ return __adopt_file(std::fopen(__s, __mdstr), __mode);
}
template <class _CharT, class _Traits>
@@ -753,7 +754,7 @@ inline basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::__open(in
if (!__mdstr)
return nullptr;
- return __do_open(fdopen(__fd, __mdstr), __mode);
+ return __adopt_file(fdopen(__fd, __mdstr), __mode);
}
# if _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -767,7 +768,7 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const wchar
if (!__mdstr)
return nullptr;
- return __do_open(_wfopen(__s, __mdstr), __mode);
+ return __adopt_file(_wfopen(__s, __mdstr), __mode);
}
# endif
diff --git a/libcxx/lib/abi/CHANGELOG.TXT b/libcxx/lib/abi/CHANGELOG.TXT
index b09f297eb65ba..567c23717ed60 100644
--- a/libcxx/lib/abi/CHANGELOG.TXT
+++ b/libcxx/lib/abi/CHANGELOG.TXT
@@ -12,6 +12,23 @@ To generate a summary, re-generate the new ABI list using the
New entries should be added directly below the "Version" header.
+------------
+Version 24.0
+------------
+
+* [libc++] Optimize standard streams with sync_with_stdio(false)
+
+ This updates the standard streams so that the buffers are replaced with `basic_filebuf`s.
+
+ Fixes #21566
+
+
+ All platforms
+ -------------
+ Symbol added: _ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE
+ Symbol added: _ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE
+ Symbol added: _ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE
+
------------
Version 23.0
------------
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 414a239757e1c..09999516face2 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -10,8 +10,8 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt20bad_array_new_length4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110error_code7messageEv', 'type': 'FUNC'}
@@ -1672,6 +1672,7 @@
{'is_defined': True, 'name': '_ZTINSt6__ndk112strstreambufE', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk112system_errorE', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 12, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 24, 'type': 'OBJECT'}
@@ -1908,6 +1909,7 @@
{'is_defined': True, 'name': '_ZTSNSt6__ndk112strstreambufE', 'size': 26, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk112system_errorE', 'size': 26, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
@@ -2143,6 +2145,7 @@
{'is_defined': True, 'name': '_ZTVNSt6__ndk112strstreambufE', 'size': 64, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk112system_errorE', 'size': 20, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 64, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 64, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 590c0de8ce20f..d53eeb7532009 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1816,6 +1816,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__111__money_putIwEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
@@ -1889,6 +1890,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__111__money_putIwEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
@@ -1963,6 +1965,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__110moneypunctIwLb0EEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__110moneypunctIwLb1EEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index f4f4ab99ad866..384904f79d20e 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1816,6 +1816,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__111__money_putIwEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__112codecvt_baseE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTINSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
@@ -1889,6 +1890,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__111__money_putIwEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__112codecvt_baseE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTSNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
@@ -1963,6 +1965,7 @@
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__110moneypunctIwLb0EEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__110moneypunctIwLb1EEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZTVNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index e1b1e110318fa..8f26fdb0462cb 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -10,8 +10,8 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt20bad_array_new_length4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110error_code7messageEv', 'type': 'FUNC'}
@@ -1672,6 +1672,7 @@
{'is_defined': True, 'name': '_ZTINSt6__ndk112strstreambufE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk112system_errorE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
@@ -1905,6 +1906,7 @@
{'is_defined': True, 'name': '_ZTSNSt6__ndk112strstreambufE', 'size': 26, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk112system_errorE', 'size': 26, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 50, 'type': 'OBJECT'}
@@ -2137,6 +2139,7 @@
{'is_defined': True, 'name': '_ZTVNSt6__ndk112strstreambufE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk112system_errorE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 128, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt6__ndk113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 11cc8f180e824..0a2858da94a67 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1644,6 +1644,7 @@
{'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
@@ -1778,6 +1779,7 @@
{'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
@@ -1916,6 +1918,7 @@
{'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 128, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index a28229a9d6e97..903457e983046 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1643,6 +1643,7 @@
{'is_defined': True, 'name': '_ZTINSt3__112strstreambufE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__112system_errorE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTINSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 40, 'type': 'OBJECT'}
@@ -1777,6 +1778,7 @@
{'is_defined': True, 'name': '_ZTSNSt3__112strstreambufE', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__112system_errorE', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 47, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 47, 'type': 'OBJECT'}
@@ -1915,6 +1917,7 @@
{'is_defined': True, 'name': '_ZTVNSt3__112strstreambufE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__112system_errorE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE', 'size': 128, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 128, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_istreamIwNS_11char_traitsIwEEEE', 'size': 80, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVNSt3__113basic_ostreamIcNS_11char_traitsIcEEEE', 'size': 80, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 2b69d6dc89138..c24cdf845b489 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -2002,4 +2002,7 @@
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
\ No newline at end of file
+{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
+{'name': '_ZTINSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 24, 'type': 'OBJECT', 'is_defined': True}
+{'name': '_ZTSNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 47, 'type': 'OBJECT', 'is_defined': True}
+{'name': '_ZTVNSt3__113basic_filebufIwNS_11char_traitsIwEEEE', 'size': 128, 'type': 'OBJECT', 'is_defined': True}
\ No newline at end of file
diff --git a/libcxx/src/ios.cpp b/libcxx/src/ios.cpp
index 2e049098740dc..0b728db5b76f9 100644
--- a/libcxx/src/ios.cpp
+++ b/libcxx/src/ios.cpp
@@ -366,13 +366,6 @@ void ios_base::__set_failbit_and_consider_rethrow() {
#endif // _LIBCPP_HAS_EXCEPTIONS
}
-bool ios_base::sync_with_stdio(bool sync) {
- static bool previous_state = true;
- bool r = previous_state;
- previous_state = sync;
- return r;
-}
-
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/src/iostream.cpp b/libcxx/src/iostream.cpp
index 0393982361456..551eb25f8fe4a 100644
--- a/libcxx/src/iostream.cpp
+++ b/libcxx/src/iostream.cpp
@@ -10,6 +10,7 @@
#include <__memory/construct_at.h>
#include <__ostream/basic_ostream.h>
+#include <fstream>
#include <istream>
#define ABI_NAMESPACE_STR _LIBCPP_TOSTRING(_LIBCPP_ABI_NAMESPACE)
@@ -34,21 +35,44 @@ union stream {
StreamT value;
};
-template <class StreamT, class BufferT>
+template <class StreamT, class SyncBufT, class UnsyncBufT>
union stream_data {
constexpr stream_data() {}
constexpr ~stream_data() {}
struct {
- BufferT buffer;
+ union {
+ SyncBufT sync_buffer;
+ UnsyncBufT unsync_buffer;
+ };
mbstate_t mb;
};
};
-template <class StreamT, class BufferT>
-void init_stream(FILE* stdstream, stream<StreamT>& stream, stream_data<StreamT, BufferT>& data) {
+template <class StreamT, class SyncBufT, class UnsyncBufT>
+void init_stream(FILE* stdstream, stream<StreamT>& stream, stream_data<StreamT, SyncBufT, UnsyncBufT>& data) {
data.mb = {};
- std::construct_at(&data.buffer, stdstream, &data.mb);
- std::construct_at(&stream.value, &data.buffer);
+ std::construct_at(&data.sync_buffer, stdstream, &data.mb);
+ std::construct_at(&stream.value, &data.sync_buffer);
+}
+
+template <class StreamT, class SyncBufT, class UnsyncBufT>
+void switch_to_sync_stream(FILE* stdstream, stream<StreamT>& stream, stream_data<StreamT, SyncBufT, UnsyncBufT>& data) {
+ data.unsync_buffer.__adopt_file(nullptr, {}); // reset the file, so that basic_filebuf doesn't close standard streams
+ std::destroy_at(&data.unsync_buffer);
+ data.mb = {};
+ std::construct_at(&data.sync_buffer, stdstream, &data.mb);
+ stream.value.rdbuf(&data.sync_buffer);
+}
+
+template <class StreamT, class SyncBufT, class UnsyncBufT>
+void switch_to_unsync_stream(FILE* stdstream,
+ stream<StreamT>& stream,
+ stream_data<StreamT, SyncBufT, UnsyncBufT>& data,
+ ios_base::openmode mode) {
+ std::destroy_at(&data.sync_buffer);
+ std::construct_at(&data.unsync_buffer);
+ data.unsync_buffer.__adopt_file(stdstream, mode);
+ stream.value.rdbuf(&data.unsync_buffer);
}
#define CHAR_MANGLING_char "D"
@@ -62,29 +86,39 @@ void init_stream(FILE* stdstream, stream<StreamT>& stream, stream_data<StreamT,
#endif
#ifdef _LIBCPP_ABI_MICROSOFT
-# define STREAM(StreamT, BufferT, CharT, var) \
- STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var##_data; \
+# define STREAM(StreamT, SyncBufT, UnsyncBufT, CharT, var) \
+ STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, SyncBufT<CharT>, UnsyncBufT<CharT>> var##_data; \
_LIBCPP_EXPORTED_FROM_ABI STRING_DATA_CONSTINIT stream<StreamT<CharT>> var __asm__( \
"?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \
"@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12 at A")
#else
-# define STREAM(StreamT, BufferT, CharT, var) \
- STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var##_data; \
+# define STREAM(StreamT, SyncBufT, UnsyncBufT, CharT, var) \
+ STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, SyncBufT<CharT>, UnsyncBufT<CharT>> var##_data; \
_LIBCPP_EXPORTED_FROM_ABI STRING_DATA_CONSTINIT stream<StreamT<CharT>> var
#endif
// These definitions and the declarations in <iostream> technically cause ODR violations, since they have different
// types (stream_data and {i,o}stream respectively). This means that <iostream> should never be included in this TU.
-STREAM(basic_istream, __stdinbuf, char, cin);
-STREAM(basic_ostream, __stdoutbuf, char, cout);
-STREAM(basic_ostream, __stdoutbuf, char, cerr);
-STREAM(basic_ostream, __stdoutbuf, char, clog);
+#if _LIBCPP_HAS_FILESYSTEM
+template <class CharT>
+using unsync_buffer = basic_filebuf<CharT>;
+#else
+// If we don't have access to files we can't treat the standard streams as files either - just save a dummy object in
+// that case.
+template <class>
+using unsync_buffer = char;
+#endif
+
+STREAM(basic_istream, __stdinbuf, unsync_buffer, char, cin);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, char, cout);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, char, cerr);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, char, clog);
#if _LIBCPP_HAS_WIDE_CHARACTERS
-STREAM(basic_istream, __stdinbuf, wchar_t, wcin);
-STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout);
-STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr);
-STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog);
+STREAM(basic_istream, __stdinbuf, unsync_buffer, wchar_t, wcin);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, wchar_t, wcout);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, wchar_t, wcerr);
+STREAM(basic_ostream, __stdoutbuf, unsync_buffer, wchar_t, wclog);
#endif // _LIBCPP_HAS_WIDE_CHARACTERS
// Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority
@@ -155,5 +189,37 @@ ios_base::Init::Init() {
ios_base::Init::~Init() {}
+bool ios_base::sync_with_stdio(bool sync) {
+ static bool previous_state = true;
+ bool r = previous_state;
+
+#if _LIBCPP_HAS_FILESYSTEM
+ if (sync != previous_state) {
+ if (sync) {
+ switch_to_sync_stream(stdin, cin, cin_data);
+ switch_to_sync_stream(stdout, cout, cout_data);
+ switch_to_sync_stream(stderr, clog, clog_data);
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+ switch_to_sync_stream(stdin, wcin, wcin_data);
+ switch_to_sync_stream(stdout, wcout, wcout_data);
+ switch_to_sync_stream(stderr, wclog, wclog_data);
+# endif
+ } else {
+ switch_to_unsync_stream(stdin, cin, cin_data, ios::in);
+ switch_to_unsync_stream(stdout, cout, cout_data, ios::out);
+ switch_to_unsync_stream(stderr, clog, clog_data, ios::out);
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+ switch_to_unsync_stream(stdin, wcin, wcin_data, ios::in);
+ switch_to_unsync_stream(stdout, wcout, wcout_data, ios::out);
+ switch_to_unsync_stream(stderr, wclog, wclog_data, ios::out);
+# endif
+ }
+ }
+#endif // _LIBCPP_HAS_FILESYSTEM
+
+ previous_state = sync;
+ return r;
+}
+
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..052356449c5ab
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.sync_with_stdio.sh.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// QEMU does not detect EOF, when reading from stdin
+// "echo -n" suppresses any characters after the output and so the test hangs.
+// https://gitlab.com/qemu-project/qemu/-/issues/1963
+// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
+
+// This test hangs on Android devices that lack shell_v2, which was added in
+// Android N (API 24).
+// UNSUPPORTED: LIBCXX-ANDROID-FIXME && android-device-api={{2[1-3]}}
+
+// <iostream>
+
+// istream cin;
+
+// RUN: %{build}
+// RUN: echo -n 1234 > %t.input
+// RUN: %{exec} %t.exe < %t.input
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ int i;
+ std::cin >> i;
+ assert(i == 1234);
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/clog.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/clog.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..ab30dee5f695d
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/clog.sync_with_stdio.sh.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: LIBCXX-PICOLIBC-FIXME
+
+// <iostream>
+
+// ostream clog;
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2> %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ std::clog << "1234";
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..3a94964f09223
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.sync_with_stdio.sh.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iostream>
+
+// ostream cout;
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe > %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ std::cout << "1234";
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..db6c5ba0e8660
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.sync_with_stdio.sh.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// QEMU does not detect EOF, when reading from stdin
+// "echo -n" suppresses any characters after the output and so the test hangs.
+// https://gitlab.com/qemu-project/qemu/-/issues/1963
+// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
+
+// This test hangs on Android devices that lack shell_v2, which was added in
+// Android N (API 24).
+// UNSUPPORTED: LIBCXX-ANDROID-FIXME && android-device-api={{2[1-3]}}
+
+// UNSUPPORTED: no-wide-characters
+
+// <iostream>
+
+// istream wcin;
+
+// Test that we output correctly after setting sync_with_stdio(false).
+// This must be its own test because sync_with_stdio() must be called
+// before any other IO operation for the test to be portable.
+
+// RUN: %{build}
+// RUN: echo -n 1234 > %t.input
+// RUN: %{exec} %t.exe < %t.input
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ // flip-flop the setting to check that construction both ways works as expected
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ int i;
+ std::wcin >> i;
+ assert(i == 1234);
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wclog.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wclog.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..c0a0f299451fb
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wclog.sync_with_stdio.sh.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: LIBCXX-PICOLIBC-FIXME
+
+// UNSUPPORTED: no-wide-characters
+
+// <iostream>
+
+// ostream wclog;
+
+// Test that we output correctly after setting sync_with_stdio(false).
+// This must be its own test because sync_with_stdio() must be called
+// before any other IO operation for the test to be portable.
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2> %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ // flip-flop the setting to check that construction both ways works as expected
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ std::wclog << L"1234";
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcout.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcout.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..a2cdc070620b1
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcout.sync_with_stdio.sh.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-wide-characters
+
+// <iostream>
+
+// ostream wcout;
+
+// Test that we output correctly after setting sync_with_stdio(false).
+// This must be its own test because sync_with_stdio() must be called
+// before any other IO operation for the test to be portable.
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe > %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ // flip-flop the setting to check that construction both ways works as expected
+ assert(std::ios::sync_with_stdio(false));
+ assert(!std::ios::sync_with_stdio(true));
+ assert(std::ios::sync_with_stdio(false));
+ std::wcout << L"1234";
+ return 0;
+}
>From ebf915fac915353eca504da6839c2a78b8a9fbfb Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 21 Jul 2026 14:16:12 -0400
Subject: [PATCH 2/2] Add more test coverage for sync_with_stdio stream
switching
Extend the tests for the sync_with_stdio(false) optimization:
- ensure that the optimization is actually in effect by checking the
type of the underlying buffer.
- verify that toggling the synchronization mode preserves per-stream state.
- cerr/wcerr are deliberately not switched to a filebuf, so check they keep
producing correct output.
- check that C stdio and cout output interleave in order in synchronized mode.
- read a large input to force the buffered filebuf to refill (underflow) several
times in unsynchronized mode, and check EOF detection.
---
.../sync_with_stdio.buffer_type.pass.cpp | 70 +++++++++++
.../cerr.sync_with_stdio.sh.cpp | 38 ++++++
.../narrow.stream.objects/cin.readmany.sh.cpp | 56 +++++++++
.../cout.interleave_with_stdio.sh.cpp | 34 ++++++
.../sync_with_stdio.state.pass.cpp | 109 ++++++++++++++++++
.../wcerr.sync_with_stdio.sh.cpp | 35 ++++++
.../wide.stream.objects/wcin.readmany.sh.cpp | 58 ++++++++++
.../sync_with_stdio.pass.cpp | 2 +
8 files changed, 402 insertions(+)
create mode 100644 libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cerr.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.readmany.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.interleave_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/sync_with_stdio.state.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcerr.sync_with_stdio.sh.cpp
create mode 100644 libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.readmany.sh.cpp
diff --git a/libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp b/libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp
new file mode 100644
index 0000000000000..789ef630a2a2e
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iostream>
+
+// static bool ios_base::sync_with_stdio(bool sync = true);
+
+// This is a libc++ implementation detail: when sync_with_stdio(false) is used,
+// libc++ swaps the buffers of cin/cout/clog (and the wide equivalents) for a
+// basic_filebuf to avoid going through the C stdio layer. This test ensures
+// that this optimization is applied by inspecting the type of the underlying
+// buffer.
+
+// The optimization is only applied when we have a filesystem, since fstream
+// is not present otherwise. Also, the test itself requires RTTI.
+// UNSUPPORTED: no-filesystem, no-rtti
+
+#include <cassert>
+#include <fstream>
+#include <iostream>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ // By default the streams are synchronized, so they are not backed by a filebuf.
+ assert(!dynamic_cast<std::filebuf*>(std::cin.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::cout.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::cerr.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::clog.rdbuf()));
+#if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcin.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcout.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcerr.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wclog.rdbuf()));
+#endif
+
+ // Turning synchronization off switches cin/cout/clog to a filebuf, but leaves
+ // cerr untouched (it stays synchronized so it keeps flushing eagerly).
+ std::ios_base::sync_with_stdio(false);
+ assert(dynamic_cast<std::filebuf*>(std::cin.rdbuf()));
+ assert(dynamic_cast<std::filebuf*>(std::cout.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::cerr.rdbuf()));
+ assert(dynamic_cast<std::filebuf*>(std::clog.rdbuf()));
+#if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
+ assert(dynamic_cast<std::wfilebuf*>(std::wcin.rdbuf()));
+ assert(dynamic_cast<std::wfilebuf*>(std::wcout.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcerr.rdbuf()));
+ assert(dynamic_cast<std::wfilebuf*>(std::wclog.rdbuf()));
+#endif
+
+ // Turning it back on restores the original buffers.
+ std::ios_base::sync_with_stdio(true);
+ assert(!dynamic_cast<std::filebuf*>(std::cin.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::cout.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::cerr.rdbuf()));
+ assert(!dynamic_cast<std::filebuf*>(std::clog.rdbuf()));
+#if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcin.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcout.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wcerr.rdbuf()));
+ assert(!dynamic_cast<std::wfilebuf*>(std::wclog.rdbuf()));
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cerr.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cerr.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..9f40e1ae04e67
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cerr.sync_with_stdio.sh.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: LIBCXX-PICOLIBC-FIXME
+
+// <iostream>
+
+// ostream cerr;
+
+// Unlike cin/cout/clog, std::cerr is still unbuffered even when sync_with_stdio(false)
+// is called. This test ensures that it keeps producing correctly-ordered output when
+// interleaved with the C stdio functions even after sync_with_stdio(false).
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2> %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <cstdio>
+#include <iostream>
+
+int main(int, char**) {
+ assert(std::ios_base::sync_with_stdio(false));
+
+ // interleave output with C stdio functions
+ std::fputs("1", stderr);
+ std::cerr << "2";
+ std::fprintf(stderr, "%d", 3);
+ std::cerr << 4;
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.readmany.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.readmany.sh.cpp
new file mode 100644
index 0000000000000..08f417b9ba451
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cin.readmany.sh.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// QEMU does not detect EOF, when reading from stdin
+// "echo -n" suppresses any characters after the output and so the test hangs.
+// https://gitlab.com/qemu-project/qemu/-/issues/1963
+// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
+
+// This test hangs on Android devices that lack shell_v2, which was added in
+// Android N (API 24).
+// UNSUPPORTED: LIBCXX-ANDROID-FIXME && android-device-api={{2[1-3]}}
+
+// <iostream>
+
+// istream cin;
+
+// Read an input that is much larger than any reasonable internal buffer so that the
+// buffer has to be refilled (underflow) several times, and check that every value
+// is read correctly and that EOF is detected at the end.
+
+// RUN: seq 1 5000 > %t.input
+
+// RUN: %{build} -DSYNC_WITH_STDIO_FALSE
+// RUN: %{exec} %t.exe < %t.input
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe < %t.input
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+#ifdef SYNC_WITH_STDIO_FALSE
+ assert(std::ios_base::sync_with_stdio(false));
+#endif
+
+ long sum = 0;
+ int count = 0;
+ int value = 0;
+ while (std::cin >> value) {
+ sum += value;
+ ++count;
+ }
+
+ assert(count == 5000);
+ assert(sum == 5000L * 5001L / 2L); // sum of 1..5000
+ assert(std::cin.eof());
+ assert(!std::cin.good());
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.interleave_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.interleave_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..8497801f1778c
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/narrow.stream.objects/cout.interleave_with_stdio.sh.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iostream>
+
+// ostream cout;
+
+// In synchronized mode, output written through std::cout and through the C stdio
+// functions must appear in the order in which it was written.
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe > %t.actual
+// RUN: echo -n 123456 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <cstdio>
+#include <iostream>
+
+int main(int, char**) {
+ std::fputs("1", stdout);
+ std::cout << "2";
+ std::fprintf(stdout, "%d", 3);
+ std::cout << 4;
+ std::fputs("5", stdout);
+ std::cout << 6;
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/sync_with_stdio.state.pass.cpp b/libcxx/test/std/input.output/iostream.objects/sync_with_stdio.state.pass.cpp
new file mode 100644
index 0000000000000..e6f9ef3002396
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/sync_with_stdio.state.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iostream>
+
+// Changing the synchronization mode with std::ios_base::sync_with_stdio must
+// preserve the per-stream state of the standard stream objects.
+
+#include <cassert>
+#include <iostream>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ int dummy = 0;
+ const int index = std::ios_base::xalloc();
+
+ std::cin.iword(index) = 11;
+ std::cout.iword(index) = 22;
+ std::cerr.iword(index) = 33;
+ std::clog.iword(index) = 44;
+ std::cout.pword(index) = &dummy;
+
+ std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
+ std::cout.precision(7);
+ std::cout.fill('*');
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ std::wcin.iword(index) = 11;
+ std::wcout.iword(index) = 22;
+ std::wcerr.iword(index) = 33;
+ std::wclog.iword(index) = 44;
+ std::wcout.pword(index) = &dummy;
+
+ std::wcout.setf(std::ios_base::hex, std::ios_base::basefield);
+ std::wcout.precision(7);
+ std::wcout.fill(L'*');
+#endif
+
+ // Switch to the unsynchronized mode. This swaps the underlying buffers, but the
+ // stream objects and all their state must be preserved.
+ std::ios_base::sync_with_stdio(false);
+
+ assert(std::cin.iword(index) == 11);
+ assert(std::cout.iword(index) == 22);
+ assert(std::cerr.iword(index) == 33);
+ assert(std::clog.iword(index) == 44);
+ assert(std::cout.pword(index) == &dummy);
+ assert((std::cout.flags() & std::ios_base::basefield) == std::ios_base::hex);
+ assert(std::cout.precision() == 7);
+ assert(std::cout.fill() == '*');
+ assert(std::cin.tie() == &std::cout);
+ assert(std::cerr.tie() == &std::cout);
+ assert(std::cerr.flags() & std::ios_base::unitbuf);
+ assert(std::cin.good());
+ assert(std::cout.good());
+ assert(std::cin.rdbuf());
+ assert(std::cout.rdbuf());
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ assert(std::wcin.iword(index) == 11);
+ assert(std::wcout.iword(index) == 22);
+ assert(std::wcerr.iword(index) == 33);
+ assert(std::wclog.iword(index) == 44);
+ assert(std::wcout.pword(index) == &dummy);
+ assert((std::wcout.flags() & std::ios_base::basefield) == std::ios_base::hex);
+ assert(std::wcout.precision() == 7);
+ assert(std::wcout.fill() == L'*');
+ assert(std::wcin.tie() == &std::wcout);
+ assert(std::wcerr.tie() == &std::wcout);
+ assert(std::wcerr.flags() & std::ios_base::unitbuf);
+ assert(std::wcin.good());
+ assert(std::wcout.good());
+ assert(std::wcin.rdbuf());
+ assert(std::wcout.rdbuf());
+#endif
+
+ // Switch back to synchronized mode and check that the state is still there.
+ std::ios_base::sync_with_stdio(true);
+
+ assert(std::cout.iword(index) == 22);
+ assert(std::cout.pword(index) == &dummy);
+ assert((std::cout.flags() & std::ios_base::basefield) == std::ios_base::hex);
+ assert(std::cout.precision() == 7);
+ assert(std::cout.fill() == '*');
+ assert(std::cin.tie() == &std::cout);
+ assert(std::cerr.tie() == &std::cout);
+ assert(std::cerr.flags() & std::ios_base::unitbuf);
+ assert(std::cout.good());
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ assert(std::wcout.iword(index) == 22);
+ assert(std::wcout.pword(index) == &dummy);
+ assert((std::wcout.flags() & std::ios_base::basefield) == std::ios_base::hex);
+ assert(std::wcout.precision() == 7);
+ assert(std::wcout.fill() == L'*');
+ assert(std::wcin.tie() == &std::wcout);
+ assert(std::wcerr.tie() == &std::wcout);
+ assert(std::wcerr.flags() & std::ios_base::unitbuf);
+ assert(std::wcout.good());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcerr.sync_with_stdio.sh.cpp b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcerr.sync_with_stdio.sh.cpp
new file mode 100644
index 0000000000000..2a65be4863bf5
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcerr.sync_with_stdio.sh.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// XFAIL: LIBCXX-PICOLIBC-FIXME
+
+// UNSUPPORTED: no-wide-characters
+
+// <iostream>
+
+// wostream wcerr;
+
+// Unlike wcin/wcout/wclog, std::wcerr is still unbuffered even when sync_with_stdio(false)
+// is called. This test ensures that it produces correct output after sync_with_stdio(false).
+// We can't check interleaving with C stdio functions here since C stdio uses narrow characters.
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2> %t.actual
+// RUN: echo -n 1234 > %t.expected
+// RUN: diff %t.expected %t.actual
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+ assert(std::ios_base::sync_with_stdio(false));
+
+ std::wcerr << L"12" << 34;
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.readmany.sh.cpp b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.readmany.sh.cpp
new file mode 100644
index 0000000000000..57113e21535e3
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.objects/wide.stream.objects/wcin.readmany.sh.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// QEMU does not detect EOF, when reading from stdin
+// "echo -n" suppresses any characters after the output and so the test hangs.
+// https://gitlab.com/qemu-project/qemu/-/issues/1963
+// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
+
+// This test hangs on Android devices that lack shell_v2, which was added in
+// Android N (API 24).
+// UNSUPPORTED: LIBCXX-ANDROID-FIXME && android-device-api={{2[1-3]}}
+
+// UNSUPPORTED: no-wide-characters
+
+// <iostream>
+
+// wistream wcin;
+
+// Read an input that is much larger than any reasonable internal buffer so that the
+// buffer has to be refilled (underflow) several times, and check that every value
+// is read correctly and that EOF is detected at the end.
+
+// RUN: seq 1 5000 > %t.input
+
+// RUN: %{build} -DSYNC_WITH_STDIO_FALSE
+// RUN: %{exec} %t.exe < %t.input
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe < %t.input
+
+#include <cassert>
+#include <iostream>
+
+int main(int, char**) {
+#ifdef SYNC_WITH_STDIO_FALSE
+ assert(std::ios_base::sync_with_stdio(false));
+#endif
+
+ long sum = 0;
+ int count = 0;
+ int value = 0;
+ while (std::wcin >> value) {
+ sum += value;
+ ++count;
+ }
+
+ assert(count == 5000);
+ assert(sum == 5000L * 5001L / 2L); // sum of 1..5000
+ assert(std::wcin.eof());
+ assert(!std::wcin.good());
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostreams.base/ios.base/ios.members.static/sync_with_stdio.pass.cpp b/libcxx/test/std/input.output/iostreams.base/ios.base/ios.members.static/sync_with_stdio.pass.cpp
index 0ec24b77560e5..3051f0dc3b1cb 100644
--- a/libcxx/test/std/input.output/iostreams.base/ios.base/ios.members.static/sync_with_stdio.pass.cpp
+++ b/libcxx/test/std/input.output/iostreams.base/ios.base/ios.members.static/sync_with_stdio.pass.cpp
@@ -17,6 +17,8 @@
int main(int, char**)
{
+ ASSERT_SAME_TYPE(decltype(std::ios_base::sync_with_stdio(false)), bool);
+
assert( std::ios_base::sync_with_stdio(false));
assert(!std::ios_base::sync_with_stdio(false));
assert(!std::ios_base::sync_with_stdio(true));
More information about the libcxx-commits
mailing list