Skip to content

[libc++][format] P3142R0: Printing Blank Lines with println #87277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

H-G-Hristov
Copy link
Contributor

@H-G-Hristov H-G-Hristov commented Apr 1, 2024

Implements https://wg21.link/P3142R0

Applied retroactively as DR, same as stdlibc++ and MS STL:
STL C++26 Features

@H-G-Hristov H-G-Hristov changed the title [libc++][format] P3142R0 - Printing Blank Lines with println [libc++][format] P3142R0: Printing Blank Lines with println Apr 1, 2024
@H-G-Hristov H-G-Hristov marked this pull request as ready for review April 1, 2024 20:25
@H-G-Hristov H-G-Hristov requested a review from a team as a code owner April 1, 2024 20:25
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 1, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 1, 2024

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

Changes

Implements https://wg21.link/P3142R0


Full diff: https://github.com/llvm/llvm-project/pull/87277.diff

8 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/19.rst (+1)
  • (modified) libcxx/include/ostream (+4)
  • (modified) libcxx/include/print (+8)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp (+3-1)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp (+3-1)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp (+4-1)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp (+18)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/println.sh.cpp (+2-1)
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index dd39c1bbbc78a3..7bf1da91e2abb9 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -42,6 +42,7 @@ Implemented Papers
 - P2652R2 - Disallow User Specialization of ``allocator_traits``
 - P2819R2 - Add ``tuple`` protocol to ``complex``
 - P2495R3 - Interfacing ``stringstream``\s with ``string_view``
+- P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
 - P2302R4 - ``std::ranges::contains``
 - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
 
diff --git a/libcxx/include/ostream b/libcxx/include/ostream
index 42819ceb252c65..d4fc1c58b8a941 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -164,6 +164,7 @@ template<class... Args>
   void print(ostream& os, format_string<Args...> fmt, Args&&... args);
 template<class... Args>                                                                                // since C++23
   void println(ostream& os, format_string<Args...> fmt, Args&&... args);
+void println(ostream& os);                                                                             // since C++26
 
 void vprint_unicode(ostream& os, string_view fmt, format_args args);                                   // since C++23
 void vprint_nonunicode(ostream& os, string_view fmt, format_args args);                                // since C++23
@@ -1163,6 +1164,9 @@ _LIBCPP_HIDE_FROM_ABI void println(ostream& __os, format_string<_Args...> __fmt,
 #  endif // _LIBCPP_HAS_NO_UNICODE
 }
 
+template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
+_LIBCPP_HIDE_FROM_ABI inline void println(ostream& __os) { std::print(__os, "\n"); }
+
 #endif // _LIBCPP_STD_VER >= 23
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/print b/libcxx/include/print
index a9f10433a7dc61..e0bcf214ea239b 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -15,8 +15,10 @@ namespace std {
   // [print.fun], print functions
   template<class... Args>
     void print(format_string<Args...> fmt, Args&&... args);
+  void println();                                                          // Since C++26
   template<class... Args>
     void print(FILE* stream, format_string<Args...> fmt, Args&&... args);
+  void println(FILE* stream);                                              // Since C++26
 
   template<class... Args>
     void println(format_string<Args...> fmt, Args&&... args);
@@ -356,6 +358,12 @@ _LIBCPP_HIDE_FROM_ABI void println(FILE* __stream, format_string<_Args...> __fmt
 #  endif // _LIBCPP_HAS_NO_UNICODE
 }
 
+template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
+_LIBCPP_HIDE_FROM_ABI inline void println(FILE* __stream) { std::print(__stream, "\n"); }
+
+template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
+_LIBCPP_HIDE_FROM_ABI inline void println() { println(stdout); }
+
 template <class... _Args>
 _LIBCPP_HIDE_FROM_ABI void println(format_string<_Args...> __fmt, _Args&&... __args) {
   std::println(stdout, __fmt, std::forward<_Args>(__args)...);
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
index 6b62e2f1754de5..8edfb90b15b86d 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
@@ -26,6 +26,7 @@
 //   void print(ostream& os, format_string<Args...> fmt, Args&&... args);
 // template<class... Args>
 //   void println(ostream& os, format_string<Args...> fmt, Args&&... args);
+// void println(ostream& os);                                                // since C++26
 //
 // void vprint_unicode(ostream& os, string_view fmt, format_args args);
 // void vprint_nonunicode(ostream& os, string_view fmt, format_args args);
@@ -86,10 +87,11 @@ test(std::stringstream& stream, std::string expected, test_format_string<char, A
   }
   // *** println ***
   {
-    expected += '\n'; // Tested last since it changes the expected value.
+    expected += "\n\n"; // Tested last since it changes the expected value.
     stream.str("");
     ;
     std::println(stream, fmt, std::forward<Args>(args)...);
+    std::println(stream);
     std::string out = stream.str();
     TEST_REQUIRE(out == expected,
                  TEST_WRITE_CONCATENATED(
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
index 479a3de0a93c8d..b61fcf174422af 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
@@ -17,6 +17,7 @@
 
 // template<class... Args>
 //   void println(ostream& os, format_string<Args...> fmt, Args&&... args);
+// void println(ostream& os);                                                // since C++26
 
 // [ostream.formatted.print]/3
 //   If the function is vprint_unicode and os is a stream that refers to
@@ -37,10 +38,11 @@
 #include "test_macros.h"
 
 auto test_file = []<class... Args>(std::string_view e, test_format_string<char, Args...> fmt, Args&&... args) {
-  std::string expected = std::string{e} + '\n';
+  std::string expected = std::string{e} + "\n\n";
 
   std::stringstream sstr;
   std::println(sstr, fmt, std::forward<Args>(args)...);
+  std::println(sstr);
 
   std::string out = sstr.str();
   TEST_REQUIRE(out == expected,
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
index f502616b677b77..450ca45a6d4b7e 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
@@ -25,8 +25,10 @@
 
 // template<class... Args>
 //   void print(FILE* stream, format_string<Args...> fmt, Args&&... args);
+// void println();                                                          // Since C++26
 // template<class... Args>
 //   void println(FILE* stream, format_string<Args...> fmt, Args&&... args);
+// void println(FILE* stream);                                              // Since C++26
 // void vprint_unicode(FILE* stream, string_view fmt, format_args args);
 // void vprint_nonunicode(FILE* stream, string_view fmt, format_args args);
 
@@ -56,11 +58,12 @@ static void test_println() {
   assert(file);
 
   std::println(file, "hello world{}", '!');
+  std::println(file);
   long pos = std::ftell(file);
   std::fclose(file);
 
   assert(pos > 0);
-  assert(std::string_view(buffer.data(), pos) == "hello world!\n");
+  assert(std::string_view(buffer.data(), pos) == "hello world!\n\n");
 }
 
 static void test_vprint_unicode() {
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
index 07272ebb57e5fc..9e96864aa822dd 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
@@ -112,6 +112,17 @@ static void test_new_line() {
     FILE* file = fopen(filename.c_str(), "w");
     assert(file);
 
+    std::println(file);
+#ifndef _WIN32
+    assert(std::ftell(file) == 1);
+#else
+    assert(std::ftell(file) == 2);
+#endif
+  }
+  {
+    FILE* file = fopen(filename.c_str(), "w");
+    assert(file);
+
     std::println(file, "");
 #ifndef _WIN32
     assert(std::ftell(file) == 1);
@@ -124,6 +135,13 @@ static void test_new_line() {
     FILE* file = fopen(filename.c_str(), "wb");
     assert(file);
 
+    std::println(file);
+    assert(std::ftell(file) == 1);
+  }
+  {
+    FILE* file = fopen(filename.c_str(), "wb");
+    assert(file);
+
     std::println(file, "");
     assert(std::ftell(file) == 1);
   }
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/println.sh.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/println.sh.cpp
index b811b4f2a24933..67343b3a730c54 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/println.sh.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/println.sh.cpp
@@ -36,7 +36,7 @@
 
 // FILE_DEPENDENCIES: echo.sh
 // RUN: %{build}
-// RUN: %{exec} bash echo.sh -ne "1234 一二三四\ntrue 0x0\n" > %t.expected
+// RUN: %{exec} bash echo.sh -ne "1234 一二三四\ntrue 0x0\n\n" > %t.expected
 // RUN: %{exec} "%t.exe" > %t.actual
 // RUN: diff -u %t.actual %t.expected
 
@@ -46,6 +46,7 @@ int main(int, char**) {
   // The data is passed as-is so it does not depend on the encoding of the input.
   std::println("{} {}", 1234, "一二三四");
   std::println("{} {}", true, nullptr);
+  std::println();
 
   return 0;
 }

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks quite good. A few minor comments. Can you rebase so you can update the status page.

@Zingam Zingam requested a review from mordante April 6, 2024 07:13
Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM!

@Zingam
Copy link
Contributor

Zingam commented Apr 6, 2024

@mordante Thank you!

@Zingam Zingam merged commit 7f9f82e into llvm:main Apr 6, 2024
@vvereschaka
Copy link
Contributor

@H-G-Hristov ,

the llvm-libc++-static.cfg.in::println.blank_line.sh.cpp test gets failed on the windows to linux cross builders with the following messages

diff -u C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.actual C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.expected
# executed command: diff -u 'C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.actual' 'C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.expected'
# .---command stdout------------
# | --- C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.actual
# | +++ C:\buildbot\as-builder-1\x-armv7l\build\runtimes\runtimes-armv7-unknown-linux-gnueabihf-bins\test\std\input.output\iostream.format\print.fun\Output\println.blank_line.sh.cpp.dir\t.tmp.expected
# | @@ -1 +1 @@
# | -
# | +n
# `-----------------------------
# error: command failed with exit status: 1

would you take care of it?

@mordante
Copy link
Member

mordante commented Apr 8, 2024

I had a look and a similar test std/input.output/iostream.format/print.fun/println.sh.cpp passes on this platform. Maybe the issue is that the output only contains \n. Maybe changing the test to

print("hello world");
println();

might solve the issue. @Zingam can you provide a followup patch to make this change?
@vvereschaka would you be able to test that followup patch? Do you feel this is so urgent it warrants a temporary revert?

If the suggested solution works we should add comment why we output we do that.

@H-G-Hristov
Copy link
Contributor Author

H-G-Hristov commented Apr 8, 2024

@vvereschaka @mordante I created a PR with the proposed resolution with a slight twist here: #88011 Thank you for the heads-up!

I wonder if double println() will resolve the issue too but I don't know how to test it.

vvereschaka pushed a commit that referenced this pull request Apr 8, 2024
…-win-x-* configurations (#88011)

Fix for issue:
#87277 (comment)

The test fails on the windows to linux cross builders. The proposed
resolution is to print some text. The issue is possibly due to the
original test outputting a single `\n` character.
@H-G-Hristov H-G-Hristov deleted the hgh/libcxx/P3142R0-Printing-Blank-Lines-with-std_println branch April 13, 2024 21:08
blueboxd pushed a commit to blueboxd/libcxx that referenced this pull request May 21, 2024
…-win-x-* configurations (#88011)

Fix for issue:
llvm/llvm-project#87277 (comment)

The test fails on the windows to linux cross builders. The proposed
resolution is to print some text. The issue is possibly due to the
original test outputting a single `\n` character.

NOKEYCHECK=True
GitOrigin-RevId: ea2392ed33f765018002f833da9a04cd0571ab83
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants