[libcxx-commits] [libcxx] [libc++] Fix unnecessary flushes in std::print() on POSIX (PR #70321)
Dimitrij Mijoski via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Mar 10 05:57:42 PDT 2026
https://github.com/dimztimz updated https://github.com/llvm/llvm-project/pull/70321
>From c9dd48ded43c6eed78589b88ba3ca62d7a73b70c Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Tue, 16 Dec 2025 19:15:47 +0100
Subject: [PATCH 1/7] [libc++] Fix unnecessary flushes in std::print() on POSIX
The check whether the stream is associated with a terminal or not is
needed only on Windows. The flush is needed only on Windows and when the
stream is terminal. The flushing is done only once before using the native
Unicode API on Windows.
Additionally, the correct flush is now called. In the case of C stream
overloads of print(), std::fflush() should be used, and in the
ostream overloads, only ostream::flush() member function should be used.
Before this fix, the ostream overloads called ostream::flush() and then
std::fflush().
See also https://wg21.link/LWG4044.
Fixes #70142
---
libcxx/include/__ostream/print.h | 8 +-
libcxx/include/print | 27 +++----
.../vprint_unicode.pass.cpp | 28 +++++++
.../print.fun/vprint_unicode_posix.pass.cpp | 79 -------------------
.../print.fun/vprint_unicode_windows.pass.cpp | 30 +------
5 files changed, 43 insertions(+), 129 deletions(-)
delete mode 100644 libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_posix.pass.cpp
diff --git a/libcxx/include/__ostream/print.h b/libcxx/include/__ostream/print.h
index c5906c41b95b5..dd0955256550e 100644
--- a/libcxx/include/__ostream/print.h
+++ b/libcxx/include/__ostream/print.h
@@ -87,7 +87,7 @@ _LIBCPP_EXPORTED_FROM_ABI FILE* __get_ostream_file(ostream& __os);
# if _LIBCPP_HAS_UNICODE
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI void __vprint_unicode(ostream& __os, string_view __fmt, format_args __args, bool __write_nl) {
-# if _LIBCPP_AVAILABILITY_HAS_PRINT == 0
+# if _LIBCPP_AVAILABILITY_HAS_PRINT == 0 || !defined(_LIBCPP_WIN32API)
return std::__vprint_nonunicode(__os, __fmt, __args, __write_nl);
# else
FILE* __file = std::__get_ostream_file(__os);
@@ -110,10 +110,8 @@ _LIBCPP_HIDE_FROM_ABI void __vprint_unicode(ostream& __os, string_view __fmt, fo
# endif // _LIBCPP_HAS_EXCEPTIONS
ostream::sentry __s(__os);
if (__s) {
-# ifndef _LIBCPP_WIN32API
- __print::__vprint_unicode_posix(__file, __fmt, __args, __write_nl, true);
-# elif _LIBCPP_HAS_WIDE_CHARACTERS
- __print::__vprint_unicode_windows(__file, __fmt, __args, __write_nl, true);
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+ __print::__vprint_unicode_windows(__file, __fmt, __args, __write_nl);
# else
# error "Windows builds with wchar_t disabled are not supported."
# endif
diff --git a/libcxx/include/print b/libcxx/include/print
index 0ff314c22dcd9..2105fab888514 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -236,26 +236,11 @@ __vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args, bool
// terminal when the output is redirected. Typically during testing the
// output is redirected to be able to capture it. This makes it hard to
// test this code path.
-template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
-_LIBCPP_HIDE_FROM_ABI inline void
-__vprint_unicode_posix(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl, bool __is_terminal) {
- // TODO PRINT Should flush errors throw too?
- if (__is_terminal)
- std::fflush(__stream);
-
- __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl);
-}
# if _LIBCPP_HAS_WIDE_CHARACTERS
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void
-__vprint_unicode_windows(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl, bool __is_terminal) {
- if (!__is_terminal)
- return __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl);
-
- // TODO PRINT Should flush errors throw too?
- std::fflush(__stream);
-
+__vprint_unicode_windows([[maybe_unused]] FILE* __stream, string_view __fmt, format_args __args, bool __write_nl) {
string __str = std::vformat(__fmt, __args);
// UTF-16 uses the same number or less code units than UTF-8.
// However the size of the code unit is 16 bits instead of 8 bits.
@@ -316,9 +301,15 @@ __vprint_unicode([[maybe_unused]] FILE* __stream,
// Windows there is a different API. This API requires transcoding.
# ifndef _LIBCPP_WIN32API
- __print::__vprint_unicode_posix(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream));
+ __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl);
# elif _LIBCPP_HAS_WIDE_CHARACTERS
- __print::__vprint_unicode_windows(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream));
+ if (__print::__is_terminal(__stream)) {
+ // TODO PRINT Should flush errors throw too?
+ std::fflush(__stream);
+ __print::__vprint_unicode_windows(__stream, __fmt, __args, __write_nl);
+ } else {
+ __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl);
+ }
# else
# error "Windows builds with wchar_t disabled are not supported."
# endif
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index 52d8500f7fa3a..7882d237f8f20 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -81,14 +81,22 @@ static void test_is_terminal_file_stream() {
assert(stream.is_open());
assert(stream.good());
std::print(stream, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 1);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
{
std::ofstream stream(filename);
assert(stream.is_open());
assert(stream.good());
std::print(stream, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 2);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
}
@@ -105,7 +113,11 @@ static void test_is_terminal_rdbuf_derived_from_filebuf() {
std::ostream stream(&buf);
std::print(stream, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 1);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
// When the stream is cout, clog, or cerr, its FILE* may be a terminal. Validate
@@ -115,15 +127,27 @@ static void test_is_terminal_std_cout_cerr_clog() {
is_terminal_result = false;
{
std::print(std::cout, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 1);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
{
std::print(std::cerr, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 2);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
{
std::print(std::clog, "test");
+#ifdef _WIN32
assert(is_terminal_calls == 3);
+#else
+ assert(is_terminal_calls == 0);
+#endif
}
}
@@ -156,7 +180,11 @@ static void test_is_terminal_is_flushed() {
// A terminal sync is called.
is_terminal_result = true;
std::print(stream, "");
+#ifdef _WIN32
assert(buf.sync_calls == 1); // only called from the destructor of the sentry
+#else
+ assert(buf.sync_calls == 0);
+#endif
}
int main(int, char**) {
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_posix.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_posix.pass.cpp
deleted file mode 100644
index b89d02ba99425..0000000000000
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_posix.pass.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: no-filesystem
-// UNSUPPORTED: libcpp-has-no-unicode
-// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
-
-// XFAIL: availability-fp_to_chars-missing
-
-// fmemopen is available starting in Android M (API 23)
-// XFAIL: target={{.+}}-android{{(eabi)?(21|22)}}
-
-// REQUIRES: has-unix-headers
-
-// <print>
-
-// Tests the implementation of
-// void __print::__vprint_unicode_posix(FILE* __stream, string_view __fmt,
-// format_args __args, bool __write_nl,
-// bool __is_terminal);
-//
-// In the library when the stdout is redirected to a file it is no
-// longer considered a terminal and the special terminal handling is no
-// longer executed. By testing this function we can "force" emulate a
-// terminal.
-// Note __write_nl is tested by the public API.
-
-#include <algorithm>
-#include <array>
-#include <cassert>
-#include <cstdio>
-#include <print>
-
-#include "test_macros.h"
-
-int main(int, char**) {
- std::array<char, 100> buffer;
- std::ranges::fill(buffer, '*');
-
- FILE* file = fmemopen(buffer.data(), buffer.size(), "wb");
- assert(file);
-
- // Test the file is buffered.
- std::fprintf(file, "Hello");
- assert(std::ftell(file) == 5);
-#if defined(TEST_HAS_GLIBC) && \
- !(__has_feature(address_sanitizer) || __has_feature(thread_sanitizer) || __has_feature(memory_sanitizer))
- assert(std::ranges::all_of(buffer, [](char c) { return c == '*'; }));
-#endif
-
- // Test writing to a "non-terminal" stream does not flush.
- std::__print::__vprint_unicode_posix(file, " world", std::make_format_args(), false, false);
- assert(std::ftell(file) == 11);
-#if defined(TEST_HAS_GLIBC) && \
- !(__has_feature(address_sanitizer) || __has_feature(thread_sanitizer) || __has_feature(memory_sanitizer))
- assert(std::ranges::all_of(buffer, [](char c) { return c == '*'; }));
-#endif
-
- // Test writing to a "terminal" stream flushes before writing.
- std::__print::__vprint_unicode_posix(file, "!", std::make_format_args(), false, true);
- assert(std::ftell(file) == 12);
- assert(std::string_view(buffer.data(), buffer.data() + 11) == "Hello world");
-#if defined(TEST_HAS_GLIBC)
- // glibc does not flush after a write.
- assert(buffer[11] != '!');
-#endif
-
- // Test everything is written when closing the stream.
- std::fclose(file);
- assert(std::string_view(buffer.data(), buffer.data() + 12) == "Hello world!");
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
index bcd1d05a3aeeb..4777d9a3180f4 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
@@ -22,7 +22,7 @@
// Tests the implementation of
// void __print::__vprint_unicode_windows(FILE* __stream, string_view __fmt,
// format_args __args, bool __write_nl,
-// bool __is_terminal);
+// );
//
// In the library when the stdout is redirected to a file it is no
// longer considered a terminal and the special terminal handling is no
@@ -59,43 +59,19 @@ scoped_test_env env;
std::string filename = env.create_file("output.txt");
static void test_basics() {
- FILE* file = std::fopen(filename.c_str(), "wb");
- assert(file);
-
- // Test writing to a "non-terminal" stream does not call WriteConsoleW.
- std::__print::__vprint_unicode_windows(file, "Hello", std::make_format_args(), false, false);
- assert(std::ftell(file) == 5);
-
// It's not possible to reliably test whether writing to a "terminal" stream
// flushes before writing. Testing flushing a closed stream worked on some
// platforms, but was unreliable.
calling = true;
- std::__print::__vprint_unicode_windows(file, " world", std::make_format_args(), false, true);
+ std::__print::__vprint_unicode_windows(stdout, " world", std::make_format_args(), false);
}
// When the output is a file the data is written as-is.
// When the output is a "terminal" invalid UTF-8 input is flagged.
static void test(std::wstring_view output, std::string_view input) {
- // *** File ***
- FILE* file = std::fopen(filename.c_str(), "wb");
- assert(file);
-
- std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, false);
- assert(std::ftell(file) == static_cast<long>(input.size()));
- std::fclose(file);
-
- file = std::fopen(filename.c_str(), "rb");
- assert(file);
-
- std::vector<char> buffer(input.size());
- size_t read = fread(buffer.data(), 1, buffer.size(), file);
- assert(read == input.size());
- assert(input == std::string_view(buffer.begin(), buffer.end()));
- std::fclose(file);
-
// *** Terminal ***
expected = output;
- std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, true);
+ std::__print::__vprint_unicode_windows(stdout, input, std::make_format_args(), false);
}
static void test() {
>From 6453a9c4f440f2518bc828707bf85200c2cc3b03 Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Tue, 14 May 2024 18:12:49 +0200
Subject: [PATCH 2/7] fixup! [libc++] Fix unnecessary flushes in std::print()
on POSIX
Fix test for modules
---
.../ostream.formatted.print/vprint_unicode.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index 7882d237f8f20..c3c60ed705361 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -19,7 +19,7 @@
// XFAIL: availability-print-missing
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_IS_TERMINAL
-// XFAIL: clang-modules-build
+// XFAIL: clang-modules-build && target={{.*}}-windows{{.*}}
// <ostream>
// Tests the implementation of
>From 9ec1a79602ac606e6269c7be8f62e6b087a1e582 Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Tue, 23 Jul 2024 13:23:19 +0200
Subject: [PATCH 3/7] fixup! [libc++] Fix unnecessary flushes in std::print()
on POSIX
Fix for CI job Apple system configuration
---
.../ostream.formatted.print/vprint_unicode.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index c3c60ed705361..20bccf342f165 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -16,7 +16,7 @@
// When std::print is unavailable, we don't rely on an implementation of
// std::__is_terminal and we always assume a non-unicode and non-terminal
// output.
-// XFAIL: availability-print-missing
+// XFAIL: availability-print-missing && target={{.*}}-windows{{.*}}
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_IS_TERMINAL
// XFAIL: clang-modules-build && target={{.*}}-windows{{.*}}
>From 807aa0c9efa8f62c87c7d892e19b54fd6e8af12a Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Mon, 9 Mar 2026 19:44:51 +0100
Subject: [PATCH 4/7] fixup! [libc++] Fix unnecessary flushes in std::print()
on POSIX
Fix tests
---
.../vprint_unicode.pass.cpp | 5 -----
.../print.fun/vprint_unicode_windows.pass.cpp | 19 +++++++++++--------
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index 20bccf342f165..c531d1ac340af 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -13,11 +13,6 @@
// XFAIL: availability-fp_to_chars-missing
-// When std::print is unavailable, we don't rely on an implementation of
-// std::__is_terminal and we always assume a non-unicode and non-terminal
-// output.
-// XFAIL: availability-print-missing && target={{.*}}-windows{{.*}}
-
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_IS_TERMINAL
// XFAIL: clang-modules-build && target={{.*}}-windows{{.*}}
// <ostream>
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
index 4777d9a3180f4..ae79a022a1116 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
@@ -59,19 +59,22 @@ scoped_test_env env;
std::string filename = env.create_file("output.txt");
static void test_basics() {
- // It's not possible to reliably test whether writing to a "terminal" stream
- // flushes before writing. Testing flushing a closed stream worked on some
- // platforms, but was unreliable.
+ FILE* file = std::fopen(filename.c_str(), "wb");
+ assert(file);
+
calling = true;
- std::__print::__vprint_unicode_windows(stdout, " world", std::make_format_args(), false);
+ std::__print::__vprint_unicode_windows(file, " world", std::make_format_args(), false);
}
-// When the output is a file the data is written as-is.
-// When the output is a "terminal" invalid UTF-8 input is flagged.
+// Invalid UTF-8 input is flagged.
static void test(std::wstring_view output, std::string_view input) {
- // *** Terminal ***
+ FILE* file = std::fopen(filename.c_str(), "wb");
+ assert(file);
+
expected = output;
- std::__print::__vprint_unicode_windows(stdout, input, std::make_format_args(), false);
+ std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false);
+ assert(std::ftell(file) == 0);
+ std::fclose(file);
}
static void test() {
>From 96f6c2666ffc95e26176cc1522791e3be4ddfaf8 Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Mon, 9 Mar 2026 22:05:08 +0100
Subject: [PATCH 5/7] fixup! [libc++] Fix unnecessary flushes in std::print()
on POSIX
fix tests for modules
---
.../ostream.formatted.print/vprint_unicode.pass.cpp | 2 +-
.../iostream.format/print.fun/vprint_unicode_windows.pass.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index c531d1ac340af..27387311b9f16 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -14,7 +14,7 @@
// XFAIL: availability-fp_to_chars-missing
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_IS_TERMINAL
-// XFAIL: clang-modules-build && target={{.*}}-windows{{.*}}
+// ADDITIONAL_COMPILE_FLAGS: -fno-modules
// <ostream>
// Tests the implementation of
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
index ae79a022a1116..d6f9d9cf0dda7 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
@@ -13,7 +13,7 @@
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION
-// XFAIL: clang-modules-build
+// ADDITIONAL_COMPILE_FLAGS: -fno-modules
// XFAIL: availability-fp_to_chars-missing
>From 0dab34714bda4534341f2eabf3a46cc300e6b15d Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Tue, 10 Mar 2026 12:09:58 +0100
Subject: [PATCH 6/7] fixup! [libc++] Fix unnecessary flushes in std::print()
on POSIX
---
libcxx/include/print | 10 ++--------
libcxx/src/print.cpp | 5 ++++-
.../print.fun/vprint_unicode_windows.pass.cpp | 3 +--
3 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/libcxx/include/print b/libcxx/include/print
index 2105fab888514..253b4af4f7971 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -69,8 +69,6 @@ _LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream);
// Note the function is only implemented on the Windows platform.
_LIBCPP_EXPORTED_FROM_ABI void __write_to_windows_console(FILE* __stream, wstring_view __view);
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
-# elif __has_include(<unistd.h>)
-_LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream);
# endif // _LIBCPP_WIN32API
# if _LIBCPP_STD_VER >= 23
@@ -202,14 +200,10 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_terminal([[maybe_unused]] FILE* __stream)
// the behavior in the test. This is not part of the public API.
# ifdef _LIBCPP_TESTING_PRINT_IS_TERMINAL
return _LIBCPP_TESTING_PRINT_IS_TERMINAL(__stream);
-# elif _LIBCPP_AVAILABILITY_HAS_PRINT == 0 || !_LIBCPP_HAS_TERMINAL
- return false;
-# elif defined(_LIBCPP_WIN32API)
+# elif _LIBCPP_AVAILABILITY_HAS_PRINT && _LIBCPP_HAS_TERMINAL && defined(_LIBCPP_WIN32API)
return std::__is_windows_terminal(__stream);
-# elif __has_include(<unistd.h>)
- return std::__is_posix_terminal(__stream);
# else
-# error "Provide a way to determine whether a FILE* is a terminal"
+ return false;
# endif
}
diff --git a/libcxx/src/print.cpp b/libcxx/src/print.cpp
index 82cf2afd052e2..a5edcc4632195 100644
--- a/libcxx/src/print.cpp
+++ b/libcxx/src/print.cpp
@@ -64,9 +64,12 @@ __write_to_windows_console([[maybe_unused]] FILE* __stream, [[maybe_unused]] wst
}
# endif // _LIBCPP_HAS_WIDE_CHARACTERS
-#elif defined(HAS_FILENO_AND_ISATTY) // !_LIBCPP_WIN32API
+#elif defined(HAS_FILENO_AND_ISATTY) && _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 23 // !_LIBCPP_WIN32API
+_LIBCPP_DIAGNOSTIC_PUSH
+_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes")
_LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream) { return isatty(fileno(__stream)); }
+_LIBCPP_DIAGNOSTIC_POP
#endif
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
index d6f9d9cf0dda7..162579027831b 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/vprint_unicode_windows.pass.cpp
@@ -21,8 +21,7 @@
// Tests the implementation of
// void __print::__vprint_unicode_windows(FILE* __stream, string_view __fmt,
-// format_args __args, bool __write_nl,
-// );
+// format_args __args, bool __write_nl);
//
// In the library when the stdout is redirected to a file it is no
// longer considered a terminal and the special terminal handling is no
>From 9a8d89f24d306518a68f86184d0baaf78b19f71b Mon Sep 17 00:00:00 2001
From: Dimitrij Mijoski <dmjpp at hotmail.com>
Date: Tue, 10 Mar 2026 13:40:51 +0100
Subject: [PATCH 7/7] amend! [libc++] Fix unnecessary flushes in std::print()
on POSIX
[libc++] Fix checks for terminal and flushes in std::print()
The check whether a stream is associated with a terminal or not and the
flushing of the stream in std::print() is needed only on Windows.
Additionally, the correct flush should be used. When std::print is
called with a C stream, std::flush() should be used. When it is called
with C++ ostream, ostream::flush() should be called.
Because POSIX does not have a separate Unicode API for terminal output,
checking for terminal (isatty) and flushing is not needed at all.
Moreover, isatty has noticeable performance cost.
See also https://wg21.link/LWG4044.
Fixes #70142
More information about the libcxx-commits
mailing list