diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index dcf9838edd74b..952043f652c27 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -358,7 +358,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_out_ptr`` ``202106L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_print`` ``202207L`` + ``__cpp_lib_print`` ``202403L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges`` ``202406L`` ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index e7cfa625a132c..a1f30b26c5a1d 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -40,6 +40,7 @@ Implemented Papers - N4258: Cleaning-up noexcept in the Library (`Github `__) - P1361R2: Integration of chrono with text formatting (`Github `__) +- P3107R5 - Permit an efficient implementation of ``std::print`` (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 1436db6cf2b45..5ccb60e9cf66b 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -50,7 +50,7 @@ "`P2867R2 `__","Remove Deprecated ``strstreams`` From C++26","2024-03 (Tokyo)","|Complete|","19","" "`P2869R4 `__","Remove Deprecated ``shared_ptr`` Atomic Access APIs from C++26","2024-03 (Tokyo)","","","" "`P2872R3 `__","Remove ``wstring_convert`` From C++26","2024-03 (Tokyo)","|Complete|","19","" -"`P3107R5 `__","Permit an efficient implementation of ``std::print``","2024-03 (Tokyo)","","","" +"`P3107R5 `__","Permit an efficient implementation of ``std::print``","2024-03 (Tokyo)","|Complete|","21","" "`P3142R0 `__","Printing Blank Lines with ``println``","2024-03 (Tokyo)","|Complete|","19","Implemented as a DR against C++23. (MSVC STL and libstdc++ will do the same.)" "`P2845R8 `__","Formatting of ``std::filesystem::path``","2024-03 (Tokyo)","","","" "`P0493R5 `__","Atomic minimum/maximum","2024-03 (Tokyo)","","","" diff --git a/libcxx/include/__ostream/print.h b/libcxx/include/__ostream/print.h index a4d7506cffc48..b5ce81ea5a10a 100644 --- a/libcxx/include/__ostream/print.h +++ b/libcxx/include/__ostream/print.h @@ -111,9 +111,9 @@ _LIBCPP_HIDE_FROM_ABI void __vprint_unicode(ostream& __os, string_view __fmt, fo ostream::sentry __s(__os); if (__s) { # ifndef _LIBCPP_WIN32API - __print::__vprint_unicode_posix(__file, __fmt, __args, __write_nl, true); + __print::__vprint_unicode_posix<__print::__lock_policy::__stdio>(__file, __fmt, __args, __write_nl, true); # elif _LIBCPP_HAS_WIDE_CHARACTERS - __print::__vprint_unicode_windows(__file, __fmt, __args, __write_nl, true); + __print::__vprint_unicode_windows<__print::__lock_policy::__stdio>(__file, __fmt, __args, __write_nl, true); # else # error "Windows builds with wchar_t disabled are not supported." # endif diff --git a/libcxx/include/print b/libcxx/include/print index 1794d6014efcd..8cc7c07aa0d2a 100644 --- a/libcxx/include/print +++ b/libcxx/include/print @@ -27,9 +27,11 @@ namespace std { void vprint_unicode(string_view fmt, format_args args); void vprint_unicode(FILE* stream, string_view fmt, format_args args); + void vprint_unicode_buffered(FILE* stream, string_view fmt, format_args args); void vprint_nonunicode(string_view fmt, format_args args); void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); + void vprint_nonunicode_buffered(FILE* stream, string_view fmt, format_args args); } */ @@ -41,6 +43,7 @@ namespace std { # include <__config> # include <__system_error/throw_system_error.h> # include <__utility/forward.h> +# include <__utility/move.h> # include # include # include @@ -52,6 +55,9 @@ namespace std { # pragma GCC system_header # endif +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD # ifdef _LIBCPP_WIN32API @@ -213,20 +219,181 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_terminal([[maybe_unused]] FILE* __stream) # endif } -template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). -_LIBCPP_HIDE_FROM_ABI inline void -__vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl) { +_LIBCPP_HIDE_FROM_ABI inline void __flockfile(FILE* __stream) { +# if defined(_LIBCPP_WIN32API) + ::_lock_file(__stream); +# elif __has_include() + ::flockfile(__stream); +# else +# error "Provide a way to do unlocked stream I/O operations" +# endif +} +_LIBCPP_HIDE_FROM_ABI inline void __funlockfile(FILE* __stream) { +# if defined(_LIBCPP_WIN32API) + ::_unlock_file(__stream); +# elif __has_include() + ::funlockfile(__stream); +# else +# error "Provide a way to do unlocked stream I/O operations" +# endif +} + +_LIBCPP_HIDE_FROM_ABI inline int __fflush_unlocked(FILE* __stream) { +# if defined(_LIBCPP_WIN32API) + return ::_fflush_nolock(__stream); +# elif defined(__PICOLIBC__) || defined(_AIX) || defined(__ANDROID__) || defined(__APPLE__) + // There is no fflush_unlocked on these systems. + // This funcion is not part of POSIX. + return ::fflush(__stream); +# elif __has_include() + return ::fflush_unlocked(__stream); +# else +# error "Provide a way to do unlocked stream I/O operations" +# endif +} + +// Note for our use-case __size is always 1; +_LIBCPP_HIDE_FROM_ABI inline size_t +__fwrite_unlocked(const void* __buffer, [[maybe_unused]] size_t __size, size_t __n, FILE* __stream) { +# if defined(_LIBCPP_WIN32API) + return ::_fwrite_nolock(__buffer, __size, __n, __stream); +# elif defined(__PICOLIBC__) || defined(_AIX) || defined(__ANDROID__) || defined(__APPLE__) + // The function fwrite_unlocked is not part of POSIX and not available on + // these systems. + auto __b = static_cast(__buffer); + for (size_t __i = 0; __i < __n; ++__i, ++__b) + // Unqualified since putc_unlocked is a macro on AIX. + if (putc_unlocked(*__b, __stream) == EOF) + return __i; + return __n; +# elif __has_include() + return ::fwrite_unlocked(__buffer, __size, __n, __stream); +# else +# error "Provide a way to do unlocked stream I/O operations" +# endif +} + +enum class __lock_policy { + // The locking is done manually, which allows calling the *_unlocked functions. + // + // These are used in the *_buffered overloads. + __manual, + // The locking is done inside the stdio library. + __stdio, + +}; + +template <__lock_policy __policy> +_LIBCPP_HIDE_FROM_ABI int __fflush(FILE* __stream) { + if constexpr (__policy == __lock_policy::__manual) + return __print ::__fflush_unlocked(__stream); + else if constexpr (__policy == __lock_policy::__stdio) + return std::fflush(__stream); + else +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 + static_assert(sizeof(__lock_policy) == 0, "Unsupported policy"); +# else + static_assert(false, "Unsupported policy"); +# endif +} + +// This "buffer" is not a typical buffer but an buffered adaptor for FILE* +// +// Based on the __lock_policy it will leave the locking to stdio or manually +// locks the stream and then uses unlocked stdio functions. This policy makes +// the print functions "foo" and "foo_buffered" to be templated. +template <__lock_policy __policy> +class _LIBCPP_TEMPLATE_VIS __file_stream_buffer : public __format::__output_buffer { +public: + using value_type = char; + + __file_stream_buffer(const __file_stream_buffer&) = delete; + __file_stream_buffer operator=(const __file_stream_buffer&) = delete; + + _LIBCPP_HIDE_FROM_ABI explicit __file_stream_buffer(FILE* __stream) + : __output_buffer{__small_buffer_, __buffer_size, __prepare_write, nullptr}, __stream_(__stream) { + if constexpr (__policy == __lock_policy::__manual) + __print::__flockfile(__stream_); + else if constexpr (__policy != __lock_policy::__stdio) +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 + static_assert(sizeof(__lock_policy) == 0, "Unsupported policy"); +# else + static_assert(false, "Unsupported policy"); +# endif + } + + _LIBCPP_HIDE_FROM_ABI ~__file_stream_buffer() { + if constexpr (__policy == __lock_policy::__manual) + __print::__funlockfile(__stream_); + else if constexpr (__policy != __lock_policy::__stdio) +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 + static_assert(sizeof(__lock_policy) == 0, "Unsupported policy"); +# else + static_assert(false, "Unsupported policy"); +# endif + } + + // In order to ensure all data is written this function needs to be called. + // + // The class wraps C based APIs that never throw. However the Standard + // requires exceptions to be throw when a write operation fails. Therefore + // this function should be called before the class is destroyed. + _LIBCPP_HIDE_FROM_ABI void __write_internal_buffer() && { __write_buffer(); } + +private: + FILE* __stream_; + + // This class uses a fixed size buffer and appends the elements in + // __buffer_size chunks. An alternative would be to use an allocating buffer + // and append the output in a single write operation. Benchmarking showed no + // performance difference. + static constexpr size_t __buffer_size = 256; + char __small_buffer_[__buffer_size]; + + _LIBCPP_HIDE_FROM_ABI void __write_buffer() { + size_t __n = this->__size(); + size_t __size = [&] { + if constexpr (__policy == __lock_policy::__manual) + return __print::__fwrite_unlocked(__small_buffer_, 1, __n, __stream_); + else if constexpr (__policy == __lock_policy::__stdio) + return std::fwrite(__small_buffer_, 1, __n, __stream_); + else +# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600 + static_assert(sizeof(__lock_policy) == 0, "Unsupported policy"); +# else + static_assert(false, "Unsupported policy"); +# endif + }(); + + if (__size < __n) { + if (std::feof(__stream_)) + std::__throw_system_error(EIO, "EOF while writing the formatted output"); + std::__throw_system_error(std::ferror(__stream_), "failed to write formatted output"); + } + } + + _LIBCPP_HIDE_FROM_ABI void __prepare_write() { + __write_buffer(); + this->__buffer_flushed(); + } + + _LIBCPP_HIDE_FROM_ABI static void + __prepare_write(__output_buffer& __buffer, [[maybe_unused]] size_t __size_hint) { + static_cast<__file_stream_buffer<__policy>&>(__buffer).__prepare_write(); + } +}; + +template <__lock_policy __policy> +_LIBCPP_HIDE_FROM_ABI void __vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl) { _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream"); - string __str = std::vformat(__fmt, __args); + __print::__file_stream_buffer<__policy> __buffer(__stream); + + std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args)); if (__write_nl) - __str.push_back('\n'); + __buffer.push_back('\n'); - size_t __size = fwrite(__str.data(), 1, __str.size(), __stream); - if (__size < __str.size()) { - if (std::feof(__stream)) - std::__throw_system_error(EIO, "EOF while writing the formatted output"); - std::__throw_system_error(std::ferror(__stream), "failed to write formatted output"); - } + std::move(__buffer).__write_internal_buffer(); } # if _LIBCPP_HAS_UNICODE @@ -236,25 +403,33 @@ __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 // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). -_LIBCPP_HIDE_FROM_ABI inline void + +template <__lock_policy __policy> +_LIBCPP_HIDE_FROM_ABI void __vprint_unicode_posix(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl, bool __is_terminal) { + _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream"); + // TODO PRINT Should flush errors throw too? if (__is_terminal) - std::fflush(__stream); + __print::__fflush<__policy>(__stream); - __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl); + __print::__vprint_nonunicode<__policy>(__stream, __fmt, __args, __write_nl); } # if _LIBCPP_HAS_WIDE_CHARACTERS -template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). -_LIBCPP_HIDE_FROM_ABI inline void + +template <__lock_policy __policy> +_LIBCPP_HIDE_FROM_ABI void __vprint_unicode_windows(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl, bool __is_terminal) { + _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream"); + if (!__is_terminal) - return __print::__vprint_nonunicode(__stream, __fmt, __args, __write_nl); + return __print::__vprint_nonunicode<__policy>(__stream, __fmt, __args, __write_nl); + + [[maybe_unused]] __print::__file_stream_buffer<__policy> __b(__stream); // TODO PRINT Should flush errors throw too? - std::fflush(__stream); + __print::__fflush<__policy>(__stream); string __str = std::vformat(__fmt, __args); // UTF-16 uses the same number or less code units than UTF-8. @@ -284,10 +459,11 @@ __vprint_unicode_windows(FILE* __stream, string_view __fmt, format_args __args, "__write_to_windows_console is not available."); # endif } + # endif // _LIBCPP_HAS_WIDE_CHARACTERS -template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). -_LIBCPP_HIDE_FROM_ABI inline void +template <__lock_policy __policy> +_LIBCPP_HIDE_FROM_ABI void __vprint_unicode([[maybe_unused]] FILE* __stream, [[maybe_unused]] string_view __fmt, [[maybe_unused]] format_args __args, @@ -316,28 +492,32 @@ __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_unicode_posix<__policy>(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream)); # elif _LIBCPP_HAS_WIDE_CHARACTERS - __print::__vprint_unicode_windows(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream)); + __print::__vprint_unicode_windows<__policy>(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream)); # else # error "Windows builds with wchar_t disabled are not supported." # endif } - # endif // _LIBCPP_HAS_UNICODE } // namespace __print template _LIBCPP_HIDE_FROM_ABI void print(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) { + constexpr bool __locksafe = (enable_nonlocking_formatter_optimization> && ...); + + using enum __print::__lock_policy; # if _LIBCPP_HAS_UNICODE if constexpr (__print::__use_unicode_execution_charset) - __print::__vprint_unicode(__stream, __fmt.get(), std::make_format_args(__args...), false); + __print::__vprint_unicode<__locksafe ? __manual : __stdio>( + __stream, __fmt.get(), std::make_format_args(__args...), false); else - __print::__vprint_nonunicode(__stream, __fmt.get(), std::make_format_args(__args...), false); -# else // _LIBCPP_HAS_UNICODE - __print::__vprint_nonunicode(__stream, __fmt.get(), std::make_format_args(__args...), false); # endif // _LIBCPP_HAS_UNICODE + { + __print::__vprint_nonunicode<__locksafe ? __manual : __stdio>( + __stream, __fmt.get(), std::make_format_args(__args...), false); + } } template @@ -347,17 +527,22 @@ _LIBCPP_HIDE_FROM_ABI void print(format_string<_Args...> __fmt, _Args&&... __arg template _LIBCPP_HIDE_FROM_ABI void println(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) { -# if _LIBCPP_HAS_UNICODE + constexpr bool __locksafe = (enable_nonlocking_formatter_optimization> && ...); + // Note the wording in the Standard is inefficient. The output of // std::format is a std::string which is then copied. This solution // just appends a newline at the end of the output. + using enum __print::__lock_policy; +# if _LIBCPP_HAS_UNICODE if constexpr (__print::__use_unicode_execution_charset) - __print::__vprint_unicode(__stream, __fmt.get(), std::make_format_args(__args...), true); + __print::__vprint_unicode<__locksafe ? __manual : __stdio>( + __stream, __fmt.get(), std::make_format_args(__args...), true); else - __print::__vprint_nonunicode(__stream, __fmt.get(), std::make_format_args(__args...), true); -# else // _LIBCPP_HAS_UNICODE - __print::__vprint_nonunicode(__stream, __fmt.get(), std::make_format_args(__args...), true); # endif // _LIBCPP_HAS_UNICODE + { + __print::__vprint_nonunicode<__locksafe ? __manual : __stdio>( + __stream, __fmt.get(), std::make_format_args(__args...), true); + } } template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). @@ -378,7 +563,12 @@ _LIBCPP_HIDE_FROM_ABI void println(format_string<_Args...> __fmt, _Args&&... __a # if _LIBCPP_HAS_UNICODE template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). _LIBCPP_HIDE_FROM_ABI inline void vprint_unicode(FILE* __stream, string_view __fmt, format_args __args) { - __print::__vprint_unicode(__stream, __fmt, __args, false); + __print::__vprint_unicode<__print::__lock_policy::__stdio>(__stream, __fmt, __args, false); +} + +template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). +_LIBCPP_HIDE_FROM_ABI inline void vprint_unicode_buffered(FILE* __stream, string_view __fmt, format_args __args) { + __print::__vprint_unicode<__print::__lock_policy::__manual>(__stream, __fmt, __args, false); } template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). @@ -390,7 +580,12 @@ _LIBCPP_HIDE_FROM_ABI inline void vprint_unicode(string_view __fmt, format_args template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). _LIBCPP_HIDE_FROM_ABI inline void vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args) { - __print::__vprint_nonunicode(__stream, __fmt, __args, false); + __print::__vprint_nonunicode< __print::__lock_policy::__stdio >(__stream, __fmt, __args, false); +} + +template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). +_LIBCPP_HIDE_FROM_ABI inline void vprint_nonunicode_buffered(FILE* __stream, string_view __fmt, format_args __args) { + __print::__vprint_nonunicode<__print::__lock_policy::__manual>(__stream, __fmt, __args, false); } template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). @@ -402,6 +597,8 @@ _LIBCPP_HIDE_FROM_ABI inline void vprint_nonunicode(string_view __fmt, format_ar _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_PRINT diff --git a/libcxx/include/version b/libcxx/include/version index 63ead9fd5d29d..f2f3352815dbc 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -185,7 +185,7 @@ __cpp_lib_out_ptr 202311L __cpp_lib_parallel_algorithm 201603L __cpp_lib_philox_engine 202406L __cpp_lib_polymorphic_allocator 201902L -__cpp_lib_print 202207L +__cpp_lib_print 202403L __cpp_lib_quoted_string_io 201304L __cpp_lib_ranges 202406L @@ -502,7 +502,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_optional 202110L # define __cpp_lib_out_ptr 202106L # if _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT -# define __cpp_lib_print 202207L +# define __cpp_lib_print 202403L # endif # undef __cpp_lib_ranges # define __cpp_lib_ranges 202406L diff --git a/libcxx/modules/std/print.inc b/libcxx/modules/std/print.inc index 5354025ca8bd8..123bce409a06a 100644 --- a/libcxx/modules/std/print.inc +++ b/libcxx/modules/std/print.inc @@ -14,8 +14,10 @@ export namespace std { using std::println; using std::vprint_nonunicode; + using ::std::vprint_nonunicode_buffered; # if _LIBCPP_HAS_UNICODE using std::vprint_unicode; + using std::vprint_unicode_buffered; # endif // _LIBCPP_HAS_UNICODE #endif // _LIBCPP_STD_VER >= 23 } // namespace std 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 index b89d02ba99425..db92811f803fa 100644 --- 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 @@ -21,6 +21,7 @@ // // Tests the implementation of +// template <__print::__lock_policy __policy> // void __print::__vprint_unicode_posix(FILE* __stream, string_view __fmt, // format_args __args, bool __write_nl, // bool __is_terminal); @@ -39,7 +40,8 @@ #include "test_macros.h" -int main(int, char**) { +template +static void test() { std::array buffer; std::ranges::fill(buffer, '*'); @@ -55,7 +57,7 @@ int main(int, char**) { #endif // Test writing to a "non-terminal" stream does not flush. - std::__print::__vprint_unicode_posix(file, " world", std::make_format_args(), false, false); + 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)) @@ -63,7 +65,7 @@ int main(int, char**) { #endif // Test writing to a "terminal" stream flushes before writing. - std::__print::__vprint_unicode_posix(file, "!", std::make_format_args(), false, true); + 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) @@ -74,6 +76,11 @@ int main(int, char**) { // Test everything is written when closing the stream. std::fclose(file); assert(std::string_view(buffer.data(), buffer.data() + 12) == "Hello world!"); +} + +int main(int, char**) { + test(); + test(); 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..8028d7c04b85b 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 @@ -20,6 +20,7 @@ // // Tests the implementation of +// template <__print::__lock_policy __policy> // void __print::__vprint_unicode_windows(FILE* __stream, string_view __fmt, // format_args __args, bool __write_nl, // bool __is_terminal); @@ -47,8 +48,8 @@ TEST_GCC_DIAGNOSTIC_IGNORED("-Wuse-after-free") #define SV(S) MAKE_STRING_VIEW(wchar_t, S) -bool calling = false; -std::wstring_view expected = L" world"; +bool calling = true; +std::wstring_view expected; void write_to_console(FILE*, std::wstring_view data) { assert(calling); @@ -58,29 +59,35 @@ void write_to_console(FILE*, std::wstring_view data) { scoped_test_env env; std::string filename = env.create_file("output.txt"); +template static void test_basics() { FILE* file = std::fopen(filename.c_str(), "wb"); assert(file); + calling = false; + expected = L" world"; + // Test writing to a "non-terminal" stream does not call WriteConsoleW. - std::__print::__vprint_unicode_windows(file, "Hello", std::make_format_args(), false, false); + 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(file, " world", std::make_format_args(), false, true); + std::fclose(file); } // When the output is a file the data is written as-is. // When the output is a "terminal" invalid UTF-8 input is flagged. +template 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); + std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, false); assert(std::ftell(file) == static_cast(input.size())); std::fclose(file); @@ -95,12 +102,13 @@ static void test(std::wstring_view output, std::string_view input) { // *** Terminal *** expected = output; - std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, true); + std::__print::__vprint_unicode_windows(file, input, std::make_format_args(), false, true); } +template static void test() { // *** Test valid UTF-8 *** -#define TEST(S) test(SV(S), S) +#define TEST(S) test(SV(S), S) TEST("hello world"); // copied from benchmarks/std_format_spec_string_unicode.bench.cpp @@ -112,24 +120,29 @@ static void test() { #undef TEST // *** Test invalid utf-8 *** - test(SV("\ufffd"), "\xc3"); - test(SV("\ufffd("), "\xc3\x28"); + test(SV("\ufffd"), "\xc3"); + test(SV("\ufffd("), "\xc3\x28"); // surrogate range - test(SV("\ufffd"), "\xed\xa0\x80"); // U+D800 - test(SV("\ufffd"), "\xed\xaf\xbf"); // U+DBFF - test(SV("\ufffd"), "\xed\xbf\x80"); // U+DC00 - test(SV("\ufffd"), "\xed\xbf\xbf"); // U+DFFF + test(SV("\ufffd"), "\xed\xa0\x80"); // U+D800 + test(SV("\ufffd"), "\xed\xaf\xbf"); // U+DBFF + test(SV("\ufffd"), "\xed\xbf\x80"); // U+DC00 + test(SV("\ufffd"), "\xed\xbf\xbf"); // U+DFFF // beyond valid values - test(SV("\ufffd"), "\xf4\x90\x80\x80"); // U+110000 - test(SV("\ufffd"), "\xf4\xbf\xbf\xbf"); // U+11FFFF + test(SV("\ufffd"), "\xf4\x90\x80\x80"); // U+110000 + test(SV("\ufffd"), "\xf4\xbf\xbf\xbf"); // U+11FFFF // Validates http://unicode.org/review/pr-121.html option 3. - test(SV("\u0061\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0062"), "\x61\xf1\x80\x80\xe1\x80\xc2\x62"); + test(SV("\u0061\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0062"), "\x61\xf1\x80\x80\xe1\x80\xc2\x62"); } int main(int, char**) { - test_basics(); - test(); + test_basics(); + test(); + + test_basics(); + test(); + + return 0; } diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index ec5db90597d92..7d52c9fe13594 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -122,15 +122,19 @@ atomic ratio atomic type_traits atomic version barrier atomic +barrier cctype barrier climits barrier cmath barrier compare barrier concepts barrier cstddef barrier cstdint +barrier cstdio barrier cstdlib barrier cstring barrier ctime +barrier cwchar +barrier cwctype barrier exception barrier initializer_list barrier iosfwd @@ -2024,6 +2028,7 @@ stdexcept new stdexcept type_traits stdexcept typeinfo stdexcept version +stop_token cstddef stop_token iosfwd stop_token version streambuf algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index ec5db90597d92..7d52c9fe13594 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -122,15 +122,19 @@ atomic ratio atomic type_traits atomic version barrier atomic +barrier cctype barrier climits barrier cmath barrier compare barrier concepts barrier cstddef barrier cstdint +barrier cstdio barrier cstdlib barrier cstring barrier ctime +barrier cwchar +barrier cwctype barrier exception barrier initializer_list barrier iosfwd @@ -2024,6 +2028,7 @@ stdexcept new stdexcept type_traits stdexcept typeinfo stdexcept version +stop_token cstddef stop_token iosfwd stop_token version streambuf algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index 95024df0590b8..951a785cf077b 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -125,15 +125,19 @@ atomic ratio atomic type_traits atomic version barrier atomic +barrier cctype barrier climits barrier cmath barrier compare barrier concepts barrier cstddef barrier cstdint +barrier cstdio barrier cstdlib barrier cstring barrier ctime +barrier cwchar +barrier cwctype barrier exception barrier initializer_list barrier iosfwd @@ -2064,6 +2068,7 @@ stdexcept new stdexcept type_traits stdexcept typeinfo stdexcept version +stop_token cstddef stop_token iosfwd stop_token version streambuf algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index a3518f7f62ecb..7742c23b796f7 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -122,15 +122,19 @@ atomic ratio atomic type_traits atomic version barrier atomic +barrier cctype barrier climits barrier cmath barrier compare barrier concepts barrier cstddef barrier cstdint +barrier cstdio barrier cstdlib barrier cstring barrier ctime +barrier cwchar +barrier cwctype barrier exception barrier initializer_list barrier iosfwd @@ -2077,6 +2081,7 @@ stdexcept new stdexcept type_traits stdexcept typeinfo stdexcept version +stop_token cstddef stop_token iosfwd stop_token version streambuf algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index 17972b8453743..a26aeeebef75e 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -556,7 +556,6 @@ istream ios istream iosfwd istream limits istream locale - istream ratio istream stdexcept istream streambuf diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode_buffered.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode_buffered.file.pass.cpp new file mode 100644 index 0000000000000..a5a35bf8bedb1 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode_buffered.file.pass.cpp @@ -0,0 +1,149 @@ +//===----------------------------------------------------------------------===// +// +// 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: GCC-ALWAYS_INLINE-FIXME + +// TODO PRINT Enable again +// https://reviews.llvm.org/D150044 +// https://lab.llvm.org/buildbot/#/builders/237/builds/3578 +// UNSUPPORTED: asan, hwasan, msan + +// XFAIL: availability-fp_to_chars-missing + +// The error exception has no system error string. +// XFAIL: LIBCXX-ANDROID-FIXME + +// + +// void vprint_nonunicode_buffered(FILE* stream, string_view fmt, format_args args); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "filesystem_test_helper.h" +#include "print_tests.h" +#include "test_macros.h" + +scoped_test_env env; +std::string filename = env.create_file("output.txt"); + +auto test_file = [](std::string_view expected, std::string_view fmt, Args&&... args) { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + std::vprint_nonunicode_buffered(file, fmt, std::make_format_args(args...)); + std::fclose(file); + + std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; + std::string out(std::istreambuf_iterator{stream}, {}); + TEST_REQUIRE(out == expected, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = []([[maybe_unused]] std::string_view what, + [[maybe_unused]] std::string_view fmt, + [[maybe_unused]] Args&&... args) { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + TEST_VALIDATE_EXCEPTION( + std::format_error, + [&]([[maybe_unused]] const std::format_error& e) { + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_nonunicode_buffered(file, fmt, std::make_format_args(args...))); + + fclose(file); +}; + +// Glibc fails writing to a wide stream. +#if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) +static void test_wide_stream() { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + int mode = std::fwide(file, 1); + assert(mode > 0); + + TEST_VALIDATE_EXCEPTION( + std::system_error, + [&]([[maybe_unused]] const std::system_error& e) { + [[maybe_unused]] std::string_view what{"failed to write formatted output"}; + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_nonunicode_buffered(file, "hello", std::make_format_args())); +} +#endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) + +static void test_read_only() { + FILE* file = fopen(filename.c_str(), "r"); + assert(file); + + TEST_VALIDATE_EXCEPTION( + std::system_error, + [&]([[maybe_unused]] const std::system_error& e) { + [[maybe_unused]] std::string_view what{ + "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_nonunicode_buffered(file, "hello", std::make_format_args())); +} + +static void test_new_line() { + // Text does newline translation. + { + FILE* file = fopen(filename.c_str(), "w"); + assert(file); + + std::vprint_nonunicode_buffered(file, "\n", std::make_format_args()); +#ifndef _WIN32 + assert(std::ftell(file) == 1); +#else + assert(std::ftell(file) == 2); +#endif + } + // Binary no newline translation. + { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + std::vprint_nonunicode_buffered(file, "\n", std::make_format_args()); + assert(std::ftell(file) == 1); + } +} + +int main(int, char**) { + print_tests(test_file, test_exception); + +#if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) + test_wide_stream(); +#endif + test_read_only(); + test_new_line(); + + return 0; +} diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode_buffered.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode_buffered.file.pass.cpp new file mode 100644 index 0000000000000..23d77b5079a08 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode_buffered.file.pass.cpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// TODO PRINT Enable again +// https://reviews.llvm.org/D150044 +// https://lab.llvm.org/buildbot/#/builders/237/builds/3578 +// UNSUPPORTED: asan, hwasan, msan + +// XFAIL: availability-fp_to_chars-missing + +// The error exception has no system error string. +// XFAIL: LIBCXX-ANDROID-FIXME + +// + +// void vprint_unicode_buffered(FILE* stream, string_view fmt, format_args args); + +// 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. There are tests in +// libcxx/test/libcxx/input.output/iostream.format/print.fun/ +// to validate that behaviour + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "filesystem_test_helper.h" +#include "print_tests.h" +#include "test_macros.h" + +scoped_test_env env; +std::string filename = env.create_file("output.txt"); + +auto test_file = [](std::string_view expected, std::string_view fmt, Args&&... args) { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + std::vprint_unicode_buffered(file, fmt, std::make_format_args(args...)); + std::fclose(file); + + std::ifstream stream{filename.c_str(), std::ios_base::in | std::ios_base::binary}; + std::string out(std::istreambuf_iterator{stream}, {}); + TEST_REQUIRE(out == expected, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n')); +}; + +auto test_exception = []([[maybe_unused]] std::string_view what, + [[maybe_unused]] std::string_view fmt, + [[maybe_unused]] Args&&... args) { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + TEST_VALIDATE_EXCEPTION( + std::format_error, + [&]([[maybe_unused]] const std::format_error& e) { + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_unicode_buffered(file, fmt, std::make_format_args(args...))); + + fclose(file); +}; + +// Glibc fails writing to a wide stream. +#if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) +static void test_wide_stream() { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + int mode = std::fwide(file, 1); + assert(mode > 0); + + TEST_VALIDATE_EXCEPTION( + std::system_error, + [&]([[maybe_unused]] const std::system_error& e) { + [[maybe_unused]] std::string_view what{"failed to write formatted output"}; + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_unicode_buffered(file, "hello", std::make_format_args())); +} +#endif // defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) + +static void test_read_only() { + FILE* file = fopen(filename.c_str(), "r"); + assert(file); + + TEST_VALIDATE_EXCEPTION( + std::system_error, + [&]([[maybe_unused]] const std::system_error& e) { + [[maybe_unused]] std::string_view what{ + "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")}; + TEST_LIBCPP_REQUIRE( + e.what() == what, + TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n')); + }, + std::vprint_unicode_buffered(file, "hello", std::make_format_args())); +} + +static void test_new_line() { + // Text does newline translation. + { + FILE* file = fopen(filename.c_str(), "w"); + assert(file); + + std::vprint_unicode_buffered(file, "\n", std::make_format_args()); +#ifndef _WIN32 + assert(std::ftell(file) == 1); +#else + assert(std::ftell(file) == 2); +#endif + } + // Binary no newline translation. + { + FILE* file = fopen(filename.c_str(), "wb"); + assert(file); + + std::vprint_unicode_buffered(file, "\n", std::make_format_args()); + assert(std::ftell(file) == 1); + } +} + +int main(int, char**) { + print_tests(test_file, test_exception); + +#if defined(TEST_HAS_GLIBC) && !defined(TEST_HAS_NO_WIDE_CHARACTERS) + test_wide_stream(); +#endif + test_read_only(); + test_new_line(); + + return 0; +} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp index 61d7747e4b6d1..16bcb02c2516f 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp @@ -19,7 +19,7 @@ /* Constant Value __cpp_lib_char8_t 201907L [C++20] - __cpp_lib_print 202207L [C++23] + __cpp_lib_print 202403L [C++23] */ #include @@ -93,8 +93,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++23" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++23" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++23" # endif # else # ifdef __cpp_lib_print @@ -121,8 +121,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++26" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++26" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++26" # endif # else # ifdef __cpp_lib_print diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp index c9743cf41ef1e..de04d0bf02ba8 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp @@ -18,7 +18,7 @@ // Test the feature test macros defined by /* Constant Value - __cpp_lib_print 202207L [C++23] + __cpp_lib_print 202403L [C++23] */ #include @@ -54,8 +54,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++23" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++23" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++23" # endif # else # ifdef __cpp_lib_print @@ -69,8 +69,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++26" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++26" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++26" # endif # else # ifdef __cpp_lib_print diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 1e4465d515e6b..6e2d3eec7f366 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -169,7 +169,7 @@ __cpp_lib_parallel_algorithm 201603L [C++17] __cpp_lib_philox_engine 202406L [C++26] __cpp_lib_polymorphic_allocator 201902L [C++20] - __cpp_lib_print 202207L [C++23] + __cpp_lib_print 202403L [C++23] __cpp_lib_quoted_string_io 201304L [C++14] __cpp_lib_ranges 202110L [C++20] 202406L [C++23] @@ -5683,8 +5683,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++23" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++23" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++23" # endif # else # ifdef __cpp_lib_print @@ -7567,8 +7567,8 @@ # ifndef __cpp_lib_print # error "__cpp_lib_print should be defined in c++26" # endif -# if __cpp_lib_print != 202207L -# error "__cpp_lib_print should have the value 202207L in c++26" +# if __cpp_lib_print != 202403L +# error "__cpp_lib_print should have the value 202403L in c++26" # endif # else # ifdef __cpp_lib_print diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 8bf7633e985d5..7a0f31e6b7463 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1010,8 +1010,7 @@ def add_version_header(tc): { "name": "__cpp_lib_print", "values": { - "c++23": 202207, - # "c++26": 202403, # P3107R5: Permit an efficient implementation of std::print + "c++23": 202403, # "c++26": 202406, # P3235R3 std::print more types faster with less memory }, "headers": ["ostream", "print"],