From 7c2a9dbcc2c1cb1563774068c59d5e09edc59f06 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely <jwakely@redhat.com> Date: Thu, 21 Mar 2024 23:09:14 +0000 Subject: [PATCH] libstdc++: Implement "Printing blank lines with println" for C++23 This was recently approved for C++26 at the Tokyo meeting. As suggested by Stephan T. Lavavej, I'm defining it as an extension for C++23 mode (when std::print and std::prinln were first added) rather than as a new C++26 feature. Both MSVC and libc++ have agreed to do this too. libstdc++-v3/ChangeLog: * include/std/ostream (println(ostream&)): Define new overload. * include/std/print (println(FILE*), println()): Likewise. * testsuite/27_io/basic_ostream/print/2.cc: New test. * testsuite/27_io/print/1.cc: Remove unused header. * testsuite/27_io/print/3.cc: New test. --- libstdc++-v3/include/std/ostream | 12 +++++ libstdc++-v3/include/std/print | 14 +++++ .../testsuite/27_io/basic_ostream/print/2.cc | 47 ++++++++++++++++ libstdc++-v3/testsuite/27_io/print/1.cc | 1 - libstdc++-v3/testsuite/27_io/print/3.cc | 53 +++++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/27_io/basic_ostream/print/2.cc create mode 100644 libstdc++-v3/testsuite/27_io/print/3.cc diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index a136399ad0b9..8a21758d0a33 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -995,6 +995,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::print(__os, "{}\n", std::format(__fmt, std::forward<_Args>(__args)...)); } + + // Defined for C++26, supported as an extension to C++23. + inline void println(ostream& __os) + { +#if defined(_WIN32) && !defined(__CYGWIN__) + if constexpr (__unicode::__literal_encoding_is_utf8()) + std::vprint_unicode(__os, "\n", std::make_format_args()); + else +#endif + __os.put('\n'); + } + #endif // __cpp_lib_print #endif // C++11 diff --git a/libstdc++-v3/include/std/print b/libstdc++-v3/include/std/print index d44033469de2..0c259d04de33 100644 --- a/libstdc++-v3/include/std/print +++ b/libstdc++-v3/include/std/print @@ -136,6 +136,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION vprint_nonunicode(string_view __fmt, format_args __args) { std::vprint_nonunicode(stdout, __fmt, __args); } + // Defined for C++26, supported as an extension to C++23. + inline void println(FILE* __stream) + { +#if defined(_WIN32) && !defined(__CYGWIN__) + if constexpr (__unicode::__literal_encoding_is_utf8()) + std::vprint_unicode(__stream, "\n", std::make_format_args()); + else +#endif + if (std::putc('\n', __stream) == EOF) + __throw_system_error(EIO); + } + + inline void println() { std::println(stdout); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_print diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/print/2.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/print/2.cc new file mode 100644 index 000000000000..5d1e3efdbf78 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/print/2.cc @@ -0,0 +1,47 @@ +// { dg-additional-options "-lstdc++exp" { target { *-*-mingw* } } } +// { dg-do run { target c++23 } } +// { dg-require-fileio "" } + +#include <ostream> +#include <spanstream> +#include <string_view> +#include <iostream> +#include <iomanip> +#include <testsuite_hooks.h> + +void +test_println_blank_ostream() +{ + char buf[4]; + std::spanstream os(buf); + std::println(os); + std::string_view txt(os.span()); + VERIFY( txt == "\n" ); +} + +void +test_errors() +{ + // Failure to generate output is reported by setting badbit. + std::stringstream in(std::ios::in); + std::println(in); // No exception here. + VERIFY(in.bad()); +#ifdef __cpp_exceptions + in.clear(); + in.exceptions(std::ios::badbit); + try + { + std::println(in); // Should throw now. + VERIFY(false); + } + catch (const std::ios::failure&) + { + } +#endif +} + +int main() +{ + test_println_blank_ostream(); + test_errors(); +} diff --git a/libstdc++-v3/testsuite/27_io/print/1.cc b/libstdc++-v3/testsuite/27_io/print/1.cc index d570f7938be6..f6585d9880ae 100644 --- a/libstdc++-v3/testsuite/27_io/print/1.cc +++ b/libstdc++-v3/testsuite/27_io/print/1.cc @@ -4,7 +4,6 @@ #include <print> #include <cstdio> -#include <spanstream> #include <testsuite_hooks.h> #include <testsuite_fs.h> diff --git a/libstdc++-v3/testsuite/27_io/print/3.cc b/libstdc++-v3/testsuite/27_io/print/3.cc new file mode 100644 index 000000000000..ffcf7337ce5d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/print/3.cc @@ -0,0 +1,53 @@ +// { dg-additional-options "-lstdc++exp" { target { *-*-mingw* } } } +// { dg-do run { target c++23 } } +// { dg-require-fileio "" } + +#include <print> +#include <cstdio> +#include <testsuite_hooks.h> +#include <testsuite_fs.h> + +void +test_println_blank() +{ + std::print("1"); + std::println(); + std::println("2"); + // { dg-output "1\n2" } +} + +void +test_println_blank_file() +{ + __gnu_test::scoped_file f; + FILE* strm = std::fopen(f.path.string().c_str(), "w"); + VERIFY( strm ); + std::println(strm); + std::fclose(strm); + + std::ifstream in(f.path); + std::string txt(std::istreambuf_iterator<char>(in), {}); + VERIFY( txt == "\n" ); +} + +void +test_errors() +{ +#ifdef __cpp_exceptions + try + { + std::println(stdin); + VERIFY(false); + } + catch (const std::system_error&) + { + } +#endif +} + +int main() +{ + test_println_blank(); + test_println_blank_file(); + test_errors(); +} -- GitLab